> ## Documentation Index
> Fetch the complete documentation index at: https://docs.endorlabs.com/llms.txt
> Use this file to discover all available pages before exploring further.

# endorctl CLI

> Install, configure, and authenticate with the Endor Labs command-line interface.

export const YamlTable = ({children, data: propData, content}) => {
  const KV_RE = /^([A-Za-z][A-Za-z0-9_()/#\s-]+?):\s*(.+)$/;
  const INLINE_MD_RE = /(\[([^\]]+)\]\(([^)]+)\))|(`([^`]+)`)|(\*\*([^*]+)\*\*)|(\*([^*]+)\*)/g;
  const YES_RE = /^-yes-$/i;
  const NO_RE = /^-no-$/i;
  const LIMITED_RE = /^-(limited|partial)-$/i;
  const NA_RE = /^-(na|none)-$/i;
  const NA2_RE = /^-na2-$/i;
  const SIMPLE_TAG_RE = /(<br\s*\/?>)|(<p\s*\/?>)|(-note-)|(-warning-)/gi;
  const tryParseKV = trimmed => {
    const m = KV_RE.exec(trimmed);
    return m ? {
      key: m[1],
      value: m[2].trim()
    } : null;
  };
  const registerKey = (key, seenKeys, orderedKeys) => {
    if (!seenKeys.has(key)) {
      orderedKeys.push(key);
      seenKeys.add(key);
    }
  };
  const flushEntry = (currentEntry, entries) => {
    if (Object.keys(currentEntry).length > 0) entries.push(currentEntry);
  };
  const parseDashPrefixed = (lines, entries, orderedKeys, seenKeys) => {
    let currentEntry = {};
    let inEntry = false;
    for (const line of lines) {
      const trimmed = line.trim();
      if (trimmed.startsWith('- ')) {
        if (inEntry) entries.push(currentEntry);
        currentEntry = {};
        inEntry = true;
        const kv = tryParseKV(trimmed.substring(2).trim());
        if (kv) {
          registerKey(kv.key, seenKeys, orderedKeys);
          currentEntry[kv.key] = kv.value;
        }
      } else if (inEntry && trimmed !== '') {
        const kv = tryParseKV(trimmed);
        if (kv) {
          registerKey(kv.key, seenKeys, orderedKeys);
          currentEntry[kv.key] = kv.value;
        }
      }
    }
    flushEntry(currentEntry, entries);
  };
  const parseBlankSeparated = (lines, entries, orderedKeys, seenKeys) => {
    let currentEntry = {};
    let inEntry = false;
    for (const line of lines) {
      const trimmed = line.trim();
      if (trimmed === '') {
        if (inEntry) {
          flushEntry(currentEntry, entries);
          currentEntry = {};
          inEntry = false;
        }
        continue;
      }
      const kv = tryParseKV(trimmed);
      if (!kv) continue;
      const isNewEntry = !line.startsWith(' ') && !line.startsWith('\t');
      if (isNewEntry && inEntry && Object.keys(currentEntry).length > 0) {
        entries.push(currentEntry);
        currentEntry = {};
      }
      registerKey(kv.key, seenKeys, orderedKeys);
      currentEntry[kv.key] = kv.value;
      inEntry = true;
    }
    flushEntry(currentEntry, entries);
  };
  const normalizeEntries = (entries, orderedKeys) => entries.map(entry => {
    const filled = {};
    for (const key of orderedKeys) filled[key] = entry[key] || '';
    return filled;
  });
  const parseYamlTableContent = contentStr => {
    if (!contentStr) return [];
    const entries = [];
    const orderedKeys = [];
    const seenKeys = new Set();
    const lines = contentStr.split('\n');
    if (lines.some(line => line.trim().startsWith('- '))) {
      parseDashPrefixed(lines, entries, orderedKeys, seenKeys);
    } else {
      parseBlankSeparated(lines, entries, orderedKeys, seenKeys);
    }
    return normalizeEntries(entries, orderedKeys);
  };
  const processText = text => {
    if (!text) return text;
    const parts = [];
    let keyIndex = 0;
    let lastIndex = 0;
    let match;
    while ((match = INLINE_MD_RE.exec(text)) !== null) {
      if (match.index > lastIndex) parts.push(text.slice(lastIndex, match.index));
      if (match[1]) {
        parts.push(<a key={keyIndex++} href={match[3]}>{match[2]}</a>);
      } else if (match[4]) {
        parts.push(<code key={keyIndex++}>{match[5]}</code>);
      } else if (match[6]) {
        parts.push(<strong key={keyIndex++}>{match[7]}</strong>);
      } else if (match[8]) {
        parts.push(<em key={keyIndex++}>{match[9]}</em>);
      }
      lastIndex = match.index + match[0].length;
    }
    if (lastIndex < text.length) parts.push(text.slice(lastIndex));
    if (parts.length === 0) return text;
    const keyRef = {
      current: keyIndex
    };
    return expandHtmlTags(parts, keyRef);
  };
  const processBadges = text => {
    if (!text || typeof text !== 'string') return text;
    if (YES_RE.test(text)) return <span className="yt-badge-yes" role="img" aria-label="Supported" title="Supported">✓</span>;
    if (NO_RE.test(text)) return <span className="yt-badge-no" role="img" aria-label="Not supported" title="Not supported">✗</span>;
    if (LIMITED_RE.test(text)) return <span className="yt-badge-limited" role="img" aria-label="Partially supported" title="Partially supported">◐</span>;
    if (NA_RE.test(text) || NA2_RE.test(text)) return <span className="yt-sr-only" title="Not applicable">Not applicable</span>;
    return processText(text);
  };
  const cellClassName = text => {
    if (!text || typeof text !== 'string') return undefined;
    if (NA_RE.test(text)) return 'yt-cell-na';
    if (NA2_RE.test(text)) return 'yt-cell-na2';
    return undefined;
  };
  const expandSimpleTags = (str, keyRef) => {
    const result = [];
    let last = 0;
    SIMPLE_TAG_RE.lastIndex = 0;
    let m;
    while ((m = SIMPLE_TAG_RE.exec(str)) !== null) {
      if (m.index > last) result.push(str.slice(last, m.index));
      if (m[1]) {
        result.push(<br key={keyRef.current++} />);
      } else if (m[2]) {
        result.push(<br key={keyRef.current++} />, <br key={keyRef.current++} />);
      } else if (m[3]) {
        result.push(<span key={keyRef.current++} className="yt-badge-note" style={{
          fontWeight: 600
        }}>Note: </span>);
      } else if (m[4]) {
        result.push(<span key={keyRef.current++} className="yt-badge-warning" style={{
          fontWeight: 600
        }}>Warning: </span>);
      }
      last = m.index + m[0].length;
    }
    if (last < str.length) result.push(str.slice(last));
    return result;
  };
  const expandHtmlTags = (chunks, keyRef) => {
    const out = [];
    for (const chunk of chunks) {
      if (typeof chunk === 'string') {
        out.push(...expandSimpleTags(chunk, keyRef));
      } else {
        out.push(chunk);
      }
    }
    return out;
  };
  const extractText = node => {
    if (node === null || node === undefined) return '';
    if (typeof node === 'string') return node;
    if (typeof node === 'number') return String(node);
    if (typeof node === 'boolean') return '';
    if (Array.isArray(node)) return node.map(extractText).join('');
    if (node && typeof node === 'object' && node.type) {
      const props = node.props || ({});
      if (typeof props.children === 'string') return props.children;
      if (props.children) return extractText(props.children);
      return '';
    }
    return String(node || '');
  };
  const [mounted, setMounted] = useState(false);
  useEffect(() => {
    setMounted(true);
  }, []);
  const data = useMemo(() => {
    if (propData) return propData;
    if (content && typeof content === 'string') return parseYamlTableContent(content);
    if (!children) return [];
    if (typeof children === 'string') return parseYamlTableContent(children);
    const childrenArray = Array.isArray(children) ? children : [children];
    return parseYamlTableContent(childrenArray.map(extractText).join('').trim());
  }, [children, propData, content]);
  const columns = useMemo(() => {
    if (!data || data.length === 0) return [];
    const firstRow = data[0];
    if (!firstRow || typeof firstRow !== 'object') return [];
    return Object.keys(firstRow);
  }, [data]);
  if (!mounted) return null;
  if (!data || data.length === 0) return null;
  const rowKey = row => columns.map(c => row[c] || '').join('|');
  return <table>
      <thead>
        <tr>
          {columns.map(col => <th key={col}>{col.replaceAll('_', ' ')}</th>)}
        </tr>
      </thead>
      <tbody>
        {data.map(row => <tr key={rowKey(row)}>
            {columns.map(col => <td key={col} className={cellClassName(row[col])}>{processBadges(row[col])}</td>)}
          </tr>)}
      </tbody>
    </table>;
};

Perform software composition analysis, dependency management, or detect secrets in your code using Endor Labs.

## Download and install endorctl

Use one of the following methods to download and install endorctl on your local system. After you install endorctl, you must authenticate. Then you can start scanning your code.

### Install endorctl with Homebrew

Use Homebrew to efficiently install endorctl on macOS and Linux operating systems making it easy to manage dependencies, and track installed packages with their versions.

Install endorctl from the [Endor Labs tap](https://github.com/endorlabs/homebrew-tap) with Homebrew by running the following commands. The tap is updated regularly with the latest endorctl release.

```bash theme={null}
brew tap endorlabs/tap
brew install endorctl
```

### Install endorctl with npm

Use npm to efficiently install endorctl on macOS, Linux, and Windows operating systems making it easy to manage dependencies, track and update installed packages and their versions.

1. Make sure that you have npm installed in your local environment and use the following command to install endorctl.

   ```bash theme={null}
   npm install -g endorctl
   ```

2. Run the following command to get the npm global bin directory.

   ```bash theme={null}
   npm config get prefix
   ```

3. Edit your shell configuration file and insert the path you obtained from the previous command.

   ```bash theme={null}
   export PATH="/path/to/npm/global/bin:$PATH"
   ```

4. Reload your shell configuration and verify endorctl is installed.

   ```bash theme={null}
   endorctl --version
   ```

5. To update your version of endorctl, run the following command.

   ```bash theme={null}
   npm update -g endorctl
   ```

[endorctl](https://www.npmjs.com/package/endorctl) is available as an npm package and is updated regularly with the latest endorctl release.

### Download and install the endorctl binary directly

To download the endorctl binary directly use the following commands:

<Tabs>
  <Tab title="Linux">
    ```bash theme={null}
    ## Download the latest CLI for Linux amd64
    curl https://api.endorlabs.com/download/latest/endorctl_linux_amd64 -o endorctl

    ## Verify the checksum of the binary
    echo "$(curl -s https://api.endorlabs.com/sha/latest/endorctl_linux_amd64)  endorctl" | sha256sum -c

    ## Modify the permissions of the binary to ensure it is executable
    chmod +x ./endorctl

    ## Create an alias endorctl of the binary to ensure it is available in other directory
    alias endorctl="$PWD/endorctl"
    ```
  </Tab>

  <Tab title="Mac OS">
    ```bash theme={null}
    ### Download the latest CLI for MacOS ARM64
    curl https://api.endorlabs.com/download/latest/endorctl_macos_arm64 -o endorctl

    ### Verify the checksum of the binary
    echo "$(curl -s https://api.endorlabs.com/sha/latest/endorctl_macos_arm64)  endorctl" | shasum -a 256 -c

    ### Modify the permissions of the binary to ensure it is executable
    chmod +x ./endorctl

    ### Create an alias endorctl of the binary to ensure it is available in other directory
    alias endorctl="$PWD/endorctl"
    ```
  </Tab>

  <Tab title="Windows">
    ```bash theme={null}
    ## Download the latest CLI for Windows amd64
    curl -O https://api.endorlabs.com/download/latest/endorctl_windows_amd64.exe

    ## Check the expected checksum of the binary file
    curl https://api.endorlabs.com/sha/latest/endorctl_windows_amd64.exe

    ## Verify the expected checksum and the actual checksum of the binary match
    certutil -hashfile .\endorctl_windows_amd64.exe SHA256

    ## Rename the binary file
    ren endorctl_windows_amd64.exe endorctl.exe

    ```
  </Tab>
</Tabs>

You can also view these instructions via the Endor Labs application user interface:

1. Select **Projects** from the left sidebar.
2. Click **Add Project**.
3. Choose **CLI**.
4. Follow the on-screen instructions to download and install the appropriate version and architecture of `endorctl` for your system.

## Authenticate to Endor Labs

You can authenticate to Endor Labs in multiple ways:

1. [Using the init command](#login-with-the-init-command)
2. [With an API token](#login-with-an-api-key)

### Login with the init command

To log in with your supported authentication provider:

<Tabs>
  <Tab title="Google">
    ```bash theme={null}
    endorctl init --auth-mode=google
    ```
  </Tab>

  <Tab title="GitHub">
    ```bash theme={null}
    endorctl init --auth-mode=github
    ```
  </Tab>

  <Tab title="GitLab">
    ```bash theme={null}
    endorctl init --auth-mode=gitlab
    ```
  </Tab>

  <Tab title="Email">
    ```bash theme={null}
    endorctl init --auth-email=<insert_email_address>
    ```
  </Tab>

  <Tab title="SSO">
    ```bash theme={null}
    endorctl init --auth-mode=sso --auth-tenant=<insert-your-tenant>
    ```
  </Tab>
</Tabs>

To log in with your supported authentication provider in environments without a browser you can use headless mode:

<Tabs>
  <Tab title="Google">
    ```bash theme={null}
    endorctl init --auth-mode=google --headless-mode
    ```
  </Tab>

  <Tab title="GitHub">
    ```bash theme={null}
    endorctl init --auth-mode=github --headless-mode
    ```
  </Tab>

  <Tab title="GitLab">
    ```bash theme={null}
    endorctl init --auth-mode=gitlab --headless-mode
    ```
  </Tab>

  <Tab title="Email">
    ```bash theme={null}
    endorctl init --auth-email=<insert_email_address> --headless-mode
    ```
  </Tab>

  <Tab title="SSO">
    ```bash theme={null}
    endorctl init --auth-mode=sso --auth-tenant=<insert-your-tenant> --headless-mode
    ```
  </Tab>
</Tabs>

### Login with an API Key

To log in with an API key you'll need to set the following environment variables:

* **ENDOR\_API\_CREDENTIALS\_KEY** - The API key used to authenticate against the Endor Labs API.
* **ENDOR\_API\_CREDENTIALS\_SECRET** - The API key secret used to authenticate against the Endor Labs API.
* **ENDOR\_NAMESPACE** - The Endor Labs namespace you would like to scan against. You can locate the namespace from the top left hand corner of the screen under the Endor Labs logo on the [Endor Labs application](https://app.endorlabs.com).

To get an API Key and secret for use with endorctl, see [Managing API Keys](/platform-administration/api-keys).

To set your environment variables run the following commands and replace each example with the appropriate value.

```bash theme={null}
export ENDOR_API_CREDENTIALS_KEY=<example-api-key>
export ENDOR_API_CREDENTIALS_SECRET=<example-api-key-secret>
export ENDOR_NAMESPACE=<example-tenant-namespace>
```

Once you've exported your environment variables you can test successful authentication by running the following command to list projects in your namespace.

```bash theme={null}
endorctl api list -r Project --page-size=1
```

<Note>
  If you do not have any projects in your namespace you will get an empty json output, which means you are successfully authenticated.
</Note>

### Print your access token

Once you have successfully initialized endorctl, you can print your access token with the following command.

```bash theme={null}
endorctl auth --print-access-token
```

The token has an expiration time of 4 hours.

## Clone your repository

Upon successful authentication to Endor Labs using `endorctl`, proceed to clone the repository you intend to scan. If you prefer initiating with a dummy app for scanning, feel free to skip to the next step.

To clone a Git repository, use the `git clone` command followed by the clone link of the repository. You can find the URL on the repository's page on a platform like GitHub or GitLab. For example,

```bash theme={null}
git clone https://github.com/username/repo-name.git
```

Replace `https://github.com/username/repo-name.git` with the actual URL of the Git repository you want to clone.

Navigate to the repository you've cloned.

```bash theme={null}
cd <repo-name>
```

## Software prerequisites for endorctl scan

The following prerequisites must be met to scan with Endor Labs:

* A local installation of Git or the ability to clone repositories in CI. See the [Git documentation for instructions on installing Git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git)
* A runtime environment and build tools for supported software development languages your team uses must be installed on any system used for testing. For more information, see [Supported languages and frameworks](/scan/sca).

<YamlTable>
  {`


    - Language: [Java](/scan/sca/java)
    Package_Managers_/_Build_Tools: Maven
    Manifest_files: \`pom.xml\`
    Runtime_Requirements: JDK version 11-25; Maven 3.6.1 and higher versions

    - Language:
    Package_Managers_/_Build_Tools: Gradle
    Manifest_files: \`build.gradle\`
    Runtime_Requirements: JDK version 11-25; Gradle 6.0.0 and higher versions

    - Language:
    Package_Managers_/_Build_Tools: Bazel
    Manifest_files: \`workspace\`, \`MODULE.bazel\`, \`BUILD.bazel\`
    Runtime_Requirements: JDK version 11-25; Bazel versions \`5.x.x\`, \`6.x.x\`, \`7.x.x\`, \`8.x.x\`, and \`9.x.x\`

    - Language: [Kotlin](/scan/sca/kotlin)
    Package_Managers_/_Build_Tools: Maven
    Manifest_files: \`pom.xml\`
    Runtime_Requirements: JDK version 11-25; Maven 3.6.1 and higher versions

    - Language:
    Package_Managers_/_Build_Tools: Gradle
    Manifest_files: \`build.gradle\`
    Runtime_Requirements: JDK version 11-25; Gradle 6.0.0 and higher versions

    - Language: [Golang](/scan/sca/golang)
    Package_Managers_/_Build_Tools: Go
    Manifest_files: \`go.mod\`, \`go.sum\`
    Runtime_Requirements: Go 1.12 and higher versions

    - Language:
    Package_Managers_/_Build_Tools: Bazel
    Manifest_files: \`workspace\`, \`MODULE.bazel\`, \`BUILD.bazel\`
    Runtime_Requirements: Bazel versions \`5.x.x\`, \`6.x.x\`, \`7.x.x\`, \`8.x.x\`, and \`9.x.x\`

    - Language: [Rust](/scan/sca/rust)
    Package_Managers_/_Build_Tools: Cargo
    Manifest_files: \`cargo.toml\`, \`cargo.lock\`
    Runtime_Requirements: Rust 1.63.0 and higher versions

    - Language: [JavaScript](/scan/sca/javascript)
    Package_Managers_/_Build_Tools: npm
    Manifest_files: \`package-lock.json\`, \`package.json\`
    Runtime_Requirements: npm 6.14.18 and higher versions

    - Language: [TypeScript](/scan/sca/javascript)
    Package_Managers_/_Build_Tools: npm
    Manifest_files: \`package-lock.json\`, \`package.json\`
    Runtime_Requirements: npm 6.14.18 and higher versions

    - Language:
    Package_Managers_/_Build_Tools: Yarn
    Manifest_files: \`yarn.lock\`, \`package.json\`
    Runtime_Requirements: Yarn all versions

    - Language:
    Package_Managers_/_Build_Tools: Rush
    Manifest_files: \`rush.json\`, \`package.json\`; lock file in \`common/config/rush/\`
    Runtime_Requirements: Rush (version in rush.json); set ENDOR_RUSH_ENABLED=true

    - Language: [Python](/scan/sca/python)
    Package_Managers_/_Build_Tools: pip
    Manifest_files: \`requirements.txt\`
    Runtime_Requirements: Python 3.6 and higher versions; pip 10.0.0 and higher versions

    - Language:
    Package_Managers_/_Build_Tools: Poetry
    Manifest_files: \`pyproject.toml\`, \`poetry.lock\`
    Runtime_Requirements:

    - Language:
    Package_Managers_/_Build_Tools: PDM
    Manifest_files: \`pyproject.toml\`, \`pdm.lock\`
    Runtime_Requirements:

    - Language:
    Package_Managers_/_Build_Tools: UV
    Manifest_files: \`pyproject.toml\`, \`uv.lock\`
    Runtime_Requirements:

    - Language:
    Package_Managers_/_Build_Tools: PyPI
    Manifest_files: \`setup.py\`, \`setup.cfg\`, \`pyproject.toml\`
    Runtime_Requirements:

    - Language:
    Package_Managers_/_Build_Tools: Bazel
    Manifest_files: \`workspace\`, \`MODULE.bazel\`
    Runtime_Requirements: Bazel versions \`5.x.x\`, \`6.x.x\`, \`7.x.x\`, \`8.x.x\`, and \`9.x.x\`

    - Language: [.NET (C#)](/scan/sca/dotnet)
    Package_Managers_/_Build_Tools: NuGet
    Manifest_files: \`*.csproj\`, \`package.lock.json\`, \`projects.assets.json\`, \`Directory.Build.props\`, \`Directory.Packages.props\`, \`*.props\`
    Runtime_Requirements: .NET 5.0 and higher versions; .NET Core 1.0 and higher versions; .NET Framework 4.5 and higher versions. Call graphs are supported for .NET 7.0.1 and higher versions.
    - Language: [Scala](/scan/sca/scala)
    Package_Managers_/_Build_Tools: sbt
    Manifest_files: \`build.sbt\`
    Runtime_Requirements: sbt 1.3 and higher versions

    - Language:
    Package_Managers_/_Build_Tools: Gradle
    Manifest_files: \`build.gradle\`, \`build.gradle.kts\`
    Runtime_Requirements: JDK version 11-25; Gradle 6.0.0 and higher versions

    - Language: [Ruby](/scan/sca/ruby)
    Package_Managers_/_Build_Tools: Bundler
    Manifest_files: \`Gemfile\`, \`*.gemspec\`, \`gemfile.lock\`
    Runtime_Requirements: Ruby 2.6 and higher versions

    - Language: [Swift/Objective-C](/scan/sca/swift-objective-c)
    Package_Managers_/_Build_Tools: CocoaPods
    Manifest_files: \`Podfile\`, \`Podfile.lock\`
    Runtime_Requirements: CocoaPods 0.9.0 and higher versions

    - Language:
    Package_Managers_/_Build_Tools: SwiftPM
    Manifest_files: \`Package.swift\`
    Runtime_Requirements: SwiftPM 5.0.0 and higher versions

    - Language: [PHP](/scan/sca/php)
    Package_Managers_/_Build_Tools: Composer
    Manifest_files: \`composer.json\`, \`composer.lock\`
    Runtime_Requirements: PHP 5.3.2 and higher versions; Composer 2.2.0 and higher versions

    `}
</YamlTable>

For more information, see [endorctl commands](/developers-api/cli/commands) and [working with the API](/developers-api/cli/commands/api).

## Build your software

To run a complete and accurate scan with Endor Labs, ensure that the software can be successfully built, incorporating well-formatted manifest files. To maximize the benefits of an Endor Labs OSS scan, you should perform a comprehensive testing as a post-build step, either locally or in a CI pipeline. Use the following commands to verify that the software can be built successfully with well-formatted manifest files before initiating the scan.

<Tabs>
  <Tab title="Java (Maven)">
    ```bash theme={null}
    mvn dependency:tree
    mvn clean install
    ```
  </Tab>

  <Tab title="Java (Gradle)">
    ```bash theme={null}
    gradle dependencies --configuration runtimeClasspath
    ./gradlew assemble
    # Use `gradle assemble` if you do not have a gradle wrapper in your repository
    ```
  </Tab>

  <Tab title="JavaScript (npm)">
    ```bash theme={null}
    npm install
    ```
  </Tab>

  <Tab title="JavaScript (yarn)">
    ```bash theme={null}
    yarn install
    ```
  </Tab>

  <Tab title="JavaScript (pnpm)">
    ```bash theme={null}
    export ENDOR_PNPM_ENABLED=true
    pnpm install
    ```
  </Tab>

  <Tab title="JavaScript (Rush)">
    ```bash theme={null}
    export ENDOR_RUSH_ENABLED=true
    rush install
    ```
  </Tab>

  <Tab title=".NET (dotnet)">
    ```bash theme={null}
    dotnet restore
    dotnet build
    ```
  </Tab>

  <Tab title="PHP (composer)">
    ```bash theme={null}
    composer install
    ```
  </Tab>

  <Tab title="Golang">
    ```bash theme={null}
    go mod tidy
    ```
  </Tab>

  <Tab title="Python (pip)">
    ```bash theme={null}
    python3 -m venv venv
    source venv/bin/activate
    venv/bin/python3 -m pip install
    ```
  </Tab>

  <Tab title="Python (poetry)">
    ```bash theme={null}
    poetry install
    ```
  </Tab>

  <Tab title="Ruby (bundler)">
    ```bash theme={null}
    bundler install
    ```
  </Tab>

  <Tab title="Swift/Objective-C">
    ```bash theme={null}
    pod install
    ```
  </Tab>

  <Tab title="Scala (sbt)">
    ```bash theme={null}
    sbt projects
    sbt compile
    sbt dependencyTree
    ```
  </Tab>

  <Tab title="Scala (Gradle)">
    ```bash theme={null}
    gradle dependencies --configuration runtimeClasspath
    ./gradlew assemble
    # Use `gradle assemble` if you do not have a gradle wrapper in your repository
    ```
  </Tab>

  <Tab title="Rust (Cargo)">
    ```bash theme={null}
    cargo build
    ```
  </Tab>
</Tabs>

## Persistently set environment variables for endorctl

To persistently set an environment variable, append the environment variable and the value to `~/.endorctl/config.yaml`. This configuration file is for CLI usage.

For example, if your GitHub Enterprise Server URL was [https://api.github.com](https://api.github.com) you can set the variable to persist in your configuration using the following command.

```bash theme={null}
echo "ENDOR_SCAN_SOURCE_GITHUB_API_URL: https://api.github.com" >> ~/.endorctl/config.yaml
```

See [endorctl commands for all supported commands and environment variables](/developers-api/cli/environment-variables).
