Skip to content

Commit

Permalink
feat: add rootComponentBuildSystem configuration
Browse files Browse the repository at this point in the history
resolves CycloneDX#1344

Signed-off-by: Jeremy Long <[email protected]>
  • Loading branch information
jeremylong committed Jan 7, 2025
1 parent 4ee0973 commit e89dabe
Show file tree
Hide file tree
Showing 13 changed files with 3,342 additions and 2 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ new CycloneDxWebpackPlugin(options?: object)
| **`rootComponentType`** | `{string}` | `"application"` | Set the RootComponent's type.<br/>See [the list of valid values](https://cyclonedx.org/docs/1.4/json/#metadata_component_type). Supported values depend on [CycloneDX-javascript-library]'s enum `ComponentType`. |
| **`rootComponentName`** | optional `{string}` | `undefined` | If `rootComponentAutodetect` is disabled, then this value is assumed as the "name" of the `package.json`. |
| **`rootComponentVersion`** | optional `{string}` | `undefined` | If `rootComponentAutodetect` is disabled, then this value is assumed as the "version" of the `package.json`. |
| **`rootComponentBuildSystem`** | optional `{string}` | `undefined` | Set's the URL for the RootComponent's External References' build-system. |
| **`collectEvidence`** | `{boolean}` | `false` | Whether to collect (license) evidence and attach them to the resulting SBOM. |

### Example
Expand Down
1 change: 1 addition & 0 deletions examples/simple/webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ const cycloneDxWebpackPluginOptions = {
rootComponentType: 'application',
rootComponentName: undefined,
rootComponentVersion: undefined,
rootComponentBuildSystem: undefined,
collectEvidence: true
}

Expand Down
23 changes: 21 additions & 2 deletions src/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,12 @@ export interface CycloneDxWebpackPluginOptions {
*/
rootComponentVersion?: CycloneDxWebpackPlugin['rootComponentVersion']

/**
* Set the externalReference URL for the build-system for the RootComponent.
* See {@link https://cyclonedx.org/docs/1.6/json/#metadata_component_externalReferences}.
*/
rootComponentBuildSystem?: CycloneDxWebpackPlugin['rootComponentBuildSystem']

/**
* Whether to collect (license) evidence and attach them to the resulting SBOM.
*
Expand Down Expand Up @@ -135,6 +141,7 @@ export class CycloneDxWebpackPlugin {
rootComponentType: CDX.Models.Component['type']
rootComponentName: CDX.Models.Component['name'] | undefined
rootComponentVersion: CDX.Models.Component['version'] | undefined
rootComponentBuildSystem: CDX.Models.ExternalReference['url'] | undefined

collectEvidence: boolean

Expand All @@ -149,6 +156,7 @@ export class CycloneDxWebpackPlugin {
rootComponentType = CDX.Enums.ComponentType.Application,
rootComponentName = undefined,
rootComponentVersion = undefined,
rootComponentBuildSystem = undefined,
collectEvidence = false
}: CycloneDxWebpackPluginOptions = {}) {
this.specVersion = specVersion
Expand All @@ -163,6 +171,7 @@ export class CycloneDxWebpackPlugin {
this.rootComponentType = rootComponentType
this.rootComponentName = rootComponentName
this.rootComponentVersion = rootComponentVersion
this.rootComponentBuildSystem = rootComponentBuildSystem
this.collectEvidence = collectEvidence
}

Expand Down Expand Up @@ -191,7 +200,6 @@ export class CycloneDxWebpackPlugin {
const bom = new CDX.Models.Bom()
bom.metadata.lifecycles.add(CDX.Enums.LifecyclePhase.Build)
bom.metadata.component = this.#makeRootComponent(compilation.compiler.context, cdxComponentBuilder, logger.getChildLogger('RootComponentBuilder'))

const serializeOptions: CDX.Serialize.Types.SerializerOptions & CDX.Serialize.Types.NormalizerOptions = {
sortLists: this.reproducibleResults,
space: 2 // TODO add option to have this configurable
Expand Down Expand Up @@ -244,6 +252,7 @@ export class CycloneDxWebpackPlugin {
// metadata matches this exact component.
// -> so the component is actually treated as the root component.
thisLogger.debug('update bom.metadata.component - replace', bom.metadata.component, 'with', component)
this.#ensureExternalRefs(component, thisLogger)
bom.metadata.component = component
} else {
thisLogger.debug('add to bom.components', component)
Expand Down Expand Up @@ -306,6 +315,14 @@ export class CycloneDxWebpackPlugin {
)
}

#ensureExternalRefs (component: CDX.Models.Component | undefined, logger: WebpackLogger): void {
if (component !== undefined && this.rootComponentBuildSystem !== undefined) {
const buildSystemRef = new CDX.Models.ExternalReference(this.rootComponentBuildSystem, CDX.Enums.ExternalReferenceType.BuildSystem)
component.externalReferences.add(buildSystemRef)
logger.debug('Added build system URL:', this.rootComponentBuildSystem)
}
}

#makeRootComponent (
path: string,
builder: CDX.Builders.FromNodePackageJson.ComponentBuilder,
Expand All @@ -316,7 +333,9 @@ export class CycloneDxWebpackPlugin {
: { name: this.rootComponentName, version: this.rootComponentVersion }
if (thisPackageJson === undefined) { return undefined }
normalizePackageJson(thisPackageJson, w => { logger.debug('normalizePackageJson from PkgPath', path, 'caused:', w) })
return builder.makeComponent(thisPackageJson)
const component = builder.makeComponent(thisPackageJson)
this.#ensureExternalRefs(component, logger)
return component
}

#finalizeBom (
Expand Down
Loading

0 comments on commit e89dabe

Please sign in to comment.