Skip to content

Commit 1061244

Browse files
feat(CSAF2.1): #366 add recommende test 6.1.46 - show not listed licenses in message
1 parent bf46908 commit 1061244

File tree

2 files changed

+62
-72
lines changed

2 files changed

+62
-72
lines changed

csaf_2_1/recommendedTests/recommendedTest_6_2_46.js

Lines changed: 30 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import Ajv from 'ajv/dist/jtd.js'
2-
import { parse } from 'license-expressions'
2+
import { parse, validate } from 'license-expressions'
33
import license_information from '../../lib/license/license_information.js'
44
import translations from '../../lib/language_specific_translation/translations.js'
55
import bcp47 from 'bcp47'
@@ -80,61 +80,67 @@ function isAboutCodeLicense(licenseRefToCheck) {
8080
* Recursively checks if a parsed license expression contains not listed licenses.
8181
*
8282
* @param {import('license-expressions').ParsedSpdxExpression} parsedExpression - The parsed license expression
83-
* @returns {boolean} True if the expression contains any license references, false otherwise
83+
* @returns {Array<string>} all not listed licenses
8484
*/
85-
function containsNotListedLicenses(parsedExpression) {
85+
function notListedLicenses(parsedExpression) {
86+
/** @type {Array<string>} */
87+
const deprecatedLicenses = []
8688
// If it's a LicenseRef type directly
8789
if ('licenseRef' in parsedExpression) {
88-
return !isAboutCodeLicense(parsedExpression.licenseRef)
90+
if (!isAboutCodeLicense(parsedExpression.licenseRef)) {
91+
deprecatedLicenses.push(parsedExpression.licenseRef)
92+
}
8993
}
9094

9195
if (
9296
'license' in parsedExpression &&
9397
!SPDX_LICENSE_KEYS.has(parsedExpression.license)
9498
) {
95-
return true
99+
deprecatedLicenses.push(parsedExpression.license)
96100
}
97101

98102
if (
99103
'exception' in parsedExpression &&
100104
parsedExpression.exception &&
101105
!SPDX_LICENSE_KEYS.has(parsedExpression.exception)
102106
) {
103-
return true
107+
deprecatedLicenses.push(parsedExpression.exception)
104108
}
105109

106110
// If it's a conjunction, check both sides
107111
if ('conjunction' in parsedExpression) {
108-
return (
109-
containsNotListedLicenses(parsedExpression.left) ||
110-
containsNotListedLicenses(parsedExpression.right)
111-
)
112+
deprecatedLicenses.push(...notListedLicenses(parsedExpression.left))
113+
deprecatedLicenses.push(...notListedLicenses(parsedExpression.right))
112114
}
113115

114116
// If it's a LicenseInfo type, it doesn't contain not listed licenses
115-
return false
117+
return deprecatedLicenses
116118
}
117119

118120
/**
119121
* Checks if a license expression string contains any not listed licenses.
120122
*
121123
* @param {string} licenseToCheck - The license expression to check
122-
* @returns {boolean} True if the license expression contains any document references, false otherwise
124+
* @returns {Array<string>} all not listed licenses
123125
*/
124-
function hasNotListedLicenses(licenseToCheck) {
126+
function allNotListedLicenses(licenseToCheck) {
125127
const parseResult = parse(licenseToCheck)
126-
return containsNotListedLicenses(parseResult)
128+
return notListedLicenses(parseResult)
127129
}
128130

129131
/**
130132
* check if the license_expression contains license identifiers or exceptions
131133
* that are not listed in the SPDX license list or Aboutcode's "ScanCode LicenseDB"
132134
*
133135
* @param {string} licenseToCheck - The license expression to check
134-
* @returns {boolean} True if the license has not listed licenses, false otherwise
136+
* @returns {Array<string>} all not listed licenses
135137
*/
136-
export function existsNotListedLicenses(licenseToCheck) {
137-
return !!licenseToCheck && hasNotListedLicenses(licenseToCheck)
138+
export function getNotListedLicenses(licenseToCheck) {
139+
if (!licenseToCheck || !validate(licenseToCheck).valid) {
140+
return []
141+
} else {
142+
return allNotListedLicenses(licenseToCheck)
143+
}
138144
}
139145

140146
/**
@@ -216,7 +222,8 @@ export function recommendedTest_6_2_46(doc) {
216222

217223
const licenseToCheck = doc.document.license_expression
218224
if (isLangSpecifiedAndNotEnglish(doc.document.lang)) {
219-
if (existsNotListedLicenses(licenseToCheck)) {
225+
const notListedLicenses = getNotListedLicenses(licenseToCheck)
226+
if (notListedLicenses.length > 0) {
220227
const notes = doc.document.notes
221228
if (
222229
!notes ||
@@ -225,9 +232,11 @@ export function recommendedTest_6_2_46(doc) {
225232
ctx.warnings.push({
226233
instancePath: '/document/notes',
227234
message:
228-
'The license_expression contains a license identifiers or exceptions that is not ' +
229-
'listed in Aboutcode or SPDX license list. Therefore exactly one note with ' +
230-
'title "License" and category "legal_disclaimer" must exist',
235+
`The license_expression contains contains the following license identifiers that ` +
236+
`are nor listed in Aboutcode or SPDX license list: ` +
237+
`"${notListedLicenses.join(', ')}". ` +
238+
`Therefore exactly one note with ` +
239+
`title "License" and category "legal_disclaimer" must exist`,
231240
})
232241
}
233242
}
Lines changed: 32 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import {
2-
existsNotListedLicenses,
3-
getLicenseInDocumentLang,
2+
getNotListedLicenses,
43
recommendedTest_6_2_46,
54
} from '../../csaf_2_1/recommendedTests/recommendedTest_6_2_46.js'
65
import { expect } from 'chai'
@@ -11,87 +10,69 @@ describe('recommendedTest_6_2_46', function () {
1110
assert.equal(recommendedTest_6_2_46({}).warnings.length, 0)
1211
})
1312

14-
it('only runs on valid language', function () {
15-
assert.equal(
16-
recommendedTest_6_2_46({
17-
document: { lang: '123', license_expression: 'MIT' },
18-
}).warnings.length,
19-
0
20-
)
21-
})
22-
23-
it('check get license in document lang', function () {
24-
expect(getLicenseInDocumentLang({ document: { lang: 'de' } })).to.eq(
25-
'Lizenz'
26-
)
27-
expect(getLicenseInDocumentLang({ document: { lang: 'es' } })).to.eq(
28-
undefined
29-
)
30-
expect(getLicenseInDocumentLang({ document: {} })).to.eq(undefined)
31-
})
32-
3313
it('check license expressions', function () {
34-
expect(existsNotListedLicenses('GPL-3.0+')).to.be.false
35-
expect(existsNotListedLicenses('GPL-3.0-only')).to.be.false
36-
expect(existsNotListedLicenses('MIT OR (Apache-2.0 AND 0BSD)')).to.be.false
37-
expect(existsNotListedLicenses('Invalid-license-expression')).to.be.true
38-
expect(existsNotListedLicenses('GPL-2.0 OR BSD-3-Clause')).to.be.false
39-
expect(existsNotListedLicenses('LGPL-2.1 OR BSD-3-Clause AND MIT')).to.be
40-
.false
41-
expect(existsNotListedLicenses('(MIT AND (LGPL-2.1+ AND BSD-3-Clause))')).to
42-
.be.false
14+
expect(getNotListedLicenses('GPL-3.0+')).to.eql([])
15+
expect(getNotListedLicenses('GPL-3.0-only')).to.be.eql([])
16+
expect(getNotListedLicenses('MIT OR (Apache-2.0 AND 0BSD)')).to.be.eql([])
17+
expect(getNotListedLicenses('Invalid-license-expression')).to.be.eql([])
18+
expect(getNotListedLicenses('GPL-2.0 OR BSD-3-Clause')).to.be.eql([])
19+
expect(getNotListedLicenses('LGPL-2.1 OR BSD-3-Clause AND MIT')).to.be.eql(
20+
[]
21+
)
22+
expect(
23+
getNotListedLicenses('(MIT AND (LGPL-2.1+ AND BSD-3-Clause))')
24+
).to.eql([])
4325
expect(
44-
existsNotListedLicenses('MIT OR Apache-2.0 WITH Autoconf-exception-2.0'),
26+
getNotListedLicenses('MIT OR Apache-2.0 WITH Autoconf-exception-2.0'),
4527
'Exception associated with unrelated license'
46-
).to.be.true
28+
).to.eql([])
4729
expect(
48-
existsNotListedLicenses('3dslicer-1.0'),
30+
getNotListedLicenses('3dslicer-1.0'),
4931
'SPDX License List matching guidelines'
50-
).to.be.false
32+
).to.eql([])
5133

5234
expect(
53-
existsNotListedLicenses('LicenseRef-www.example.com-no-work-pd'),
35+
getNotListedLicenses('LicenseRef-www.example.com-no-work-pd'),
5436
'Valid SPDX expression with License Ref'
55-
).to.be.true
37+
).to.eql(['LicenseRef-www.example.com-no-work-pd'])
5638

5739
expect(
58-
existsNotListedLicenses(
40+
getNotListedLicenses(
5941
'LicenseRef-www.example.com-no-work-pd OR BSD-3-Clause AND MIT'
6042
),
6143
'Valid SPDX expression with compound-expression and License Ref'
62-
).to.be.true
44+
).to.eql(['LicenseRef-www.example.com-no-work-pd'])
6345

64-
expect(existsNotListedLicenses('wxWindows'), 'Deprecated License').to.be
65-
.false
46+
expect(getNotListedLicenses('wxWindows'), 'Deprecated License').to.eql([])
6647

6748
expect(
68-
existsNotListedLicenses('DocumentRef-X:LicenseRef-Y AND MIT'),
69-
'DocumentRef in License with compound-expression '
70-
).to.be.true
49+
getNotListedLicenses('DocumentRef-X:LicenseRef-Y AND LicenseRef-X'),
50+
'DocumentRef in License with compound-expression'
51+
).to.eql(['LicenseRef-Y', 'LicenseRef-X'])
7152

7253
expect(
73-
existsNotListedLicenses(
54+
getNotListedLicenses(
7455
'DocumentRef-some-document-reference:LicenseRef-www.example.org-Example-CSAF-License-2.0'
7556
),
7657
'DocumentRef in License'
77-
).to.be.true
58+
).to.eql(['LicenseRef-www.example.org-Example-CSAF-License-2.0'])
7859

7960
expect(
80-
existsNotListedLicenses(
61+
getNotListedLicenses(
8162
'LicenseRef-www.example.org-Example-CSAF-License-3.0+'
8263
),
8364
'LicenseRef in License with trailing +'
84-
).to.be.true
65+
).to.eql([])
8566
expect(
86-
existsNotListedLicenses('LicenseRef-scancode-acroname-bdk'),
67+
getNotListedLicenses('LicenseRef-scancode-acroname-bdk'),
8768
'LicenseRef in with About Code Prefix and listed license'
88-
).to.be.false
69+
).to.eql([])
8970

9071
expect(
91-
existsNotListedLicenses(
72+
getNotListedLicenses(
9273
'LicenseRef-scancode-www.example.org-Example-CSAF-License-3.0'
9374
),
9475
'LicenseRef in with About Code Prefix and not listed license'
95-
).to.be.true
76+
).to.eql(['LicenseRef-scancode-www.example.org-Example-CSAF-License-3.0'])
9677
})
9778
})

0 commit comments

Comments
 (0)