IcebergSCA
Software composition analysis
Point IcebergSCA at a directory. It finds every dependency manifest and lockfile, builds the direct and transitive dependency set, looks each package up in OSV, and reports what it finds — including everything it could not check.
Install and scan¶
uv tool install git+https://github.com/IcebergAI/IcebergSCA@v0.1.0
pipx install git+https://github.com/IcebergAI/IcebergSCA.git@v0.1.0
# or run it without installing
uvx --from git+https://github.com/IcebergAI/IcebergSCA@v0.1.0 icebergsca scan .
It is a CLI application, not a library — install it as a tool rather than adding it to the dependency tree it is meant to be auditing. Then point it at a project:
Released from the repository, not from PyPI
There is no icebergsca package on PyPI, and anything published under that
name is not this project.
Pin the tag: without @v0.1.0 you get whatever main is at that moment.
Upgrade by re-running the same command against a newer tag with --force.
What an empty findings list means¶
An empty findings list means one of three different things — checked and clean, never checked, or partially checked — and only the report can say which. So the report says which:
- The OSV lookup not running is reported as "vulnerability lookup did not
run", never as "no vulnerabilities found". JSON carries an explicit
vulnerabilities_checkedflag; the SBOM carries anicebergsca:vulnerabilitiesCheckedproperty. - Packages OSV could not be asked about are listed individually as unchecked, not folded into a total.
- If OSV is unreachable, expired cache entries are served and labelled stale rather than quietly returning nothing.
- A lockfile that fails to parse falls back to its manifest with a warning that the versions are declared rather than installed.
- Skipped files, truncated graphs and unresolved constraints are counted and shown.
How a scan decides what it knows
-
Lockfile-first
Where a lockfile exists the resolved graph is read straight from it, so the report describes what is actually installed — not what would resolve today. Only without one does it fall back to resolving ranges against the registry, and those findings are labelled
resolvedrather thanpinned. -
Seven ecosystems, one report
Python, npm, Maven/Gradle, Go, Rust, .NET and Ruby — manifests and lockfiles both. A monorepo produces one merged report grouped by manifest, with every finding carrying the files that introduced it.
-
Transitive dependency graphs
Transitive edges, parent chains and scope propagated as the most-included value across every path — so a package reachable from a runtime dependency is never hidden behind a dev edge.
-
Five output formats
tablefor humans,jsonfor everything else, pluscsv, SARIF 2.1.0 for GitHub code scanning, and CycloneDX 1.6 that doubles as a VEX document. SARIF and CycloneDX are validated against the official schemas in the test suite. -
Findings never change the exit code
Exit
0means the scan completed, findings or not. A non-zero exit always means the tool could not do its job, which is what keeps|| trueoff the end of the command and genuine failures visible. -
A skill for coding agents
A skill ships inside the wheel, following the convention FastAPI, Typer and SQLModel use. Agents that glob site-packages find it after install: invocation, the JSON schema, exit-code semantics, and the three fields to check before calling a project clean.
The tool's own dependencies¶
A dependency scanner with a large dependency tree of its own is a poor
advertisement. Ranges, SARIF and CycloneDX are hand-written rather than pulled
from packages, with correctness held by schema validation against the official
schemas. Maven graphs are reconstructed from Central rather than shelling out to
mvn, because running a project's build to discover its dependencies is itself
a supply chain risk. CI scans this repository with the tool on every run.