Skip to content

Commit 956bbc9

Browse files
authored
models ComponentEvidence (#753)
--------- Signed-off-by: Jan Kowalleck <[email protected]>
1 parent e83cd5b commit 956bbc9

21 files changed

+433
-114
lines changed

HISTORY.md

+68-49
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ All notable changes to this project will be documented in this file.
2222
* Class `Models.SpdxLicense` was modified
2323
* Constructor no longer throws, when value is not eligible ([#530] via [#547])
2424
* Property `id` setter no longer throws, when value is not eligible ([#530] via [#547])
25-
* Interface `Spec.Protocol` now defines a new mandatory property `supportsVulnerabilities:boolean` (via [#722])
25+
* Interface `Spec.Protocol` now defines a new mandatory property `supportsComponentEvidence:boolean` (via [#753])
26+
* Interface `Spec.Protocol` now defines a new mandatory property `supportsVulnerabilities:boolean` (via [#722])
2627
* Removed deprecated symbols ([#747] via [#752])
2728
* Namespace `{Builders,Factories}.FromPackageJson` -> use `{Builders,Factories}.FromNodePackageJson` instead
2829
* Class `Models.HashRepository` -> use `Models.HashDictionary` instead
@@ -32,50 +33,64 @@ All notable changes to this project will be documented in this file.
3233
* Changed
3334
* Removed beta state from symbols `{Enums,Models}.Vulnerability.*` ([#164] via [#722])
3435
The structures are defined as stable now.
35-
* Class `Models.Vulnerability.Credits`
36+
* Class `Models.Attachment` was modified
37+
* Property `content` was widened to be any stringable, was `string` ([#516] via [#753])
38+
This enables the use of `Buffer` and other data-saving mechanisms.
39+
* Class `Models.Component` was modified
40+
* Property `copyright` was widened to be any stringable, was `string` ([#516] via [#753])
41+
This enables the use of `Buffer` and other data-saving mechanisms.
42+
* Class `Models.Vulnerability.Credits` was modified
3643
* Property `organizations` is no longer optional (via [#722])
37-
This collection(`Set`) will always exist, but might be empty.
44+
This collection(`Set`) will always exist, but might be empty.
45+
This is considered a non-breaking change, as the class was in _beta_ state.
3846
* Property `individuals` is no longer optional (via [#722])
39-
This collection(`Set`) will always exist, but might be empty.
47+
This collection(`Set`) will always exist, but might be empty.
48+
This is considered a non-breaking change, as the class was in _beta_ state.
4049
* Added
4150
* Serializers and `Bom`-Normalizers will take `Bom.vulnerabilities` into account ([#164] via [#722])
42-
* Namespace`Models.Vulnerability` was enhanced
43-
* Class `Advisory` was enhanced
44-
* New method `compare()` (via [#722])
45-
* Class `AdvisoryRepository` was enhanced
46-
* New method `sorted()` (via [#722])
47-
* New method `compare()` (via [#722])
48-
* Class `Affect` was enhanced
49-
* New method `compare()` (via [#722])
50-
* Class `AffectRepository` was enhanced
51-
* New method `sorted()` (via [#722])
52-
* New method `compare()` (via [#722])
53-
* Class `AffectedSingleVersion` was enhanced
54-
* New method `compare()` (via [#722])
55-
* Class `AffectedVersionRange` was enhanced
56-
* New method `compare()` (via [#722])
57-
* Class `AffectedVersionRepository` was enhanced
58-
* New method `sorted()` (via [#722])
59-
* New method `compare()` (via [#722])
60-
* Class `Rating` was enhanced
61-
* New method `compare()` (via [#722])
62-
* Class `RatingRepository` was enhanced
63-
* New method `sorted()` (via [#722])
64-
* New method `compare()` (via [#722])
65-
* class `Reference` was enhanced
66-
* New method `compare()` (via [#722])
67-
* Class `ReferenceRepository` was enhanced
68-
* New method `sorted()` (via [#722])
69-
* New method `compare()` (via [#722])
70-
* class `Source` was enhanced
71-
* New method `compare()` (via [#722])
72-
* class `Vulnerability` was enhanced
73-
* New method `compare()` (via [#722])
74-
* Class `VulnerabilityRepository` was enhanced
75-
* New method `sorted()` (via [#722])
76-
* New method `compare()` (via [#722])
77-
* Namespace `Serialize.{Json,Xml}.Normalize` was enhanced
51+
* Serializers and `Component`-Normalizers will take `Component.evidence` into account ([#516] via [#753])
52+
* Namespace `Models` was enhanced
53+
* Class `Component` was enhanced
54+
* New optional property `evidence` of type `Models.ComponentEvidence` ([#516] via [#753])
55+
* New Classes `ComponentEvidence` ([#516] via [#753])
56+
* Namespace`Vulnerability` was enhanced
57+
* Class `Advisory` was enhanced
58+
* New method `compare()` (via [#722])
59+
* Class `AdvisoryRepository` was enhanced
60+
* New method `sorted()` (via [#722])
61+
* New method `compare()` (via [#722])
62+
* Class `Affect` was enhanced
63+
* New method `compare()` (via [#722])
64+
* Class `AffectRepository` was enhanced
65+
* New method `sorted()` (via [#722])
66+
* New method `compare()` (via [#722])
67+
* Class `AffectedSingleVersion` was enhanced
68+
* New method `compare()` (via [#722])
69+
* Class `AffectedVersionRange` was enhanced
70+
* New method `compare()` (via [#722])
71+
* Class `AffectedVersionRepository` was enhanced
72+
* New method `sorted()` (via [#722])
73+
* New method `compare()` (via [#722])
74+
* Class `Rating` was enhanced
75+
* New method `compare()` (via [#722])
76+
* Class `RatingRepository` was enhanced
77+
* New method `sorted()` (via [#722])
78+
* New method `compare()` (via [#722])
79+
* class `Reference` was enhanced
80+
* New method `compare()` (via [#722])
81+
* Class `ReferenceRepository` was enhanced
82+
* New method `sorted()` (via [#722])
83+
* New method `compare()` (via [#722])
84+
* class `Source` was enhanced
85+
* New method `compare()` (via [#722])
86+
* class `Vulnerability` was enhanced
87+
* New method `compare()` (via [#722])
88+
* Class `VulnerabilityRepository` was enhanced
89+
* New method `sorted()` (via [#722])
90+
* New method `compare()` (via [#722])
91+
* Namespace `Serialize.{Json,Xml}.Normalize` was enhanced
7892
* Class `Factory` was enhanced
93+
* New Method `makeForComponentEvidence()` ([#516] via [#753])
7994
* New method `makeForVulnerability()` ([#164] via [#722])
8095
* New method `makeForVulnerabilitySource()` ([#164] via [#722])
8196
* New method `makeForVulnerabilityReference()` ([#164] via [#722])
@@ -85,19 +100,21 @@ All notable changes to this project will be documented in this file.
85100
* New method `makeForVulnerabilityAffect` ([#164] via [#722])
86101
* New method `makeForVulnerabilityAffectedVersion` ([#164] via [#722])
87102
* New method `makeForVulnerabilityAnalysis` ([#164] via [#722])
103+
* New class `ComponentEvidenceNormalizer` ([#516] via [#753])
88104
* Class `OrganizationalEntityNormalizer` was enhanced
89105
* New method `normalizeIterable()` (via [#722])
90-
* Class `VulnerabilityNormalizer` was added ([#164] via [#722])
91-
* Class `VulnerabilityAdvisoryNormalizer` was added ([#164] via [#722])
92-
* Class `VulnerabilityAffectNormalizer` was added ([#164] via [#722])
93-
* Class `VulnerabilityAffectedVersionNormalizer` was added ([#164] via [#722])
94-
* Class `VulnerabilityAnalysisNormalizer` was added ([#164] via [#722])
95-
* Class `VulnerabilityCreditsNormalizer` was added ([#164] via [#722])
96-
* Class `VulnerabilityRatingNormalizer` was added ([#164] via [#722])
97-
* Class `VulnerabilityReferenceNormalizer` was added ([#164] via [#722])
98-
* Class `VulnerabilitySourceNormalizer` was added ([#164] via [#722])
106+
* New class `VulnerabilityNormalizer` ([#164] via [#722])
107+
* New class `VulnerabilityAdvisoryNormalizer` ([#164] via [#722])
108+
* New class `VulnerabilityAffectNormalizer` ([#164] via [#722])
109+
* New class `VulnerabilityAffectedVersionNormalizer` ([#164] via [#722])
110+
* New class `VulnerabilityAnalysisNormalizer` ([#164] via [#722])
111+
* New class `VulnerabilityCreditsNormalizer` ([#164] via [#722])
112+
* New class `VulnerabilityRatingNormalizer` ([#164] via [#722])
113+
* New class `VulnerabilityReferenceNormalizer` ([#164] via [#722])
114+
* New class `VulnerabilitySourceNormalizer` ([#164] via [#722])
99115
* Namespace `Spec`
100116
* Const `Spec1dot{2,3,4}`
117+
* New Property `supportsComponentEvidence:boolean` (via [#753])
101118
* New Property `supportsVulnerabilities:boolean` (via [#722])
102119
* Namespace `Spdx`
103120
* New function `isValidSpdxLicenseExpression()` ([#271] via [#547])
@@ -106,11 +123,13 @@ All notable changes to this project will be documented in this file.
106123

107124
[#164]: https://github.com/CycloneDX/cyclonedx-javascript-library/issues/164
108125
[#271]: https://github.com/CycloneDX/cyclonedx-javascript-library/issues/271
126+
[#516]: https://github.com/CycloneDX/cyclonedx-javascript-library/issues/516
109127
[#530]: https://github.com/CycloneDX/cyclonedx-javascript-library/issues/530
110128
[#547]: https://github.com/CycloneDX/cyclonedx-javascript-library/pull/547
111129
[#722]: https://github.com/CycloneDX/cyclonedx-javascript-library/pull/722
112130
[#747]: https://github.com/CycloneDX/cyclonedx-javascript-library/issues/747
113131
[#752]: https://github.com/CycloneDX/cyclonedx-javascript-library/pull/752
132+
[#753]: https://github.com/CycloneDX/cyclonedx-javascript-library/pull/753
114133

115134
## 1.14.0 -- 2023-04-25
116135

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ written in _TypeScript_ and compiled for the target.
5151
* `Attachment`
5252
* `Bom`
5353
* `BomRef`, `BomRefRepository`
54-
* `Component`, `ComponentRepository`
54+
* `Component`, `ComponentRepository`, `ComponentEvidence`
5555
* `ExternalReference`, `ExternalReferenceRepository`
5656
* `Hash`, `HashContent`, `HashDictionary`
5757
* `LicenseExpression`, `NamedLicense`, `SpdxLicense`, `LicenseRepository`

src/models/attachment.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ SPDX-License-Identifier: Apache-2.0
1717
Copyright (c) OWASP Foundation. All Rights Reserved.
1818
*/
1919

20+
import type { Stringable } from '../_helpers/stringable'
2021
import type { AttachmentEncoding } from '../enums'
2122

2223
export interface OptionalAttachmentProperties {
@@ -26,7 +27,7 @@ export interface OptionalAttachmentProperties {
2627

2728
export class Attachment {
2829
contentType?: string
29-
content: string
30+
content: Stringable
3031
encoding?: AttachmentEncoding
3132

3233
constructor (content: Attachment['content'], op: OptionalAttachmentProperties = {}) {

src/models/component.ts

+21-2
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ Copyright (c) OWASP Foundation. All Rights Reserved.
2020
import type { PackageURL } from 'packageurl-js'
2121

2222
import type { Comparable } from '../_helpers/sortable'
23-
import { SortableComparables } from '../_helpers/sortable'
23+
import { SortableComparables, SortableStringables } from '../_helpers/sortable'
24+
import type { Stringable } from '../_helpers/stringable'
2425
import { treeIteratorSymbol } from '../_helpers/tree'
2526
import type { ComponentScope, ComponentType } from '../enums'
2627
import type { CPE } from '../types'
@@ -52,13 +53,14 @@ export interface OptionalComponentProperties {
5253
components?: Component['components']
5354
cpe?: Component['cpe']
5455
properties?: Component['properties']
56+
evidence?: Component['evidence']
5557
}
5658

5759
export class Component implements Comparable<Component> {
5860
type: ComponentType
5961
name: string
6062
author?: string
61-
copyright?: string
63+
copyright?: Stringable
6264
description?: string
6365
externalReferences: ExternalReferenceRepository
6466
group?: string
@@ -73,6 +75,7 @@ export class Component implements Comparable<Component> {
7375
dependencies: BomRefRepository
7476
components: ComponentRepository
7577
properties: PropertyRepository
78+
evidence?: ComponentEvidence
7679

7780
/** @see {@link bomRef} */
7881
readonly #bomRef: BomRef
@@ -104,6 +107,7 @@ export class Component implements Comparable<Component> {
104107
this.components = op.components ?? new ComponentRepository()
105108
this.cpe = op.cpe
106109
this.properties = op.properties ?? new PropertyRepository()
110+
this.evidence = op.evidence
107111
}
108112

109113
get bomRef (): BomRef {
@@ -152,3 +156,18 @@ export class ComponentRepository extends SortableComparables<Component> {
152156
}
153157
}
154158
}
159+
160+
export interface OptionalComponentEvidenceProperties {
161+
licenses?: ComponentEvidence['licenses']
162+
copyright?: ComponentEvidence['copyright']
163+
}
164+
165+
export class ComponentEvidence {
166+
licenses: LicenseRepository
167+
copyright: SortableStringables
168+
169+
constructor (op: OptionalComponentEvidenceProperties = {}) {
170+
this.licenses = op.licenses ?? new LicenseRepository()
171+
this.copyright = op.copyright ?? new SortableStringables()
172+
}
173+
}

src/serialize/json/normalize.ts

+69-40
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,10 @@ export class Factory {
5252
return new ComponentNormalizer(this)
5353
}
5454

55+
makeForComponentEvidence (): ComponentEvidenceNormalizer {
56+
return new ComponentEvidenceNormalizer(this)
57+
}
58+
5559
makeForTool (): ToolNormalizer {
5660
return new ToolNormalizer(this)
5761
}
@@ -308,46 +312,50 @@ export class OrganizationalEntityNormalizer extends BaseJsonNormalizer<Models.Or
308312
export class ComponentNormalizer extends BaseJsonNormalizer<Models.Component> {
309313
normalize (data: Models.Component, options: NormalizerOptions): Normalized.Component | undefined {
310314
const spec = this._factory.spec
315+
if (!spec.supportsComponentType(data.type)) {
316+
return undefined
317+
}
311318
const version: string = data.version ?? ''
312-
return spec.supportsComponentType(data.type)
313-
? {
314-
type: data.type,
315-
name: data.name,
316-
group: data.group || undefined,
317-
version: version.length > 0 || spec.requiresComponentVersion
318-
? version
319-
: undefined,
320-
'bom-ref': data.bomRef.value || undefined,
321-
supplier: data.supplier === undefined
322-
? undefined
323-
: this._factory.makeForOrganizationalEntity().normalize(data.supplier, options),
324-
author: data.author || undefined,
325-
publisher: data.publisher || undefined,
326-
description: data.description || undefined,
327-
scope: data.scope,
328-
hashes: data.hashes.size > 0
329-
? this._factory.makeForHash().normalizeIterable(data.hashes, options)
330-
: undefined,
331-
licenses: data.licenses.size > 0
332-
? this._factory.makeForLicense().normalizeIterable(data.licenses, options)
333-
: undefined,
334-
copyright: data.copyright || undefined,
335-
cpe: data.cpe || undefined,
336-
purl: data.purl?.toString(),
337-
swid: data.swid === undefined
338-
? undefined
339-
: this._factory.makeForSWID().normalize(data.swid, options),
340-
externalReferences: data.externalReferences.size > 0
341-
? this._factory.makeForExternalReference().normalizeIterable(data.externalReferences, options)
342-
: undefined,
343-
properties: spec.supportsProperties(data) && data.properties.size > 0
344-
? this._factory.makeForProperty().normalizeIterable(data.properties, options)
345-
: undefined,
346-
components: data.components.size > 0
347-
? this.normalizeIterable(data.components, options)
348-
: undefined
349-
}
350-
: undefined
319+
return {
320+
type: data.type,
321+
name: data.name,
322+
group: data.group || undefined,
323+
version: version.length > 0 || spec.requiresComponentVersion
324+
? version
325+
: undefined,
326+
'bom-ref': data.bomRef.value || undefined,
327+
supplier: data.supplier === undefined
328+
? undefined
329+
: this._factory.makeForOrganizationalEntity().normalize(data.supplier, options),
330+
author: data.author || undefined,
331+
publisher: data.publisher || undefined,
332+
description: data.description || undefined,
333+
scope: data.scope,
334+
hashes: data.hashes.size > 0
335+
? this._factory.makeForHash().normalizeIterable(data.hashes, options)
336+
: undefined,
337+
licenses: data.licenses.size > 0
338+
? this._factory.makeForLicense().normalizeIterable(data.licenses, options)
339+
: undefined,
340+
copyright: data.copyright?.toString() || undefined,
341+
cpe: data.cpe || undefined,
342+
purl: data.purl?.toString(),
343+
swid: data.swid === undefined
344+
? undefined
345+
: this._factory.makeForSWID().normalize(data.swid, options),
346+
externalReferences: data.externalReferences.size > 0
347+
? this._factory.makeForExternalReference().normalizeIterable(data.externalReferences, options)
348+
: undefined,
349+
properties: spec.supportsProperties(data) && data.properties.size > 0
350+
? this._factory.makeForProperty().normalizeIterable(data.properties, options)
351+
: undefined,
352+
components: data.components.size > 0
353+
? this.normalizeIterable(data.components, options)
354+
: undefined,
355+
evidence: spec.supportsComponentEvidence && data.evidence !== undefined
356+
? this._factory.makeForComponentEvidence().normalize(data.evidence, options)
357+
: undefined
358+
}
351359
}
352360

353361
normalizeIterable (data: SortableIterable<Models.Component>, options: NormalizerOptions): Normalized.Component[] {
@@ -361,6 +369,27 @@ export class ComponentNormalizer extends BaseJsonNormalizer<Models.Component> {
361369
}
362370
}
363371

372+
export class ComponentEvidenceNormalizer extends BaseJsonNormalizer<Models.ComponentEvidence> {
373+
normalize (data: Models.ComponentEvidence, options: NormalizerOptions): Normalized.ComponentEvidence {
374+
return {
375+
licenses: data.licenses.size > 0
376+
? this._factory.makeForLicense().normalizeIterable(data.licenses, options)
377+
: undefined,
378+
copyright: data.copyright.size > 0
379+
? (
380+
options.sortLists
381+
? data.copyright.sorted().map(this.#normalizeCopyright)
382+
: Array.from(data.copyright, this.#normalizeCopyright)
383+
)
384+
: undefined
385+
}
386+
}
387+
388+
#normalizeCopyright (c: Stringable): Normalized.Copyright {
389+
return { text: c.toString() }
390+
}
391+
}
392+
364393
export class LicenseNormalizer extends BaseJsonNormalizer<Models.License> {
365394
normalize (data: Models.License, options: NormalizerOptions): Normalized.License {
366395
switch (true) {
@@ -482,7 +511,7 @@ export class ExternalReferenceNormalizer extends BaseJsonNormalizer<Models.Exter
482511
export class AttachmentNormalizer extends BaseJsonNormalizer<Models.Attachment> {
483512
normalize (data: Models.Attachment, options: NormalizerOptions): Normalized.Attachment {
484513
return {
485-
content: data.content,
514+
content: data.content.toString(),
486515
contentType: data.contentType || undefined,
487516
encoding: data.encoding
488517
}

0 commit comments

Comments
 (0)