fix(sbom): resolve Bun dependency edges from the lock graph - #1125
Merged
Merged
Conversation
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.
This was referenced Sep 14, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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
resolveDependencyEdgesgains one dispatch branch and the edge building itself is untouched: dedup, the filter that prevents dangling references, and root anchoring all still apply.nodeIdsForreturns a list rather than a single id because Bun encodes duplicate versions in the key, so onename@versioncan have several nodes when the same version is installed under more than one parent. Returning only the first would lose one of the parents.readAndParseBunLockmoves 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:DEPENDENCY_OFedgesThe one remaining parentless package is the root project, which correctly has none.
examples/bun-workspacegoes 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