Skip to content

fix(sbom): resolve Bun dependency edges from the lock graph - #1125

Merged
sonukapoor merged 3 commits into
mainfrom
bugfix/issue-1108-bun-sbom-edges
Sep 12, 2026
Merged

sonukapoor merged 3 commits into
mainfrom
bugfix/issue-1108-bun-sbom-edges

Conversation

@sonukapoor

Copy link
Copy Markdown
Collaborator

Bun SBOM edges were rebuilt from PackageRef.paths, which are capped at five paths of ten segments per package, so large trees lost edges and a package whose surviving routes all traversed excluded packages was left with no parent at all. Dependency relationships are an NTIA minimum element, so an incomplete graph weakens the document for the compliance use case it exists to serve.

The key resolution added in #1117 already produces a complete parent-to-children map. This exposes it behind the same three-method shape npm and pnpm already present, so resolveDependencyEdges gains one dispatch branch and the edge building itself is untouched: dedup, the filter that prevents dangling references, and root anchoring all still apply.

nodeIdsFor returns a list rather than a single id because Bun encodes duplicate versions in the key, so one name@version can have several nodes when the same version is installed under more than one parent. Returning only the first would lose one of the parents.

readAndParseBunLock moves into the graph module so it and the parser share one reader. The parser already imported from the graph module, so the dependency stays one-directional.

Measured

examples/cline, a 1518-package Bun workspace monorepo:

before after
DEPENDENCY_OF edges 2344 3058
packages with no parent 22 1
dangling references 0 0

The one remaining parentless package is the root project, which correctly has none. examples/bun-workspace goes from 1 edge to 3, and from 3 parentless to 1.

Scope

Yarn keeps the path-derived fallback, tracked in #1109. That is now the only remaining gap, and the cheapest of the three: Yarn's traversal is already sound (measured at 0 to 1 percent fabricated paths across three large workspace monorepos), so it needs the adapter only.

Closes #1108

Bun SBOM edges were rebuilt from PackageRef.paths, which are capped at
five paths of ten segments per package, so large trees lost edges and a
package whose surviving routes all traversed excluded packages was left
with no parent at all. Dependency relationships are an NTIA minimum
element, so an incomplete graph weakens the document for the compliance
use case it exists to serve.

The key resolution added in #1117 already produces a complete
parent-to-children map. This exposes it behind the same three-method
shape npm and pnpm already present, so resolveDependencyEdges gains one
dispatch branch and the edge building itself is untouched: dedup, the
filter that prevents dangling references, and root anchoring all still
apply.

nodeIdsFor returns a list rather than one id because Bun encodes
duplicate versions in the key, so one name@version can have several
nodes when the same version is installed under more than one parent.
Missing that would lose one of the parents.

readAndParseBunLock moves into the graph module so both it and the parser
share one reader. The parser already imported from the graph module, so
the dependency stays one-directional.

Measured on examples/cline, a 1518-package Bun workspace monorepo:
DEPENDENCY_OF edges 2344 to 3058, packages with no parent 22 to 1, zero
dangling references. The one remaining parentless package is the root
project, which correctly has none. examples/bun-workspace goes 1 to 3
edges and 3 to 1.

Yarn keeps the path-derived fallback, tracked in #1109.

Closes #1108
Unit tests for the graph adapter: each version of a package mapping to
its own parent, node ids resolving back to name and version, and every
node id being returned when one version is installed under several
parents.

Integration tests at the edge builder, mirroring the pnpm ones: edges
resolved from the graph rather than returning nothing, every parent kept
for a package reached by more than one route, each version attributed to
the parent that installs it, root anchoring, and anchoring to the root
rather than referencing a package filtered out of the document. All five
fail without the dispatch branch.

New fixture tests/fixtures/lockfile-bun-graph, which carries a nested
duplicate and a workspace member.
Moves Bun from the path-derived caveat to the complete list, with the
measurement, and leaves Yarn as the one remaining known gap.
@sonukapoor
sonukapoor merged commit 3b2a9e2 into main Sep 12, 2026
9 checks passed
@sonukapoor
sonukapoor deleted the bugfix/issue-1108-bun-sbom-edges branch September 12, 2026 14:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(sbom): resolve Bun dependency edges from the lockfile graph

1 participant