Command-line tool and Go SDK for scanning source code and querying the SCANOSS platform. It fingerprints a project with WFP (Winnowing FingerPrint), uploads the fingerprints to the SCANOSS v3 API, and can decorate results with vulnerabilities, licenses, cryptography, geoprovenance, copyright, dependency, and component data.
Important
This CLI is not compatible with OSSKB.org.
See CHANGELOG.md for release notes and the releases page for the latest version.
cmd/— the CLI (Cobra);cmd/scanoss-cliis thego installentrypoint.pkg/— the reusable Go SDK: scan and decoration services, fingerprinting, file filtering, SBOM read/write, and the low-level API client.internal/— private helpers (CLI config, build config, logging, output, version).libscanoss/— C shared library with Python and Node.js wrappers.
OpenAPI types come from the published SDK github.com/scanoss/scanoss.api-sdk
(imported as scanossapi); there is no local codegen step.
go install github.com/scanoss/scanoss.go/cmd/scanoss-cli@latestThis installs the CLI as scanoss-cli (Go names the binary after its package
directory) — matching the examples below and avoiding a clash with the SCANOSS
scan engine (also scanoss) on your PATH.
Download the archive for your platform from the
releases page, extract it, and
move the scanoss-cli binary onto your PATH:
# Linux (amd64) — adjust the archive for your OS/arch
tar xzf scanoss-cli-linux-amd64.tar.gz
sudo mv scanoss-cli /usr/local/bin/On Windows, unzip the .zip and add the folder to your PATH. On macOS, an
unsigned direct download may be quarantined by Gatekeeper — clear it with
xattr -d com.apple.quarantine ./scanoss-cli. Verify a download against
checksums.txt with sha256sum -c --ignore-missing checksums.txt.
Multi-arch images (linux/amd64, linux/arm64) are published to GHCR on each
release. Mount the code to scan and pass the CLI arguments:
docker run --rm -v "$PWD:/src" ghcr.io/scanoss/scanoss:latest \
scan /src --api-key "$SCANOSS_API_KEY" > results.jsonUse :latest or a version tag (e.g. :0.1.0).
The image runs as a non-root user, so writing output into the mounted folder
(--output /src/results.json) can fail with a permission error. Either redirect
stdout on the host as above, or run the container as your own user so writes are
owned by you:
docker run --rm --user "$(id -u):$(id -g)" -v "$PWD:/src" \
ghcr.io/scanoss/scanoss:latest scan /src --api-key "$SCANOSS_API_KEY" --output /src/results.jsongit clone https://github.com/scanoss/scanoss.go.git
cd scanoss.go
make build # or: go build -o scanoss-cli ./cmd/scanoss-cli# Scan a project and save JSON results (default endpoint needs an API key)
scanoss-cli scan ./my-project --api-key "$SCANOSS_API_KEY" --output results.json
# Generate fingerprints only
scanoss-cli wfp ./my-project > project.wfp
# Refresh vulnerabilities/licenses on an existing inventory (no re-scan)
scanoss-cli enrich results.json --include vulns,licenses --api-key "$SCANOSS_API_KEY" > enriched.jsonAdd -v / --verbose to any command for structured debug logging on stderr — the
scan flow, each API request (method/URL/status/duration), and fingerprinting.
Stdout stays reserved for results, so logs never corrupt --output or piped JSON.
| Command | Purpose |
|---|---|
scan <path> |
Fingerprint a folder/file, scan against the SCANOSS v3 API, and output results (--format raw/spdx/cyclonedx; opt into dependency/vuln/license/crypto/geo layers with --include). |
scan wfp <wfp> |
Scan a pre-generated WFP file (no fingerprinting). |
wfp <path> |
Generate WFP fingerprints only (no upload). |
results <scan-id> |
Resume or poll a scan by its id. |
sbom <input> |
Produce an SBOM from a raw inventory, or convert between formats, offline (cyclonedx/spdx). |
enrich <input> |
Add purl-keyed layers (vulns/licenses/crypto/geo) to a raw or SBOM file. |
dependencies [path] |
Extract local dependencies, or query direct/transitive deps for a PURL. |
vulnerabilities |
Known vulnerabilities / CPEs for components. |
cryptography |
Algorithms, library hints, and version ranges. |
licenses |
Declared licenses, attribution files, per-file evidence. |
geoprovenance |
Component origin and contributor countries. |
copyright |
Copyright evidence and holders. |
components |
Search, versions, and lifecycle status. |
config |
Store settings in ~/.scanoss/settings.json (see Configuration). |
The default endpoint (https://api.scanoss.com) requires an API key; a custom API
URL (e.g. an on-prem deployment) may run keyless.
See CLIENT_HELP.md for full usage — every command and
subcommand with flags, examples, the scanoss.json reference (BOM + skip rules),
SBOM output formats, and default values.
Store your credentials once instead of passing --api-key on every command:
scanoss-cli config set api-key SC_abc123def456
scanoss-cli scan ./my-project --output results.jsonSettings use the same names as the flags: api-key, api-url, proxy and ca-cert.
They live in ~/.scanoss/settings.json:
{
"api_key": "SC_abc123def456",
"api_url": "https://api.scanoss.com",
"proxy": "http://proxy.example.com:8080",
"ca_cert": "/etc/ssl/corp-ca.pem"
}The command line always uses the dashed names; snake_case is the file's format, not a
second way to type a key.
Every setting resolves the same way, and each has a matching flag:
--flag > environment variable > ~/.scanoss/settings.json > built-in default
The environment variable is the setting name in upper case with a SCANOSS_ prefix:
SCANOSS_API_KEY, SCANOSS_API_URL, SCANOSS_PROXY, SCANOSS_CA_CERT. An empty value
from the environment or the file is treated as unset and falls through to the next source.
scanoss-cli config set api-url https://scanoss.internal.example.com
# 1. the stored value is used
scanoss-cli scan .
# 2. the environment overrides the file
SCANOSS_API_URL=https://scanoss.staging.example.com scanoss-cli scan .
# 3. the flag overrides both
SCANOSS_API_URL=https://scanoss.staging.example.com \
scanoss-cli scan . --api-url https://api.scanoss.com--verbose reports which source won for each setting (the source only, never the key's
value).
config list shows the value each command will actually use, and where it came from:
$ scanoss-cli config list
api-key ******** (env: SCANOSS_API_KEY)
api-url https://scanoss.internal.example.com (config file)
Config file: /Users/you/.scanoss/settings.jsonThe API key is never printed. list and get always render it as ******** — there
is no flag that reveals it, so it cannot land in your shell history or a CI log. config get api-key therefore only tells you whether it is set (exit code 0 or 1). Scripts
that need the value should use $SCANOSS_API_KEY; to read your own file, open it
directly:
cat "$(scanoss-cli config path)"Non-secret values print normally, so config get composes:
$ scanoss-cli config get api-url
https://scanoss.internal.example.comA custom API URL may run keyless, so pointing the CLI at an internal deployment is one command:
scanoss-cli config set api-url https://scanoss.internal.example.com
scanoss-cli scan .HTTP_PROXY, HTTPS_PROXY and NO_PROXY are honoured with no flags. --proxy overrides
them for one run, and --ca-cert trusts a CA the system pool does not have — an internal
endpoint, or a proxy that intercepts TLS:
scanoss-cli scan . --proxy http://proxy.example.com:8080
scanoss-cli scan . --ca-cert /etc/ssl/corp-ca.pemThe CA is added to the system pool, so the public API keeps working, and verification
stays on — unlike --ignore-cert-errors. Both flags work on every command that reaches
the API. Proxy auto-configuration (PAC) is not supported: read the proxy out of the PAC
and pass it with --proxy.
Both can be stored, so neither flag has to be repeated:
scanoss-cli config set proxy http://proxy.example.com:8080
scanoss-cli config set ca-cert /etc/ssl/corp-ca.pem
scanoss-cli scan .A stored proxy takes precedence over HTTP_PROXY/HTTPS_PROXY. --ignore-cert-errors
is not storable — turning off verification stays a per-run choice.
Use the environment instead of a config file — no config set, and no key on the
command line where it would land in build logs:
- name: SCANOSS scan
env:
SCANOSS_API_KEY: ${{ secrets.SCANOSS_API_KEY }}
run: scanoss-cli scan . --output results.jsonscanoss-cli config set api-key SC_newkey789 # overwrite in place
scanoss-cli config unset api-key # remove the key
scanoss-cli config path # print the file locationHand-editing the file is supported, and keys this version does not recognize are left
untouched by config set.
Beyond the CLI, pkg/scanoss is a Go SDK for the SCANOSS services. The
pipeline runs a configurable set of decoration services over the same PURLs in
parallel, reports per-service progress, and returns one object keyed by service.
Chunking and the worker pool are handled internally.
import "github.com/scanoss/scanoss.go/pkg/scanoss"
client, err := scanoss.New(scanoss.Config{
APIKey: os.Getenv("SCANOSS_API_KEY"),
ChunkSize: 20, // PURLs per request
Workers: 10, // max concurrent requests
})
if err != nil {
return err
}
comps := scanoss.Components("pkg:github/scanoss/engine")
pipe := client.DecorationPipeline(
scanoss.ServiceVulnerabilities,
scanoss.ServiceLicenses,
)
pipe.Add(scanoss.ServiceCryptographyAlgorithms, scanoss.ServiceGeoprovenanceOrigin)
res, err := pipe.Run(context.Background(), comps)
if err != nil {
log.Fatal(err) // only if every service failed
}
fmt.Println(res.String())
for svc, e := range res.Errors { // per-service failures are recorded, not fatal
log.Printf("%s failed: %v", svc, e)
}Implement DecorationReporter and hand it to the call. Every update carries the service that
produced it, so one receiver renders them all — services run concurrently, so it must be safe for
concurrent use:
type bars struct{ mu sync.Mutex }
func (b *bars) Decorating(service string, done, total int) {
b.mu.Lock()
defer b.mu.Unlock()
fmt.Printf("%-26s %d/%d purls\n", service, done, total)
}
res, err := pipe.Run(ctx, comps, scanoss.WithDecorationReporter(&bars{}))The per-service methods take it too:
res, err := client.Vulnerabilities.Components(ctx, comps, scanoss.WithDecorationReporter(&bars{}))The SDK writes nothing until you ask it to — it will not put lines in your program's output uninvited. One call covers every package it is built from, not just the client:
scanoss.SetLogger(slog.Default()) // fold into your own stream
scanoss.SetLogger(slog.New(myHandler)) // keep them apart, or drop them
scanoss.SetLogger(nil) // back to silenceAt Debug this also explains file selection — which rules a collection applied, and
which rule excluded each file:
level=DEBUG msg="filters applied" builtinFolderRules=true gitignore=true matchers=51
level=DEBUG msg="file excluded" path=CHANGELOG.md rule=ext:.md
level=DEBUG msg="directory pruned" path=node_modules rule=dir:node_modules
Call it during initialisation: it is process-wide, so changing it while calls are in flight can split a run's output across two destinations.
scanoss.Components(...) produces entries with no version. When a version matters,
build the components directly:
comps := []scanoss.Component{
{Purl: "pkg:github/scanoss/engine", Requirement: "4.17.21"},
{Purl: "pkg:github/scanoss/engine", Requirement: "5.4.7"},
}Each decoration service is a grouped handle on the client:
res, err := client.Vulnerabilities.Components(ctx, comps) // *scanossapi.VulnerabilitiesResponse
// also: client.Licenses.Attribution, client.Cryptography.Algorithms,
// client.Geoprovenance.Origin, client.Copyright.Evidence, ...client, err := scanoss.New(scanoss.Config{APIKey: os.Getenv("SCANOSS_API_KEY")})
result, err := client.Scan.Folder(ctx, "./my-project")
// resume by id: client.Scan.Wait(ctx, scanID)client, err := scanoss.New(scanoss.Config{
APIKey: key,
Proxy: "http://proxy.example.com:8080", // empty honours HTTP(S)_PROXY
CACertFile: "/etc/ssl/corp-ca.pem", // added to the system pool
})
if err != nil {
return err // an unreadable CA file or a schemeless proxy fails here
}make build # build the CLI
make test # unit tests
make test-race # tests with the race detector
make lint # golangci-lint
make check # fmt-check + vet + lint + test (run before committing)See LICENSE.