Skip to content

fix(parser): five-path cap leaves gaps in the SBOM dependency graph #1079

Description

@sonukapoor

Note: this is an in-house item already being handled by the maintainer - not open for contribution. Filed for tracking only.

Problem

upsertPackage in src/parsers/utils.ts caps stored dependency paths at five per package:

existing.paths = uniquePathArrays([...(existing.paths ?? []), ...(candidate.paths ?? [])]).slice(0, 5);

That bound is fine for remediation output, where a representative path is enough to explain why a package is present. It becomes visible once those paths are used to build a dependency graph, because any package reachable by more than five routes loses edges.

Concrete case

Scanning this repo with --sbom spdx --prod-only produces 51 DEPENDENCY_OF edges. Snyk's SPDX for the same repo produces 52. The single missing edge is:

semver@7.7.4 -> node-abi@3.89.0

semver@7.7.4 is genuinely reachable through node-abi, but its five recorded paths all run through jest:

["project","jest","@jest/core","@jest/reporters","istanbul-lib-instrument","semver"]
["project","jest","@jest/core","@jest/transform","babel-plugin-istanbul","istanbul-lib-instrument","semver"]
["project","jest","jest-cli","@jest/core","@jest/reporters","istanbul-lib-instrument","semver"]
["project","jest","@jest/core","@jest/reporters","@jest/transform","babel-plugin-istanbul","istanbul-lib-instrument","semver"]
["project","jest","@jest/core","jest-config","babel-jest","babel-plugin-istanbul","istanbul-lib-instrument","semver"]

There is a second effect worth noting. Paths come from loadNpmLockGraph, which is not prodOnly-aware, so under --prod-only a package can retain only paths that traverse packages excluded from the output. The parent lookup then finds nothing and the package ends up with no parent edge at all, which is what happens to semver above.

Why it matters

Dependency relationships are one of the seven NTIA minimum elements that Executive Order 14028 points to. Packages are always complete in our SBOM; only the edges between them can be partial. That is currently documented as a known limitation in website/docs/spdx.md, but a partial graph is a weaker artifact for the compliance audience SPDX serves.

Possible directions

Not yet decided, and each needs measuring before committing:

  1. Raise or remove the cap. Simplest, but the bound exists to keep large trees manageable and the memory cost on a big monorepo needs measuring first.
  2. Make path retention prodOnly-aware so a prod-only scan keeps prod-reachable paths rather than the first five found.
  3. Keep the cap for remediation output but compute graph edges from the full lock graph separately, so SBOM completeness does not depend on a display-oriented bound.

Option 3 looks most promising because it decouples the two use cases, but it needs a look at what loadNpmLockGraph can expose without a second traversal.

Notes

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingin-houseMaintainer-handled internal work - not open for contribution

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions