Skip to content

Commit

Permalink
Cdx1.5 bom link models (#856)
Browse files Browse the repository at this point in the history

Signed-off-by: Jan Kowalleck <jan.kowalleck@gmail.com>
  • Loading branch information
jkowalleck authored Jun 27, 2023
1 parent 2c33005 commit a6ef130
Show file tree
Hide file tree
Showing 13 changed files with 216 additions and 176 deletions.
24 changes: 16 additions & 8 deletions HISTORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,16 @@ Added functionality regarding [_CycloneDX_ BOM-Link](https://cyclonedx.org/capab
* Interface `Spec.Protocol` now defines a new mandatory method `supportsVulnerabilityRatingMethod()` (via [#843])
This is only a breaking change if you custom-implemented this interface downstream; internal usage is non-breaking.
* Changed
* Classes `Serialize.{JSON,XML}.Normalize.*` support _CycloneDX_ Specification-1.5 now ([#505] via [#843])
* Functions `Serialize.{JSON,Xml}.Normalize.VulnerabilityRatingNormalizer.normalize()` omit unsupported values for `Models.Vulnerability.Rating.method` (via [#843])
This utilizes the new method `Spec.Protocol.supportsVulnerabilityRatingMethod()`.
* Classes `Validation\{Json,JsonStrict,Xml}Validator` support _CycloneDX_ Specification-1.5 now ([#505] via [#843])
* Namespace `Models`
* Method `BomRef.compare()` accepts every stringable now, was `Models.BomRef` only (via [#856])
* Class `ExternalReference`'s property `url` also accepts `BomLink` now, was `URL|string` only (via [#856])
* Class `Vulnerability.Affect`'s property `ref` also accepts `BomLinkElement` now, was `BomRef` only (via [#856])
* Namespace `Serialize.{JSON,XML}.Normalize`
* All classes support _CycloneDX_ Specification-1.5 now ([#505] via [#843])
* Methods `VulnerabilityRatingNormalizer.normalize()` omit unsupported values for `Models.Vulnerability.Rating.method` (via [#843])
This utilizes the new method `Spec.Protocol.supportsVulnerabilityRatingMethod()`.
* Namespace `Validation`
* Classes `{Json,JsonStrict,Xml}Validator` support _CycloneDX_ Specification-1.5 now ([#505] via [#843])
* Added
* Namespace `Enums`
* Enum `ComponentType` got new members ([#505] via [#843])
Expand All @@ -25,25 +31,27 @@ Added functionality regarding [_CycloneDX_ BOM-Link](https://cyclonedx.org/capab
New: `AdversaryModel`, `Attestation`, `CertificationReport`, `CodifiedInfrastructure`, `ComponentAnalysisReport`, `Configuration`, `DistributionIntake`, `DynamicAnalysisReport`, `Evidence`, `ExploitabilityStatement`, `Formulation`, `Log`, `MaturityReport`, `ModelCard`, `POAM`, `PentestReport`, `QualityMetrics`, `RiskAssessment`, `RuntimeAnalysisReport`, `SecurityContact`, `StaticAnalysisReport`, `ThreatModel`, `VulnerabilityAssertion`
* Enum `Vulnerability.RatingMethod` got new members ([#505] via [#843])
New: `CVSSv4`, `SSVC`
* Namespace `Models`
* New classes `BomLinkDocument` and `BomLinkDocument` to represent _CycloneDX_ BOM-Link (via [#843], [#856])
* New type `BomLink` to represent _CycloneDX_ BOM-Link (via [#843], [#856])
* Namespace `Spec`
* Enum `Version` got new member `v1dot5` to reflect _CycloneDX_ Specification-1.5 ([#505] via [#843])
* Constant `SpecVersionDict` got new entry to reflect _CycloneDX_ Specification-1.5 ([#505] via [#843])
* New constant `Spec1dot5` to reflect _CycloneDX_ Specification-1.5 ([#505] via [#843])
* Constants `Spec1dot{2,3,4}` got a new method `supportsVulnerabilityRatingMethod()` (via [#843])
* Interface `Protocol` has a new method `supportsVulnerabilityRatingMethod()` (via [#843])
* Namespace `Types`
* New types and predicates to reflect _CycloneDX_ BOM-Link (via [#843])
Type definitions: `BomLink`, `BomLinkDocument`, `BomLinkElement`
Predicates: `isBomLink()`, `isBomLinkDocument()`, `isBomLinkElement()`
* Misc
* Added functional and integration tests for _CycloneDX_ Specification-1.5 ([#505] via [#843])
* Added unit tests for _CycloneDX_ BOM-Link (via [#843], [#856])
* Fetched latest stable schema definition files for offline usage (via [#843])
* Improved internal documentation (via [#856])
* Build
* Use _Webpack_ `v5.88.0` now, was `v5.86.0` (via [#841])

[#505]: https://github.com/CycloneDX/cyclonedx-javascript-library/issues/505
[#841]: https://github.com/CycloneDX/cyclonedx-javascript-library/pull/841
[#843]: https://github.com/CycloneDX/cyclonedx-javascript-library/pull/843
[#856]: https://github.com/CycloneDX/cyclonedx-javascript-library/pull/856

## 2.1.0 -- 2023-06-10

Expand Down
91 changes: 91 additions & 0 deletions src/models/bomLink.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/*!
This file is part of CycloneDX JavaScript Library.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
SPDX-License-Identifier: Apache-2.0
Copyright (c) OWASP Foundation. All Rights Reserved.
*/

import type { Comparable } from '../_helpers/sortable'
import type { Stringable } from '../_helpers/stringable'

abstract class BomLinkBase implements Stringable, Comparable<Stringable> {
/* @ts-expect-error TS2564 */
#value: string

protected abstract _isValid (value: any): boolean

constructor (value: string) {
this.value = value
}

set value (value: string) {
if (!this._isValid(value)) {
throw new RangeError('invalid value')
}
this.#value = value
}

get value (): string {
return this.#value
}

compare (other: Stringable): number {
return this.toString().localeCompare(other.toString())
}

toString (): string {
return this.value
}
}

/**
* See [the docs](https://cyclonedx.org/capabilities/bomlink/)
*/
export class BomLinkDocument extends BomLinkBase {
/* regular expressions were taken from the CycloneDX schema definitions. */
static #pattern = /^urn:cdx:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\/[1-9][0-9]*$/

static isValid (value: any): boolean {
return typeof value === 'string' &&
BomLinkDocument.#pattern.test(value)
}

protected _isValid (value: any): boolean {
return BomLinkDocument.isValid(value)
}
}

/**
* See [the docs](https://cyclonedx.org/capabilities/bomlink/)
*/
export class BomLinkElement extends BomLinkBase {
/* regular expressions were taken from the CycloneDX schema definitions. */
static #pattern = /^urn:cdx:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\/[1-9][0-9]*#.+$/

static isValid (value: any): boolean {
return typeof value === 'string' &&
BomLinkElement.#pattern.test(value)
}

protected _isValid (value: any): boolean {
return BomLinkElement.isValid(value)
}
}

/**
* See [the docs](https://cyclonedx.org/capabilities/bomlink/)
* @see {@link isBomLink}
*/
export type BomLink = BomLinkDocument | BomLinkElement
7 changes: 5 additions & 2 deletions src/models/bomRef.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,21 @@ SPDX-License-Identifier: Apache-2.0
Copyright (c) OWASP Foundation. All Rights Reserved.
*/

import type { Comparable } from '../_helpers/sortable'
import type { Stringable } from '../_helpers/stringable'

/**
* Proxy for the BomRef.
* This way a `BomRef` gets unique by the in-memory-address of the object.
*/
export class BomRef {
export class BomRef implements Stringable, Comparable<Stringable> {
value?: string

constructor (value?: BomRef['value']) {
this.value = value
}

compare (other: BomRef): number {
compare (other: Stringable): number {
return this.toString().localeCompare(other.toString())
}

Expand Down
3 changes: 2 additions & 1 deletion src/models/externalReference.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,14 @@ Copyright (c) OWASP Foundation. All Rights Reserved.
import type { Comparable } from '../_helpers/sortable'
import { SortableComparables } from '../_helpers/sortable'
import type { ExternalReferenceType } from '../enums'
import type { BomLink } from './bomLink'

export interface OptionalExternalReferenceProperties {
comment?: ExternalReference['comment']
}

export class ExternalReference implements Comparable<ExternalReference> {
url: URL | string
url: URL | BomLink | string
type: ExternalReferenceType
comment?: string

Expand Down
1 change: 1 addition & 0 deletions src/models/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ Copyright (c) OWASP Foundation. All Rights Reserved.

export * from './attachment'
export * from './bom'
export * from './bomLink'
export * from './bomRef'
export * from './component'
export * from './externalReference'
Expand Down
5 changes: 3 additions & 2 deletions src/models/vulnerability/affect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,18 @@ Copyright (c) OWASP Foundation. All Rights Reserved.
import type { Comparable } from '../../_helpers/sortable'
import { SortableComparables } from '../../_helpers/sortable'
import type { AffectStatus } from '../../enums/vulnerability'
import type { BomLinkElement } from '../bomLink'
import type { BomRef } from '../bomRef'

export interface OptionalAffectProperties {
versions?: Affect['versions']
}

export class Affect implements Comparable<Affect> {
ref: BomRef
ref: BomRef | BomLinkElement
versions: AffectedVersionRepository

constructor (ref: BomRef, op: OptionalAffectProperties = {}) {
constructor (ref: Affect['ref'], op: OptionalAffectProperties = {}) {
this.ref = ref
this.versions = op.versions ?? new AffectedVersionRepository()
}
Expand Down
15 changes: 10 additions & 5 deletions src/serialize/json/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,11 @@ export namespace JsonSchema {
export namespace Normalized {

export type RefType = string
export type RefLinkType = RefType

export type BomLinkDocumentType = string
export type BomLinkElementType = string
export type BomLink = BomLinkDocumentType | BomLinkElementType

export interface Bom {
$schema?: string
Expand Down Expand Up @@ -183,7 +188,7 @@ export namespace Normalized {
}

export interface ExternalReference {
url: string
url: JsonSchema.IriReference | BomLink
type: Enums.ExternalReferenceType
comment?: string
}
Expand All @@ -200,8 +205,8 @@ export namespace Normalized {
}

export interface Dependency {
ref: RefType
dependsOn?: RefType[]
ref: RefLinkType
dependsOn?: RefLinkType[]
}

export interface Vulnerability {
Expand Down Expand Up @@ -248,7 +253,7 @@ export namespace Normalized {

export interface Advisory {
title?: string
url: string
url: JsonSchema.IriReference
}

export interface Credits {
Expand All @@ -264,7 +269,7 @@ export namespace Normalized {
}

export interface Affect {
ref: RefType
ref: RefLinkType | BomLinkElementType
versions?: AffectedVersion[]
}

Expand Down
62 changes: 0 additions & 62 deletions src/types/bomLink.ts

This file was deleted.

1 change: 0 additions & 1 deletion src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ SPDX-License-Identifier: Apache-2.0
Copyright (c) OWASP Foundation. All Rights Reserved.
*/

export * from './bomLink'
export * from './cpe'
export * from './cwe'
export * from './integer'
Expand Down
4 changes: 2 additions & 2 deletions src/types/integer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export function isInteger (value: any): value is Integer {
}

/**
* Integer greater than 0
* Integer greater than or equal to `0`
*
* @see {@link isNonNegativeInteger}
*/
Expand All @@ -41,7 +41,7 @@ export function isNonNegativeInteger (value: any): value is NonNegativeInteger {
}

/**
* Integer greater 0
* Integer greater `0`
*
* @see {@link isPositiveInteger}
*/
Expand Down
2 changes: 1 addition & 1 deletion tests/unit/Models.Bom.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ suite('Models.Bom', () => {
})

test('construct with preset properties', () => {
const version = Math.round(Math.random() * 1000)
const version = Math.max(1, Math.round(Math.random() * Number.MAX_SAFE_INTEGER))
const serialNumber = 'urn:uuid:12345678-4321-0987-6547-abcdef123456'
const metadata = new Metadata()
const components = new ComponentRepository()
Expand Down
Loading

0 comments on commit a6ef130

Please sign in to comment.