Skip to content

Commit 2bb7604

Browse files
committed
feat: Support properties on license
Signed-off-by: Peter Schuster <p.schuster@pilz.de>
1 parent 69ac857 commit 2bb7604

19 files changed

Lines changed: 357 additions & 27 deletions

src/models/license.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import type { Sortable } from '../_helpers/sortable'
2121
import type { LicenseAcknowledgement } from '../enums/licenseAcknowledgement'
2222
import type { SpdxId } from '../spdx'
2323
import type { Attachment } from './attachment'
24+
import { PropertyRepository } from './property'
2425

2526
/**
2627
* (SPDX) License Expression.
@@ -64,11 +65,13 @@ class DisjunctiveLicenseBase {
6465
acknowledgement?: LicenseAcknowledgement
6566
text?: Attachment
6667
#url?: URL | string
68+
properties: PropertyRepository
6769

6870
constructor (op: OptionalDisjunctiveLicenseProperties = {}) {
6971
this.acknowledgement = op.acknowledgement
7072
this.text = op.text
7173
this.url = op.url
74+
this.properties = op.properties ?? new PropertyRepository()
7275
}
7376

7477
get url (): URL | string | undefined {
@@ -86,6 +89,7 @@ interface OptionalDisjunctiveLicenseProperties {
8689
acknowledgement?: DisjunctiveLicenseBase['acknowledgement']
8790
text?: DisjunctiveLicenseBase['text']
8891
url?: DisjunctiveLicenseBase['url']
92+
properties?: DisjunctiveLicenseBase['properties']
8993
}
9094

9195
export interface OptionalNamedLicenseProperties extends OptionalDisjunctiveLicenseProperties {}

src/serialize/json/normalize.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -529,36 +529,44 @@ export class LicenseNormalizer extends BaseJsonNormalizer<Models.License> {
529529
}
530530

531531
#normalizeNamedLicense (data: Models.NamedLicense, options: NormalizerOptions): Normalized.NamedLicense {
532+
const spec = this._factory.spec
532533
const url = escapeUri(data.url?.toString())
533534
return {
534535
license: {
535536
name: data.name,
536-
acknowledgement: this._factory.spec.supportsLicenseAcknowledgement
537+
acknowledgement: spec.supportsLicenseAcknowledgement
537538
? data.acknowledgement
538539
: undefined,
539540
text: data.text === undefined
540541
? undefined
541542
: this._factory.makeForAttachment().normalize(data.text, options),
542543
url: JsonSchema.isIriReference(url)
543544
? url
545+
: undefined,
546+
properties: spec.supportsProperties(data) && data.properties.size > 0
547+
? this._factory.makeForProperty().normalizeIterable(data.properties, options)
544548
: undefined
545549
}
546550
}
547551
}
548552

549553
#normalizeSpdxLicense (data: Models.SpdxLicense, options: NormalizerOptions): Normalized.SpdxLicense {
554+
const spec = this._factory.spec
550555
const url = escapeUri(data.url?.toString())
551556
return {
552557
license: {
553558
id: data.id,
554-
acknowledgement: this._factory.spec.supportsLicenseAcknowledgement
559+
acknowledgement: spec.supportsLicenseAcknowledgement
555560
? data.acknowledgement
556561
: undefined,
557562
text: data.text === undefined
558563
? undefined
559564
: this._factory.makeForAttachment().normalize(data.text, options),
560565
url: JsonSchema.isIriReference(url)
561566
? url
567+
: undefined,
568+
properties: spec.supportsProperties(data) && data.properties.size > 0
569+
? this._factory.makeForProperty().normalizeIterable(data.properties, options)
562570
: undefined
563571
}
564572
}

src/serialize/json/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,7 @@ export namespace Normalized {
196196
acknowledgement?: Enums.LicenseAcknowledgement
197197
text?: Attachment
198198
url?: string
199+
properties?: Property[]
199200
}
200201
}
201202

@@ -206,6 +207,7 @@ export namespace Normalized {
206207
acknowledgement?: Enums.LicenseAcknowledgement
207208
text?: Attachment
208209
url?: string
210+
properties?: Property[]
209211
}
210212
}
211213

src/serialize/xml/normalize.ts

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -699,12 +699,20 @@ export class LicenseNormalizer extends BaseXmlNormalizer<Models.License> {
699699
}
700700

701701
#normalizeNamedLicense (data: Models.NamedLicense, options: NormalizerOptions): SimpleXml.Element {
702-
const url = escapeUri(data.url?.toString())
702+
const spec = this._factory.spec
703+
const url = escapeUri(data.url?.toString())
704+
const properties: SimpleXml.Element | undefined = spec.supportsProperties(data) && data.properties.size > 0
705+
? {
706+
type: 'element',
707+
name: 'properties',
708+
children: this._factory.makeForProperty().normalizeIterable(data.properties, options, 'property')
709+
}
710+
: undefined
703711
return {
704712
type: 'element',
705713
name: 'license',
706714
attributes: {
707-
acknowledgement: this._factory.spec.supportsLicenseAcknowledgement
715+
acknowledgement: spec.supportsLicenseAcknowledgement
708716
? data.acknowledgement
709717
: undefined
710718
},
@@ -715,18 +723,27 @@ export class LicenseNormalizer extends BaseXmlNormalizer<Models.License> {
715723
: this._factory.makeForAttachment().normalize(data.text, options, 'text'),
716724
XmlSchema.isAnyURI(url)
717725
? makeTextElement(url, 'url')
718-
: undefined
726+
: undefined,
727+
properties
719728
].filter(isNotUndefined)
720729
}
721730
}
722731

723732
#normalizeSpdxLicense (data: Models.SpdxLicense, options: NormalizerOptions): SimpleXml.Element {
724-
const url = escapeUri(data.url?.toString())
733+
const spec = this._factory.spec
734+
const url = escapeUri(data.url?.toString())
735+
const properties: SimpleXml.Element | undefined = spec.supportsProperties(data) && data.properties.size > 0
736+
? {
737+
type: 'element',
738+
name: 'properties',
739+
children: this._factory.makeForProperty().normalizeIterable(data.properties, options, 'property')
740+
}
741+
: undefined
725742
return {
726743
type: 'element',
727744
name: 'license',
728745
attributes: {
729-
acknowledgement: this._factory.spec.supportsLicenseAcknowledgement
746+
acknowledgement: spec.supportsLicenseAcknowledgement
730747
? data.acknowledgement
731748
: undefined
732749
},
@@ -737,7 +754,8 @@ export class LicenseNormalizer extends BaseXmlNormalizer<Models.License> {
737754
: this._factory.makeForAttachment().normalize(data.text, options, 'text'),
738755
XmlSchema.isAnyURI(url)
739756
? makeTextElement(url, 'url')
740-
: undefined
757+
: undefined,
758+
properties
741759
].filter(isNotUndefined)
742760
}
743761
}

src/spec/_protocol.ts

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ Copyright (c) OWASP Foundation. All Rights Reserved.
1818
*/
1919

2020
import type { ComponentType, ExternalReferenceType, HashAlgorithm, Vulnerability } from '../enums'
21-
import type { HashContent } from '../models'
21+
import { type HashContent, NamedLicense, SpdxLicense } from '../models'
2222
import type { Format, Version } from './enums'
2323

2424
/**
@@ -79,6 +79,7 @@ export class _Spec implements _SpecProtocol {
7979
readonly #supportsLicenseAcknowledgement: boolean
8080
readonly #supportsServices: boolean
8181
readonly #supportsToolsComponentsServices: boolean
82+
readonly #supportsLicenseProperties: boolean
8283

8384
/* eslint-disable-next-line @typescript-eslint/max-params -- architectural decision */
8485
constructor (
@@ -101,7 +102,8 @@ export class _Spec implements _SpecProtocol {
101102
supportsExternalReferenceHashes: boolean,
102103
supportsLicenseAcknowledgement: boolean,
103104
supportsServices: boolean,
104-
supportsToolsComponentsServices: boolean
105+
supportsToolsComponentsServices: boolean,
106+
supportsLicenseProperties: boolean
105107
) {
106108
this.#version = version
107109
this.#formats = new Set(formats)
@@ -123,6 +125,7 @@ export class _Spec implements _SpecProtocol {
123125
this.#supportsLicenseAcknowledgement = supportsLicenseAcknowledgement
124126
this.#supportsServices = supportsServices
125127
this.#supportsToolsComponentsServices = supportsToolsComponentsServices
128+
this.#supportsLicenseProperties = supportsLicenseProperties
126129
}
127130

128131
get version (): Version {
@@ -166,9 +169,13 @@ export class _Spec implements _SpecProtocol {
166169
return this.#requiresComponentVersion
167170
}
168171

169-
supportsProperties (): boolean {
170-
// currently a global allow/deny -- might work based on input, in the future
171-
return this.#supportsProperties
172+
supportsProperties (model: any): boolean {
173+
switch (true) {
174+
case model instanceof NamedLicense || model instanceof SpdxLicense:
175+
return this.#supportsLicenseProperties
176+
default:
177+
return this.#supportsProperties
178+
}
172179
}
173180

174181
get supportsVulnerabilities (): boolean {

src/spec/consts.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ export const Spec1dot2: Readonly<_SpecProtocol> = Object.freeze(new _Spec(
8989
false,
9090
false,
9191
true,
92+
false,
9293
false
9394
))
9495

@@ -154,6 +155,7 @@ export const Spec1dot3: Readonly<_SpecProtocol> = Object.freeze(new _Spec(
154155
true,
155156
false,
156157
true,
158+
false,
157159
false
158160
))
159161

@@ -226,6 +228,7 @@ export const Spec1dot4: Readonly<_SpecProtocol> = Object.freeze(new _Spec(
226228
true,
227229
false,
228230
true,
231+
false,
229232
false
230233
))
231234

@@ -327,6 +330,7 @@ export const Spec1dot5: Readonly<_SpecProtocol> = Object.freeze(new _Spec(
327330
true,
328331
false,
329332
true,
333+
true,
330334
true
331335
))
332336

@@ -433,6 +437,7 @@ export const Spec1dot6: Readonly<_SpecProtocol> = Object.freeze(new _Spec(
433437
true,
434438
true,
435439
true,
440+
true,
436441
true
437442
))
438443

@@ -547,6 +552,7 @@ export const Spec1dot7: Readonly<_SpecProtocol> = Object.freeze(new _Spec(
547552
true,
548553
true,
549554
true,
555+
true,
550556
true
551557
))
552558

tests/_data/models.js

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,11 @@ function createComplexStructure () {
158158
contentType: 'text/plain',
159159
encoding: Enums.AttachmentEncoding.Base64
160160
}),
161-
url: 'https://localhost/license'
161+
url: 'https://localhost/license',
162+
properties: new Models.PropertyRepository([
163+
new Models.Property('a', 'b'),
164+
new Models.Property('primaryLicense', 'true')
165+
])
162166
}))
163167
component.licenses.add((function (license) {
164168
license.text = new Models.Attachment('TUlUIExpY2Vuc2UKLi4uClRIRSBTT0ZUV0FSRSBJUyBQUk9WSURFRCAiQVMgSVMiLi4u')
@@ -167,7 +171,12 @@ function createComplexStructure () {
167171
license.url = new URL('https://spdx.org/licenses/MIT.html')
168172
license.acknowledgement = Enums.LicenseAcknowledgement.Declared
169173
return license
170-
})(new Models.SpdxLicense('MIT')))
174+
})(new Models.SpdxLicense('MIT', {
175+
properties: new Models.PropertyRepository([
176+
new Models.Property('c', 'd'),
177+
new Models.Property('primaryLicense', 'false')
178+
])
179+
})))
171180
component.publisher = 'the publisher'
172181
component.purl = new PackageURL('npm', 'acme', 'dummy-component', '1337-beta', undefined, undefined)
173182
component.scope = Enums.ComponentScope.Required

tests/_data/normalizeResults/json_sortedLists_spec1.5.json

Lines changed: 22 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/_data/normalizeResults/json_sortedLists_spec1.6.json

Lines changed: 22 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/_data/normalizeResults/json_sortedLists_spec1.7.json

Lines changed: 22 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)