Build a matrix of every language and package manager you use, then test whether the candidate SCA tool reads the manifest, the lockfile and, where needed, the build resolved tree for each. Coverage claims are only meaningful per cell, not as a count of supported languages.
Why a language list is not enough
"Supports Java" can mean it reads a pom.xml, resolves the full tree including transitive dependencies, handles a parent POM, and copes with a private repository. Or it can mean it lists only the dependencies declared in one file. The difference decides whether you see the vulnerable package three levels down.
Step 1: inventory what you really use
Ask platform teams, then confirm by scanning your repositories for files such as package-lock.json, yarn.lock, pnpm-lock.yaml, poetry.lock, requirements.txt, go.sum, Cargo.lock, Gemfile.lock, pom.xml, build.gradle and *.csproj. Note repos with a manifest but no lockfile. Those are the weak spots, because the version actually installed is not recorded.
Step 2: build the matrix
| Ecosystem | Manifest read | Lockfile read | Transitive tree | Resolved at build | Private registry |
|---|---|---|---|---|---|
| npm family | test | test | test | n/a | test |
| Python | test | test | test | test | test |
| JVM | test | test | test | test | test |
| Go | test | test | test | n/a | test |
| Others you run | test | test | test | test | test |
Replace each "test" with a result from a real repository of yours. Include at least one monorepo with several lockfiles.
Step 3: use a known answer
Pick one repo where you can produce an authoritative dependency list with the package manager itself. Compare counts with the tool. A gap means missed packages or counting differences, and both are worth understanding.
Step 4: where static parsing runs out
Static parsing of files can miss dependencies that are only resolved during a build. GitHub's dependency graph is built by parsing manifest and lock files, and GitHub offers a dependency submission API so build time resolved dependencies can be sent as a snapshot with PURLs, direct or indirect relationship, and runtime or development scope. It also notes that user submissions take precedence over automatic detection for the same manifest (see Sources). The lesson for any SCA tool: ask whether it can accept build time dependency data when static parsing is not enough, and in what format.
Step 5: formats you may need to exchange
Check SBOM import and export. CycloneDX is standardized as ECMA-424, with JSON and XML as common formats, and the NTIA minimum elements name SPDX, CycloneDX and SWID as formats used for automation. Confirm which the tool reads and writes, and test a round trip.
Step 6: record gaps as findings
For every empty cell, write down a workaround: a build step that emits a lockfile, a submission job, or a documented exclusion. A known gap with a plan is acceptable. An unknown gap is the risk.
Related: find every lockfile in a monorepo and does the scanner cover private registries and internal packages.
Try it yourself
Click through it at your own pace, or open it full screen.
Check whether the inventory separates direct from transitive packages. Your matrix should demand that.
Safeguard offers SBOM and dependency scanning, and a free scan at gold.safeguard.sh/scan gives a quick first inventory to compare against your own list.
Quick check
What if a repo has no lockfile?
Add one if the package manager supports it. Without it, installed versions are not recorded and any scan is an estimate.
Is one SBOM format enough?
Often yes internally, but buyers and partners may ask for another. Check that the tool can export what you are asked for.
Sources
- GitHub Docs: About the dependency graph
- GitHub Docs: Dependency submission REST API
- CycloneDX specification overview
- NTIA: The Minimum Elements for a Software Bill of Materials
Last reviewed: 19 October 2026.