Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions lib/utils/sbom-spdx.js
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,13 @@ const toSpdxID = (node) => {
// Strip leading @ for scoped packages
name = name.replace(/^@/, '')

// Escape literal dots before mapping the scope separator to a dot, so a
// scoped name and an unscoped name that only differ by `/` vs `.` (e.g.
// `@a/b` and `a.b`) don't collapse to the same SPDXID. A collision there
// would drop one of the two distinct packages from the document, since the
// identifier is used to dedupe components.
name = name.replace(/\./g, '..')

// Replace slashes with dots
name = name.replace(/\//g, '.')

Expand Down
29 changes: 29 additions & 0 deletions test/lib/utils/sbom-spdx.js
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,35 @@ t.test('single node - linked', t => {
t.end()
})

t.test('scoped and dotted unscoped deps get distinct SPDXIDs', t => {
// `@a/b` and `a.b` are different packages but both used to map to
// SPDXRef-Package-a.b-1.0.0, so the second collided with the first and was
// dropped from the document during component dedup.
const scoped = {
packageName: '@a/b',
version: '1.0.0',
pkgid: '@a/b@1.0.0',
package: {},
location: 'node_modules/@a/b',
edgesOut: [],
}
const dotted = {
packageName: 'a.b',
version: '1.0.0',
pkgid: 'a.b@1.0.0',
package: {},
location: 'node_modules/a.b',
edgesOut: [],
}
const node = { ...root, edgesOut: [{ to: scoped }, { to: dotted }] }
const res = spdxOutput({ npm, nodes: [node, scoped, dotted] })
const ids = res.packages.map(p => p.SPDXID)
t.equal(res.packages.length, 3, 'both deps and the root are present')
t.equal(new Set(ids).size, ids.length, 'every package has a unique SPDXID')
t.equal(ids.filter(id => id === 'SPDXRef-Package-a.b-1.0.0').length, 1)
t.end()
})

t.test('node - with deps', t => {
const node = { ...root,
edgesOut: [
Expand Down
Loading