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

# Self-Hosted Supply Chain Installation

## Supply Chain CLI

The Supply Chain CLI is a container image that can be downloaded and ran via Docker.

For prerequisites, including licenses, see [Prerequisites](/docs/products/airgap/airgap_prerequisites).

### Download

Download the Supply Chain CLI file and transfer it to the system where it will be deployed.

<Note>
  **Docker Command Fails**

  When using Docker commands, like `docker pull`, if you get a permission denied message, try using `sudo docker`, like `sudo docker pull`.

  Alternatively, add the user to the appropriate Docker group for Docker daemon permissions.
</Note>

1. Authenticate using `docker login`.

   * The username is the Registry Username.
   * The password is the Model Scanner License ID.
   * For information about licenses, see [Prerequisites](/docs/products/airgap/airgap_prerequisites#licenses).

   ```sh theme={null}
   docker login images.hiddenlayer.ai
   ```

2. Pull the HiddenLayer image.

   <ModelScannerCommandsDockerPullAisecPlatform />

3. Tag the image for your private registry.

   <ModelScannerCommandsDockerTagAisecPlatform />

4. Push the air-gapped image to your private registry. **Note**: Make sure you are logged in to your private registry in order to push the image.

   <ModelScannerCommandsDockerPushSupplyChainScannerCustomerRegistry />

<Note>
  **Notes**

  * You will run the Supply Chain CLI after you deploy the AI Security Platform and create an API key.
  * The above may need to be repeated for each updated release of Supply Chain.
</Note>

### Running Supply Chain CLI

Select your deployment type.

* **Hybrid**: Connecting a Self-Hosted Supply Chain to an Self-Hosted AI Security Platform.
* **Standalone**: Self-Hosted Supply Chain without a Self-Hosted AI Security Platform.

<Tabs>
  <Tab title="Hybrid">
    1. Export your HiddenLayer information (product license, API key, and API secret).

           <Accordion title="HiddenLayer Information Descriptions (Click to expand)">
             * Replace `%HIDDENLAYER_LICENSE%` with your HiddenLayer License.
             * Replace `%HL_API_KEY%` and `%HL_API_SECRET%` with your HiddenLayer API client ID and client secret, generated in the Platform Console.
             * For `HL_MODEL_SCANNER_PLATFORM_RESULTS_URL` and `HL_MODEL_SCANNER_TOKEN_URL`, replace `%HIDDENLAYER_PLATFORM_HOSTNAME%` with the URL for your Console.
               * Example: `http://server1.test.hiddenlayer.com`.
             * For Windows, replace `export` with `set`.
             * For information about licenses and keys, see [Prerequisites](/docs/products/airgap/airgap_prerequisites).
           </Accordion>

       ```
       export HL_LICENSE=%HIDDENLAYER_LICENSE%
       export HL_CLIENT_ID=%HL_API_KEY%
       export HL_CLIENT_SECRET=%HL_API_SECRET%
       export HL_MODEL_SCANNER_PLATFORM_RESULTS_URL=%HIDDENLAYER_PLATFORM_HOSTNAME%
       export HL_MODEL_SCANNER_TOKEN_URL=%HIDDENLAYER_PLATFORM_HOSTNAME%
       ```

    2. Run the Supply Chain command.

           <Accordion title="Supply Chain Command Descriptions (Click to expand)">
             * Replace `$(directory)` with the path on the local machine where models to be scanned are located. Example: `/Users/username/Downloads`.
               * To scan a specific file in the folder, update `--input /files-to-scan` with the file name. Example: `--input /files-to-scan/test_model.pkl`.
             * Replace `<location of supply chain cli in local registry>` with the location of the Supply Chain image.
               * Example for Docker image:
             * Replace `$model_name` with either the name of an existing model from the inventory (to add a new scan version to the existing model) or a new, unique name (to create a new model entry in the inventory). Example: `Test Scan`.
             * Using `--persist` adds the scan results to an existing model in the AI Security Platform Console.
             * In the following example, `jq` is used to make the output more readable. Remove `| jq` if you do not want to use jq.
           </Accordion>

       ```
       docker run --rm \
           -e HL_LICENSE \
           -e HL_CLIENT_ID \
           -e HL_CLIENT_SECRET \
           -e HL_MODEL_SCANNER_PLATFORM_RESULTS_URL \
           -e HL_MODEL_SCANNER_TOKEN_URL \
           -v ${directory}:/files-to-scan \
           <location of supply chain cli in local registry> --input /files-to-scan --persist --model-name="$model_name" | jq
       ```
  </Tab>

  <Tab title="Standalone">
    1. Export your HiddenLayer information (product license, API key, and API secret).

           <Accordion title="HiddenLayer Information Descriptions (Click to expand)">
             * Replace `%HIDDENLAYER_LICENSE%` with your HiddenLayer License.
             * For Windows, replace `export` with `set`.
             * For information about licenses and keys, see [Prerequisites](/docs/products/airgap/airgap_prerequisites).
           </Accordion>

       ```
       export HL_LICENSE=%HIDDENLAYER_LICENSE%
       ```

    2. Run the Supply Chain command.

           <Accordion title="Supply Chain Command Descriptions (Click to expand)">
             * Replace `$(directory)` with the path on the local machine where models to be scanned are located. Example: `/Users/username/Downloads`.
               * To scan a specific file in the folder, update `--input /files-to-scan` with the file name. Example: `--input /files-to-scan/test_model.pkl`.
             * Replace `<location of supply chain cli in local registry>` with the location of the Supply Chain image.
               * Example for Docker image: `<ModelScannerSupplyChainScannerImageAisecPlatform />`
             * Replace `$model_name` with either the name of an existing model from the inventory (to add a new scan version to the existing model) or a new, unique name (to create a new model entry in the inventory). Example: `Test Scan`.
             * In the following example, `jq` is used to make the output more readable. Remove `| jq` if you do not want to use jq.
           </Accordion>

       ```
       docker run --rm \
           -e HL_LICENSE \
           -v ${directory}:/files-to-scan \
           <location of supply chain cli in local registry> --input /files-to-scan --persist --model-name="$model_name" | jq
       ```
  </Tab>
</Tabs>

3. The scan results display in the terminal or command prompt. You can also log in to the Platform Console to view the scan results.
4. For more information about Supply Chain CLI command-line arguments, for input and output, see [Command-Line Arguments](/docs/products/supply-chain/cli/commandline_arguments)

<Accordion title="Supply Chain Sample Output (Click to expand)">
  The following is an example output for a Supply Chain CLI scan using a terminal or command prompt.

  ```json theme={null}
  {
    "scan_id": "eadcb851-bf57-4e57-acbe-c3e7fededd44",
    "start_time": "2025-10-24T21:08:51.96Z",
    "end_time": "2025-10-24T21:08:52.222Z",
    "status": "done",
    "version": "25.9.0",
    "$schema_version": "3.3.0",
    "inventory": {
      "requested_scan_location": "/files-to-scan/test_model_safe.pkl",
      "model_id": "00000000-0000-0000-0000-000000000000",
      "model_name": "test scan 01",
      "model_version": "1761340131",
      "model_version_id": "00000000-0000-0000-0000-000000000000"
    },
    "file_results": [
      {
        "file_instance_id": "0854d4a0-3acf-4e15-b3b5-63090bfd218a",
        "file_location": "/files-to-scan/test_model_safe.pkl",
        "status": "done",
        "start_time": "2025-10-24T21:08:51.96Z",
        "end_time": "2025-10-24T21:08:52.222Z",
        "details": {
          "sha256": "bce834158f08706277377c50226e31b74e372770fe26fc5bdb4ff74de9924ffa",
          "file_type": "pickle",
          "file_type_details": {
            "pickle_header": {
              "pickle_version": "3",
              "type": "pickle"
            },
            "pickle_modules": [
              "sklearn.pipeline.pipeline",
              "sklearn.preprocessing._data.standardscaler",
              "callable: numpy.core.multiarray.scalar",
              "callable: numpy.dtype",
              "callable: numpy.core.multiarray._reconstruct",
              "numpy.ndarray",
              "lightgbm.sklearn.lgbmclassifier",
              "lightgbm.basic.booster",
              "callable: collections.defaultdict",
              "collections.ordereddict",
              "sklearn.preprocessing._label.labelencoder"
            ],
            "subtype": [
              "numpy",
              "scikit"
            ]
          },
          "estimated_time": ""
        },
        "seen": "2025-10-24T21:08:51.96Z",
        "detections": []
      }
    ],
    "detection_count": 0,
    "file_count": 1,
    "files_with_detections_count": 0,
    "summary": {
      "detection_count": 0,
      "file_count": 1,
      "severity": "safe",
      "files_with_detections_count": 0,
      "files_failed_to_scan": 0,
      "unknown_files": 0
    }
  }
  ```
</Accordion>

<Note>
  **Self-Signed Certificates Breaks Persist Flag**

  When using a self-signed certificate for testing, using the `--persist` flag results in a failed scan. Scan results never display in the Platform Console.

  The container does not trust the internal certificate. To fix this, you must fetch the certificate and mount it into the container.

  To fetch the certificate:

  ```sh theme={null}
  echo | openssl s_client -connect <hostname>:443 \
    -servername <hostname> 2>/dev/null \
    | openssl x509 > ~/selfsigned.pem
  ```

  Add these flags to the Docker run command:

  ```sh theme={null}
  -e SSL_CERT_FILE=/etc/ssl/certs/selfsigned.pem \
  -e REQUESTS_CA_BUNDLE=/etc/ssl/certs/selfsigned.pem \
  -v ~/selfsigned.pem:/etc/ssl/certs/selfsigned.pem
  ```
</Note>
