Skip to content

fix(arborist): don't load store packages' devDependencies as required edges#9633

Merged
owlstronaut merged 1 commit into
npm:release/v11from
manzoorwanijk:backport/v11/9626
Jun 24, 2026
Merged

fix(arborist): don't load store packages' devDependencies as required edges#9633
owlstronaut merged 1 commit into
npm:release/v11from
manzoorwanijk:backport/v11/9626

Conversation

@manzoorwanijk

Copy link
Copy Markdown
Contributor

Backport of #9626 to release/v11.

Under install-strategy=linked, npm sbom exited with ESBOMPROBLEMS, reporting transitive packages' devDependencies as missing/required. A store package lives at node_modules/.store/<key>/node_modules/<pkg>, which makes it a structural tree top, so Node._loadDeps loaded its devDependencies as required edges. loadActual now flags such nodes isInStore and _loadDeps skips devDependencies for them, matching the hoisted strategy.

Cherry-picked cleanly except for a test-file context conflict: the unrelated applies root packageExtensions to a linked actual tree test (not part of this PR and not present on release/v11) was dropped from the resolution; only this fix's two regression tests are included.

References

Backports #9626

… edges (npm#9626)

In continuation of our exploration of using `install-strategy=linked` in
the [Gutenberg
monorepo](WordPress/gutenberg#75814), which
powers the WordPress Block Editor.

Under `install-strategy=linked`, `npm sbom` exited non-zero with
`ESBOMPROBLEMS`, reporting the devDependencies of transitive packages
(e.g. `matcha`, `tape`) as `missing: ... required by ...`. Those dev
dependencies are correctly not installed (the same is true under
hoisted), yet only the linked strategy treated them as
missing-and-required. Hoisted produced a clean SBOM for the same
dependency set.

A package in the linked strategy's store lives at
`node_modules/.store/<key>/node_modules/<pkg>`, which makes it a
structural tree top (`isTop`, no parent). `Node._loadDeps` loads
devDependencies for every top node, so each store package — a transitive
dependency whose devDependencies are never installed — gained required
`dev` edges. `npm sbom` reads the filesystem tree via `loadActual`,
queries it, and flags every non-optional missing edge, so those spurious
dev edges surfaced as `ESBOMPROBLEMS`. Standalone `npm audit` was
unaffected because it audits the virtual tree from the lockfile. Hoisted
was unaffected because its transitive packages have a real parent, so
they are not tops and never load devDependencies.

`load-actual.js` now flags a node as `isInStore` when its realpath sits
inside a `node_modules/.store/` directory, matching the flag the
isolated reifier already sets on ideal-tree store nodes.
`Node._loadDeps` excludes store nodes from the devDependency load
(`isTop && !globalTop && path && !this.isInStore`), so a store package —
a transitive dependency by definition — never gains required dev edges.
This makes the linked actual tree's edge semantics match hoisted.

Fixes npm#9610
Part of npm#9608
@owlstronaut owlstronaut merged commit a30d855 into npm:release/v11 Jun 24, 2026
16 checks passed
@manzoorwanijk manzoorwanijk deleted the backport/v11/9626 branch June 24, 2026 15:09
owlstronaut pushed a commit that referenced this pull request Jun 24, 2026
Restores the global 100% coverage gate on `release/v11`, which broke
after #9633.

`filterLinkedStrategyEdges` in `lib/commands/ls.js` skips dev edges on
non-root (store) packages — a guard added in #9095 to suppress false
`UNMET DEPENDENCY` output in the linked strategy. #9633 fixed the root
cause (store packages no longer load `devDependencies` as required
edges), so the test suite no longer produces a store package with a dev
edge, leaving that branch unexercised.

The guard is kept as defensive (a store package could still carry a dev
edge in untested paths) and marked `istanbul ignore`, so behavior is
unchanged. The full test suite passes at 100%.

This gap is invisible on direct pushes to `release/v11` because the Test
matrix only runs on PRs, so it surfaces on the first PR after #9633.

## References

Follows up #9633
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.

2 participants