Visitar URL original
fix(sbom): dedupe per-node dependsOn / relationships by mikaelkristiansson · Pull Request #9311 · npm/cli · GitHub
Skip to content

fix(sbom): dedupe per-node dependsOn / relationships - #9311

Merged
owlstronaut merged 1 commit into
npm:latestfrom
mikaelkristiansson:fix/sbom-dedupe-dependson
May 6, 2026
Merged

owlstronaut merged 1 commit into
npm:latestfrom
mikaelkristiansson:fix/sbom-dedupe-dependson

Conversation

@mikaelkristiansson

Copy link
Copy Markdown
Contributor

Summary

Closes the per-node duplication gap left by #7992.

A node can have multiple outgoing edges resolving to the same name@version — typically when a package declares both a direct dependency and an npm alias to the same package, e.g.:

{
  "dependencies": {
    "lodash": "^4.17.21",
    "lodash-aliased": "npm:lodash@^4.17.21"
  }
}

toCyclonedxDependency and the SPDX relationship loop both map each edge through name@version ID generation without deduplicating, so the per-node dependsOn array (CycloneDX) and DEPENDENCY_OF relationships (SPDX) end up with duplicate entries.

CycloneDX 1.5 requires dependsOn items to be unique, so downstream validators (e.g. Dependency Track) reject the SBOM with:

$.dependencies[N].dependsOn: must have only unique items in the array

Changes

  • lib/utils/sbom-cyclonedx.js: wrap the dependsOn array in [...new Set(...)] after mapping edges to refs.
  • lib/utils/sbom-spdx.js: dedupe per source-node relationships by the (spdxElementId, relatedSpdxElement, relationshipType) triple.
  • Test cases added to both test/lib/utils/sbom-cyclonedx.js and test/lib/utils/sbom-spdx.js covering the duplicate-edges-to-same-target scenario, with explicit assertions plus snapshot updates.

Test plan

  • node . run test -- test/lib/utils/sbom-cyclonedx.js test/lib/utils/sbom-spdx.js — passes
  • 100% coverage on both touched files
  • Snapshot diff is purely additive (no existing snapshots changed)
  • Schema-validation tests in both files still pass for all snapshots
  • Reproduced original issue locally with the alias example, ran patched npm against it, confirmed both CycloneDX dependsOn and SPDX relationships are now deduped

Fixes #9310

A node can have multiple outgoing edges resolving to the same
`name@version` (e.g. when a package declares both a direct dependency
and an alias to the same package: `foo: ^1` plus `foo-aliased:
npm:foo@^1`). The SBOM generators map each edge to a CycloneDX ID or
SPDX relationship, which produces duplicate entries inside the
per-node `dependsOn` array (CycloneDX) and per-node `DEPENDENCY_OF`
relationships (SPDX).

CycloneDX 1.5 requires `dependsOn` items to be unique, so downstream
schema validators (e.g. Dependency Track) reject the SBOM with
"must have only unique items in the array".

PR npm#7992 fixed the analogous duplication at the top level
(`components` / `dependencies` / `packages`) but left the per-node
arrays untouched. This change closes that gap by deduplicating both:

- CycloneDX: `dependsOn` is wrapped in `[...new Set(...)]`
- SPDX: per-source-node relationships are deduped by the
  `(spdxElementId, relatedSpdxElement, relationshipType)` triple

Fixes npm#9310
@mikaelkristiansson
mikaelkristiansson requested a review from a team as a code owner May 5, 2026 13:06
@owlstronaut
owlstronaut merged commit d623988 into npm:latest May 6, 2026
22 checks passed
@github-actions

github-actions Bot commented May 6, 2026

Copy link
Copy Markdown
Contributor

🎉 Backport to release/v11 created: #9318

owlstronaut pushed a commit that referenced this pull request May 6, 2026
Backport of #9311 to `release/v11`.

Co-authored-by: Mikael Kristiansson <1733784+mikaelkristiansson@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] npm sbom emits duplicate entries in CycloneDX dependsOn / SPDX relationships when a node has multiple edges to the same name@version (incomplete fix for #6967)

2 participants