Skip to content

Commit 41f1241

Browse files
feat(CSAF2.1): #199 add informative test 6.3.17
1 parent 908c3ae commit 41f1241

File tree

9 files changed

+8847
-1
lines changed

9 files changed

+8847
-1
lines changed

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -480,6 +480,7 @@ export const informativeTest_6_3_9: DocumentTest
480480
export const informativeTest_6_3_10: DocumentTest
481481
export const informativeTest_6_3_11: DocumentTest
482482
export const informativeTest_6_3_12: DocumentTest
483+
export const informativeTest_6_3_17: DocumentTest
483484
```
484485
485486
[(back to top)](#bsi-csaf-validator-lib)
@@ -576,5 +577,8 @@ For the complete list of dependencies please take a look at [package.json](https
576577
- [undici](https://undici.nodejs.org)
577578
- [@js-joda/core](https://js-joda.github.io/js-joda/)
578579
- [@js-joda/timezone](https://js-joda.github.io/js-joda/)
580+
- [aboutcode licenses](https://scancode-licensedb.aboutcode.org/index.json)
581+
- [SPDX licenses](https://raw.githubusercontent.com/spdx/license-list-data/refs/heads/main/json/licenses.json)
582+
- [license-expressions](https://github.com/lkoskela/license-expressions)
579583

580584
[(back to top)](#bsi-csaf-validator-lib)

csaf_2_1/informativeTests.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,4 @@ export { informativeTest_6_3_1 } from './informativeTests/informativeTest_6_3_1.
1212
export { informativeTest_6_3_2 } from './informativeTests/informativeTest_6_3_2.js'
1313
export { informativeTest_6_3_4 } from './informativeTests/informativeTest_6_3_4.js'
1414
export { informativeTest_6_3_12 } from './informativeTests/informativeTest_6_3_12.js'
15+
export { informativeTest_6_3_17 } from './informativeTests/informativeTest_6_3_17.js'
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
import Ajv from 'ajv/dist/jtd.js'
2+
3+
import license_information from '../../lib/license/license_information.js'
4+
import { validate, parse } from 'license-expressions'
5+
6+
const ajv = new Ajv()
7+
8+
const CONSIDERED_LICENSE_KEYS = new Set(
9+
license_information.licenses
10+
.filter((license) => !license.deprecated)
11+
.map((license) => license.license_key)
12+
)
13+
14+
const inputSchema = /** @type {const} */ ({
15+
additionalProperties: true,
16+
properties: {
17+
document: {
18+
additionalProperties: true,
19+
properties: {
20+
license_expression: {
21+
type: 'string',
22+
},
23+
},
24+
},
25+
},
26+
})
27+
28+
const validateInput = ajv.compile(inputSchema)
29+
30+
/**
31+
* Recursively checks if a parsed license expression contains any license references.
32+
*
33+
* @param {import('license-expressions').ParsedSpdxExpression} parsedExpression - The parsed license expression
34+
* @returns {boolean} True if the expression contains any license references, false otherwise
35+
*/
36+
function containsLicenseRef(parsedExpression) {
37+
// If it's a LicenseRef type directly
38+
if ('licenseRef' in parsedExpression) {
39+
return true
40+
}
41+
42+
// If it's a conjunction, check both sides
43+
if ('conjunction' in parsedExpression) {
44+
return (
45+
containsLicenseRef(parsedExpression.left) ||
46+
containsLicenseRef(parsedExpression.right)
47+
)
48+
}
49+
50+
// If it's a LicenseInfo type, it doesn't contain a license reference
51+
return false
52+
}
53+
54+
/**
55+
* Checks if a license expression contains any license references.
56+
*
57+
* @param {string} licenseToCheck - The license expression to check
58+
* @returns {boolean} True if the license expression contains any license references, false otherwise
59+
*/
60+
export function hasLicenseRef(licenseToCheck) {
61+
const parseResult = parse(licenseToCheck)
62+
return containsLicenseRef(parseResult)
63+
}
64+
65+
/**
66+
* Checks if a license is valid according to SPDX or AboutCode standards.
67+
*
68+
* @param {string} licenseToCheck - The license expression to check
69+
* @returns {boolean} True if the license is valid, false otherwise
70+
*/
71+
export function checkLicense(licenseToCheck) {
72+
if (!licenseToCheck) {
73+
return false
74+
}
75+
76+
// First do a simple check with aboutcode and spdx license ids
77+
// Then check whether the license is a valid SPDX license expression
78+
// Finally check if it contains any license references
79+
return (
80+
(CONSIDERED_LICENSE_KEYS.has(licenseToCheck) ||
81+
validate(licenseToCheck).valid) &&
82+
!hasLicenseRef(licenseToCheck)
83+
)
84+
}
85+
86+
/**
87+
* It MUST be tested that the all license identifiers and exceptions are listed either
88+
* in the official SPDX license identifier list or AboutCode's "ScanCode LicenseDB".
89+
* @param {unknown} doc
90+
* @returns
91+
*/
92+
export function informativeTest_6_3_17(doc) {
93+
const ctx = {
94+
infos: /** @type {Array<{ message: string; instancePath: string }>} */ ([]),
95+
}
96+
97+
if (!validateInput(doc)) {
98+
return ctx
99+
}
100+
101+
const licenseToCheck = doc.document.license_expression
102+
103+
if (!checkLicense(licenseToCheck)) {
104+
ctx.infos.push({
105+
instancePath: '/document/license_expression',
106+
message: `Invalid license expression: '${licenseToCheck}'`,
107+
})
108+
}
109+
110+
return ctx
111+
}

0 commit comments

Comments
 (0)