diff --git a/lib/utils/sbom-cyclonedx.js b/lib/utils/sbom-cyclonedx.js index 5ff00e7eb9cdb..bb2aeaf16354c 100644 --- a/lib/utils/sbom-cyclonedx.js +++ b/lib/utils/sbom-cyclonedx.js @@ -1,6 +1,7 @@ const crypto = require('node:crypto') const parseLicense = require('spdx-expression-parse') const PackageJson = require('@npmcli/package-json') +const hostedGitInfo = require('hosted-git-info') const npa = require('npm-package-arg') const ssri = require('ssri') @@ -147,7 +148,9 @@ const toCyclonedxItem = (node, { packageType }) => { } if (node.package?.repository?.url) { - component.externalReferences.push(extRef(REF_VCS, node.package.repository.url)) + const repository = hostedGitInfo.fromUrl(node.package.repository.url) + const repositoryUrl = repository ? repository.toString() : node.package.repository.url + component.externalReferences.push(extRef(REF_VCS, repositoryUrl)) } if (node.package?.homepage) { diff --git a/test/lib/utils/sbom-cyclonedx.js b/test/lib/utils/sbom-cyclonedx.js index b9d947be054ef..8530543724499 100644 --- a/test/lib/utils/sbom-cyclonedx.js +++ b/test/lib/utils/sbom-cyclonedx.js @@ -334,6 +334,16 @@ t.test('node - with duplicate edges to same dep', t => { t.end() }) +t.test('single node - normalizes scp-style repository url', t => { + const pkg = { ...rootPkg, repository: { url: 'git@github.com:pkgjs/parseargs.git' } } + const node = { ...root, package: pkg } + const res = cyclonedxOutput({ npm, nodes: [node] }) + const repository = res.metadata.component.externalReferences + .find(reference => reference.type === 'vcs') + t.equal(repository.url, 'git+ssh://git@github.com/pkgjs/parseargs.git') + t.end() +}) + // Check that all of the generated test snapshots validate against the CycloneDX schema t.test('schema validation', t => { // Load schemas