Skip to content

Commit

Permalink
feat: distribution url to SBOM (#110)
Browse files Browse the repository at this point in the history
fixes #47

---------

Signed-off-by: Jan Kowalleck <jan.kowalleck@gmail.com>
  • Loading branch information
jkowalleck committed May 27, 2024
1 parent 28b1f4b commit 5a29592
Show file tree
Hide file tree
Showing 27 changed files with 13,536 additions and 19 deletions.
9 changes: 6 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,16 +51,19 @@
],
"dependencies": {
"@cyclonedx/cyclonedx-library": "^6.8.0",
"@yarnpkg/cli": "^4.1.0",
"@yarnpkg/core": "^4.0.3",
"@yarnpkg/fslib": "^3.0.2",
"@yarnpkg/cli": "^4",
"@yarnpkg/core": "^4",
"@yarnpkg/fslib": "^3",
"@yarnpkg/plugin-git": "^3",
"clipanion": "^4.0.0-rc.3",
"hosted-git-info": "^7",
"normalize-package-data": "^3||^4||^5||^6",
"packageurl-js": "^1.2.1",
"typanion": "^3.14.0",
"xmlbuilder2": "^3.1.1"
},
"devDependencies": {
"@types/hosted-git-info": "^3.0.5",
"@types/mocha": "^10.0.6",
"@types/node": "ts5.4",
"@types/normalize-package-data": "^2.4.4",
Expand Down
20 changes: 20 additions & 0 deletions src/_helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ Copyright (c) OWASP Foundation. All Rights Reserved.
*/

import { writeSync } from 'fs'
import GitHost from 'hosted-git-info'

export async function writeAllSync (fd: number, data: string): Promise<number> {
const b = Buffer.from(data)
Expand All @@ -39,3 +40,22 @@ export async function writeAllSync (fd: number, data: string): Promise<number> {
export function isString (v: any): v is string {
return typeof v === 'string'
}

export function tryRemoveSecretsFromUrl (url: string): string {
try {
const u = new URL(url)
u.password = ''
return u.toString()
} catch {
return url
}
}

export function tryRemoveSecretsFromGitUrl (gitUrl: string): string {
const gitInfo = GitHost.fromUrl(gitUrl)
if (gitInfo === undefined) {
return gitUrl
}
gitInfo.auth = undefined
return gitInfo.toString()
}
60 changes: 57 additions & 3 deletions src/builders.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,18 @@ Copyright (c) OWASP Foundation. All Rights Reserved.

// import submodules so to prevent load of unused not-tree-shakable dependencies - like 'AJV'
import type { FromNodePackageJson as PJB } from '@cyclonedx/cyclonedx-library/Builders'
import { ComponentType, LicenseAcknowledgement } from '@cyclonedx/cyclonedx-library/Enums'
import { ComponentType, ExternalReferenceType, LicenseAcknowledgement } from '@cyclonedx/cyclonedx-library/Enums'
import type { FromNodePackageJson as PJF } from '@cyclonedx/cyclonedx-library/Factories'
import { Bom, Component, type License, Property, type Tool } from '@cyclonedx/cyclonedx-library/Models'
import { Bom, Component, ExternalReference, type License, Property, type Tool } from '@cyclonedx/cyclonedx-library/Models'
import { BomUtility } from '@cyclonedx/cyclonedx-library/Utils'
import { Cache, type FetchOptions, type Locator, type LocatorHash, type Package, type Project, structUtils, ThrowReport, type Workspace } from '@yarnpkg/core'
import { ppath } from '@yarnpkg/fslib'
import { gitUtils as YarnPluginGitUtils } from '@yarnpkg/plugin-git'
import normalizePackageData from 'normalize-package-data'
import type { PackageURL } from 'packageurl-js'

import { getBuildtimeInfo } from './_buildtimeInfo'
import { isString } from './_helpers'
import { isString, tryRemoveSecretsFromGitUrl, tryRemoveSecretsFromUrl } from './_helpers'
import { PropertyNames, PropertyValueBool } from './properties'

type ManifestFetcher = (pkg: Package) => Promise<any>
Expand Down Expand Up @@ -193,6 +194,59 @@ export class BomBuilder {
return undefined
}

switch (true) {
case locator.reference.startsWith('workspace:'): {
// @TODO: add CDX-Property for it - cdx:yarn:reference:workspace = $workspaceName
// -- reminder: skip `workspace:.`
break
}
case locator.reference.startsWith('npm:'): {
// see https://github.com/yarnpkg/berry/blob/bfa6489467e0e11ee87268e01e38e4f7e8d4d4b0/packages/plugin-npm/sources/NpmHttpFetcher.ts#L51
const { params } = structUtils.parseRange(locator.reference)
if (params !== null && isString(params.__archiveUrl)) {
component.externalReferences.add(new ExternalReference(
tryRemoveSecretsFromUrl(params.__archiveUrl),
ExternalReferenceType.Distribution,
{ comment: 'as detected from YarnLocator property "reference::__archiveUrl"' }
))
}
// For range and remap there are no concrete evidence how the resolution was done on install-time.
// Therefore, do not do anything speculative.
break
}
case YarnPluginGitUtils.isGitUrl(locator.reference): {
component.externalReferences.add(new ExternalReference(
tryRemoveSecretsFromGitUrl(locator.reference),
ExternalReferenceType.VCS,
{ comment: 'as detected from YarnLocator property "reference"' }
))
break
}
case locator.reference.startsWith('http:') || locator.reference.startsWith('https:'): {
component.externalReferences.add(new ExternalReference(
tryRemoveSecretsFromUrl(locator.reference),
ExternalReferenceType.Distribution,
{ comment: 'as detected from YarnLocator property "reference"' }
))
break
}
case locator.reference.startsWith('link:'): {
// TODO: add CDX-Property for it - cdx:yarn:reference:link = relative path from workspace
// see https://github.com/yarnpkg/berry/tree/master/packages/plugin-link
break
}
case locator.reference.startsWith('portal:'): {
// TODO: add CDX-Property for it - cdx:yarn:reference:portal = relative path from workspace
// see https://github.com/yarnpkg/berry/tree/master/packages/plugin-link
break
}
case locator.reference.startsWith('file:'): {
// TODO: add CDX-Property for it - cdx:yarn:reference:portal = relative path from workspace
// see https://github.com/yarnpkg/berry/tree/master/packages/plugin-file
break
}
}

// even private packages may have a PURL for identification
component.purl = this.makePurl(component)

Expand Down
99 changes: 99 additions & 0 deletions tests/_data/snapshots/plain_alternative-package-registry.json.bin

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

75 changes: 75 additions & 0 deletions tests/_data/snapshots/plain_alternative-package-registry.xml.bin

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 6 additions & 1 deletion tests/_data/snapshots/plain_git-protocol-dependency.json.bin

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 5 additions & 1 deletion tests/_data/snapshots/plain_git-protocol-dependency.xml.bin

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 5a29592

Please sign in to comment.