Skip to main content
This page is for anyone who runs scanoss-py today, by hand or in a pipeline, and wants to move to scanoss-cli and the v3 API. It maps what you use now to what you use in v3, and lists the changes that can alter your results. scanoss-py keeps working on v2 for now, so you can move one pipeline at a time. For an overview of who is affected, see Migrating to v3.

Install scanoss-cli

scanoss-cli is a single binary with no runtime to install. Pick one:
  • Prebuilt binary for Linux, macOS, or Windows, from the releases page. See Installation.
  • Go, if you have Go 1.26 or later:
  • Docker, with the ghcr.io/scanoss/scanoss image. It replaces ghcr.io/scanoss/scanoss-py. Its entrypoint is scanoss-cli, so you pass the command and flags directly:
    See Using Docker for writing output into the mounted folder.
Check the install with scanoss-cli --version.

Point it at the API

scanoss-cli sends every request to https://api.scanoss.com unless you set another URL, and that endpoint requires an API key. A self-hosted v3 deployment may run without a key.
scanoss-py used the free OSSKB.org service when you gave it no API key. scanoss-cli has no such fallback, and it can’t talk to OSSKB.org or to a v2 server. Without a key, a scan against the default endpoint stops before it sends anything.
Each setting resolves in this order: the flag, then the environment variable, then ~/.scanoss/settings.json, then the built-in default. To store a value once on a workstation, use scanoss-cli config set:
In CI, use environment variables instead. See Configuration and API keys and authentication.

Commands

Flags

For every flag and default, see Scanning your project or run scanoss-cli scan --help.

Output formats

The default JSON output is a new format. scanoss-py wrote one entry per scanned file, each with a list of matches. scanoss-cli writes one entry per component, with the files it matched listed as evidence. Any script that reads scanoss-py results needs rewriting: jq filters, report generators, dashboards, and uploads to other tools.
scanoss-py (plain), keyed by file:
scanoss-cli (raw), grouped by component:
Both examples are shortened. The raw format also has a top-level vulnerabilities list when you add --include vulns, and a dependencies list when you add --include deps. scanoss-cli builds CycloneDX and SPDX documents itself, on your machine. See Output formats for every field. For example, to list the detected components:

Settings file (scanoss.json)

scanoss-cli reads the scanoss.json in the folder you scan, or the file you pass with --settings. It reads these keys: scanoss-cli applies the bom rules on your machine, after the result comes back. A component you identify is never dropped by bom.ignore, bom.remove, or the ranking threshold. For worked examples, see Approve components with scanoss.json.

Behaviour changes that alter results

Run a new scan and compare it with a scanoss-py result before you rely on it. These changes can make the same code give different matches.
  • Header skipping is on by default. scanoss-cli leaves each file’s licence header, leading comments, and imports out of its fingerprint. scanoss-py did this only with --skip-headers. Fingerprints differ, so matches can differ too. To fingerprint whole files as scanoss-py did, pass --skip-headers=false, or set "skip_headers": false under settings.file_snippet in scanoss.json. If scanoss.json sets skip_headers, it wins over the flag.
  • .gitignore is honoured. Files your .gitignore excludes are not scanned. Pass --gitignore=false to scan them.
  • Model weight files are skipped, for example .safetensors, .gguf, .onnx, .pt, and .bin files. --all-extensions turns off the built-in file rules.
  • Candidates per match. The v3 server decides how many candidate components it reports for each match. If you need every candidate, pass --max-components all, or a number with --max-components N.
  • Dependencies come from your files. --include deps reads your manifest and lock files on your machine. Where a lock file covers a manifest, it lists the resolved versions without dev dependencies.
  • More threads. Fingerprinting uses 10 workers by default instead of 5.
  • Exit codes. scanoss-cli exits with 1 on any error. It has no policy exit codes. To fail a build on a finding, use a gate script.

What has no equivalent

These scanoss-py features are not in scanoss-cli: If you rely on policy checks, reports, or exports, look at Earnie. It does these for every repository you connect. See Migrating from SCANOSS Tools. Anything you keep on scanoss-py keeps working on v2.

Migrate a CI pipeline

1

Swap the image or the install step

If your job runs in ghcr.io/scanoss/scanoss-py, switch to ghcr.io/scanoss/scanoss. That image has no shell, so it suits a job that runs one scanoss-cli command. If your job runs a shell script, install the binary in the job instead. The pull request Recipe shows how, with a checksum check.
2

Rename the environment variables

Keep SCANOSS_API_KEY as a secret. Replace SCANOSS_SCAN_URL with SCANOSS_API_URL, set to the base URL only. If you use the hosted API, you don’t need to set a URL at all.
3

Change the commands

Use the command and flag tables. Move --skip-extension and --skip-folder into settings.skip.patterns in scanoss.json. Decide whether you want header skipping on (see Behaviour changes).
4

Rewrite anything that reads the output

Move every jq filter and script to the raw format. If a step only needs an SBOM, ask for CycloneDX or SPDX directly with --format.
5

Rebuild your gates

Replace scanoss-py inspect checks with a Recipe: Scan every pull request for undeclared components, Licence and vulnerability gate for licences and vulnerabilities, and Generate an SBOM for each release to publish SBOMs.
6

Run both for a while

Keep the old scanoss-py job, set not to block, next to the new one until the results agree. Then remove it.

Verify the migration

Scan the same commit with both tools and compare the components each one found:
Some differences are expected, mostly from header skipping, .gitignore, and skipped model files. To see how much header skipping accounts for, scan again with --skip-headers=false. If a component you expected is missing, try --max-components all to see every candidate the server found.