From badf1bbddef362c52e6f01dddc0e0c467f0779d9 Mon Sep 17 00:00:00 2001 From: chirschenberger Date: Wed, 21 May 2025 10:23:24 +0200 Subject: [PATCH 1/6] fix: add optional test 6.2.37 --- .../recommendedTests/optionalTest_6_2_37.js | 72 +++++++++++++++++++ tests/csaf_2_1/oasis.js | 1 - tests/csaf_2_1/optionalTest_6_2_37.js | 11 +++ 3 files changed, 83 insertions(+), 1 deletion(-) create mode 100644 csaf_2_1/recommendedTests/optionalTest_6_2_37.js create mode 100644 tests/csaf_2_1/optionalTest_6_2_37.js diff --git a/csaf_2_1/recommendedTests/optionalTest_6_2_37.js b/csaf_2_1/recommendedTests/optionalTest_6_2_37.js new file mode 100644 index 00000000..8495f8f1 --- /dev/null +++ b/csaf_2_1/recommendedTests/optionalTest_6_2_37.js @@ -0,0 +1,72 @@ +import Ajv from 'ajv/dist/jtd.js' + +const ajv = new Ajv() + +const inputSchema = /** @type {const} */ ({ + additionalProperties: true, + properties: { + vulnerabilities: { + elements: { + additionalProperties: true, + properties: { + metrics: { + elements: { + additionalProperties: true, + properties: { + content: { + additionalProperties: true, + properties: { + ssvc_v1: { + additionalProperties: true, + properties: { + role: { + type: 'string', + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, +}) + +const validate = ajv.compile(inputSchema) + +/** + * This implements the optional test 6.2.37 of the CSAF 2.1 standard. + * + * @param {any} doc + */ +export function optionalTest_6_2_37(doc) { + /** @type {Array<{ message: string; instancePath: string }>} */ + const warnings = [] + const context = { warnings } + + if (!validate(doc)) { + return context + } + + /* + * Please note that this list can change + * */ + const registeredSsvcRoles = ['Supplier', 'Deployer', 'Coordinator'] + + doc.vulnerabilities?.forEach((vulnerability, vulnerabilityIndex) => { + vulnerability.metrics.forEach((metric, metricIndex) => { + const role = metric.content.ssvc_v1.role + if (!registeredSsvcRoles.includes(role)) { + context.warnings.push({ + message: `The used role "${role}" is not a registered role`, + instancePath: `/vulnerabilities/${vulnerabilityIndex}/metrics/${metricIndex}/content/ssvc_v1/role`, + }) + } + }) + }) + + return context +} diff --git a/tests/csaf_2_1/oasis.js b/tests/csaf_2_1/oasis.js index 31ce644c..68f54a9d 100644 --- a/tests/csaf_2_1/oasis.js +++ b/tests/csaf_2_1/oasis.js @@ -55,7 +55,6 @@ const excluded = [ '6.2.34', '6.2.35', '6.2.36', - '6.2.37', '6.2.39.1', '6.2.39.2', '6.2.39.3', diff --git a/tests/csaf_2_1/optionalTest_6_2_37.js b/tests/csaf_2_1/optionalTest_6_2_37.js new file mode 100644 index 00000000..ec80867a --- /dev/null +++ b/tests/csaf_2_1/optionalTest_6_2_37.js @@ -0,0 +1,11 @@ +import assert from 'node:assert' +import { optionalTest_6_2_37 } from '../../csaf_2_1/optionalTests.js' + +describe('optionalTest_6_2_37', function () { + it('only runs on relevant documents', function () { + assert.equal( + optionalTest_6_2_37({ vulnerabilities: 'mydoc' }).warnings.length, + 0 + ) + }) +}) From 3013838821294a6723a9e2224ea3e6a607af5268 Mon Sep 17 00:00:00 2001 From: chirschenberger Date: Wed, 11 Jun 2025 17:30:46 +0200 Subject: [PATCH 2/6] refactor: rename optional test 6.2.37 to recommended test --- csaf_2_1/recommendedTests.js | 1 + .../{optionalTest_6_2_37.js => recommendedTest_6_2_37.js} | 4 ++-- tests/csaf_2_1/optionalTest_6_2_37.js | 6 +++--- 3 files changed, 6 insertions(+), 5 deletions(-) rename csaf_2_1/recommendedTests/{optionalTest_6_2_37.js => recommendedTest_6_2_37.js} (93%) diff --git a/csaf_2_1/recommendedTests.js b/csaf_2_1/recommendedTests.js index aeb25c42..25e477bb 100644 --- a/csaf_2_1/recommendedTests.js +++ b/csaf_2_1/recommendedTests.js @@ -30,4 +30,5 @@ export { recommendedTest_6_2_22 } from './recommendedTests/recommendedTest_6_2_2 export { recommendedTest_6_2_27 } from './recommendedTests/recommendedTest_6_2_27.js' export { recommendedTest_6_2_28 } from './recommendedTests/recommendedTest_6_2_28.js' export { recommendedTest_6_2_29 } from './recommendedTests/recommendedTest_6_2_29.js' +export { recommendedTest_6_2_37 } from './recommendedTests/recommendedTest_6_2_37.js' export { recommendedTest_6_2_38 } from './recommendedTests/recommendedTest_6_2_38.js' diff --git a/csaf_2_1/recommendedTests/optionalTest_6_2_37.js b/csaf_2_1/recommendedTests/recommendedTest_6_2_37.js similarity index 93% rename from csaf_2_1/recommendedTests/optionalTest_6_2_37.js rename to csaf_2_1/recommendedTests/recommendedTest_6_2_37.js index 8495f8f1..dcfe1591 100644 --- a/csaf_2_1/recommendedTests/optionalTest_6_2_37.js +++ b/csaf_2_1/recommendedTests/recommendedTest_6_2_37.js @@ -38,11 +38,11 @@ const inputSchema = /** @type {const} */ ({ const validate = ajv.compile(inputSchema) /** - * This implements the optional test 6.2.37 of the CSAF 2.1 standard. + * This implements the recommended test 6.2.37 of the CSAF 2.1 standard. * * @param {any} doc */ -export function optionalTest_6_2_37(doc) { +export function recommendedTest_6_2_37(doc) { /** @type {Array<{ message: string; instancePath: string }>} */ const warnings = [] const context = { warnings } diff --git a/tests/csaf_2_1/optionalTest_6_2_37.js b/tests/csaf_2_1/optionalTest_6_2_37.js index ec80867a..76cdfa5f 100644 --- a/tests/csaf_2_1/optionalTest_6_2_37.js +++ b/tests/csaf_2_1/optionalTest_6_2_37.js @@ -1,10 +1,10 @@ import assert from 'node:assert' -import { optionalTest_6_2_37 } from '../../csaf_2_1/optionalTests.js' +import { recommendedTest_6_2_37 } from '../../csaf_2_1/recommendedTests.js' -describe('optionalTest_6_2_37', function () { +describe('recommendedTest_6_2_37', function () { it('only runs on relevant documents', function () { assert.equal( - optionalTest_6_2_37({ vulnerabilities: 'mydoc' }).warnings.length, + recommendedTest_6_2_37({ vulnerabilities: 'mydoc' }).warnings.length, 0 ) }) From f1aba1d531fa3f9d564985608d54821cd6573fa1 Mon Sep 17 00:00:00 2001 From: chirschenberger Date: Thu, 12 Jun 2025 12:37:30 +0200 Subject: [PATCH 3/6] refactor: rename optional test 6.2.37 to recommended test --- .../{optionalTest_6_2_37.js => recommendedTest_6_2_37.js} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/csaf_2_1/{optionalTest_6_2_37.js => recommendedTest_6_2_37.js} (100%) diff --git a/tests/csaf_2_1/optionalTest_6_2_37.js b/tests/csaf_2_1/recommendedTest_6_2_37.js similarity index 100% rename from tests/csaf_2_1/optionalTest_6_2_37.js rename to tests/csaf_2_1/recommendedTest_6_2_37.js From ec19cd2b39dbb8cebdd559135c7676225bca032c Mon Sep 17 00:00:00 2001 From: chirschenberger Date: Fri, 18 Jul 2025 11:11:51 +0200 Subject: [PATCH 4/6] feat: change some properties to optionalProperties --- .../recommendedTests/recommendedTest_6_2_37.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/csaf_2_1/recommendedTests/recommendedTest_6_2_37.js b/csaf_2_1/recommendedTests/recommendedTest_6_2_37.js index dcfe1591..6cd15ab3 100644 --- a/csaf_2_1/recommendedTests/recommendedTest_6_2_37.js +++ b/csaf_2_1/recommendedTests/recommendedTest_6_2_37.js @@ -8,17 +8,17 @@ const inputSchema = /** @type {const} */ ({ vulnerabilities: { elements: { additionalProperties: true, - properties: { + optionalProperties: { metrics: { elements: { additionalProperties: true, - properties: { + optionalProperties: { content: { additionalProperties: true, - properties: { + optionalProperties: { ssvc_v1: { additionalProperties: true, - properties: { + optionalProperties: { role: { type: 'string', }, @@ -57,9 +57,9 @@ export function recommendedTest_6_2_37(doc) { const registeredSsvcRoles = ['Supplier', 'Deployer', 'Coordinator'] doc.vulnerabilities?.forEach((vulnerability, vulnerabilityIndex) => { - vulnerability.metrics.forEach((metric, metricIndex) => { - const role = metric.content.ssvc_v1.role - if (!registeredSsvcRoles.includes(role)) { + vulnerability.metrics?.forEach((metric, metricIndex) => { + const role = metric.content?.ssvc_v1?.role + if (role !== undefined && !registeredSsvcRoles.includes(role)) { context.warnings.push({ message: `The used role "${role}" is not a registered role`, instancePath: `/vulnerabilities/${vulnerabilityIndex}/metrics/${metricIndex}/content/ssvc_v1/role`, From f3b8605c7b1b1402b0f4773cc8e535955b9e9106 Mon Sep 17 00:00:00 2001 From: chirschenberger Date: Fri, 18 Jul 2025 11:12:25 +0200 Subject: [PATCH 5/6] docs: update Readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ebb45f8d..928176fa 100644 --- a/README.md +++ b/README.md @@ -357,7 +357,6 @@ The following tests are not yet implemented and therefore missing: - Recommended Test 6.2.34 - Recommended Test 6.2.35 - Recommended Test 6.2.36 -- Recommended Test 6.2.37 - Recommended Test 6.2.38 - Recommended Test 6.2.39 - Recommended Test 6.2.40 @@ -462,6 +461,7 @@ export const recommendedTest_6_2_16: DocumentTest export const recommendedTest_6_2_17: DocumentTest export const recommendedTest_6_2_18: DocumentTest export const recommendedTest_6_2_22: DocumentTest +export const recommendedTest_6_2_37: DocumentTest ``` [(back to top)](#bsi-csaf-validator-lib) From 7daecf01dfbdfbb1f1864851f0e3644254aa39d0 Mon Sep 17 00:00:00 2001 From: chirschenberger Date: Fri, 18 Jul 2025 11:15:09 +0200 Subject: [PATCH 6/6] feat: change warnings message --- csaf_2_1/recommendedTests/recommendedTest_6_2_37.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/csaf_2_1/recommendedTests/recommendedTest_6_2_37.js b/csaf_2_1/recommendedTests/recommendedTest_6_2_37.js index 6cd15ab3..a98a8d82 100644 --- a/csaf_2_1/recommendedTests/recommendedTest_6_2_37.js +++ b/csaf_2_1/recommendedTests/recommendedTest_6_2_37.js @@ -61,7 +61,7 @@ export function recommendedTest_6_2_37(doc) { const role = metric.content?.ssvc_v1?.role if (role !== undefined && !registeredSsvcRoles.includes(role)) { context.warnings.push({ - message: `The used role "${role}" is not a registered role`, + message: `The used role "${role}" is not registered`, instancePath: `/vulnerabilities/${vulnerabilityIndex}/metrics/${metricIndex}/content/ssvc_v1/role`, }) }