diff --git a/README.md b/README.md index 574c7668..fb821a71 100644 --- a/README.md +++ b/README.md @@ -315,7 +315,6 @@ The following tests are not yet implemented and therefore missing: - Mandatory Test 6.1.10 - Mandatory Test 6.1.14 - Mandatory Test 6.1.16 -- Mandatory Test 6.1.27.12 - Mandatory Test 6.1.27.13 - Mandatory Test 6.1.27.14 - Mandatory Test 6.1.27.15 @@ -422,6 +421,7 @@ export const mandatoryTest_6_1_27_8: DocumentTest export const mandatoryTest_6_1_27_9: DocumentTest export const mandatoryTest_6_1_27_10: DocumentTest export const mandatoryTest_6_1_27_11: DocumentTest +export const mandatoryTest_6_1_27_12: DocumentTest export const mandatoryTest_6_1_28: DocumentTest export const mandatoryTest_6_1_29: DocumentTest export const mandatoryTest_6_1_30: DocumentTest diff --git a/csaf_2_1/mandatoryTests.js b/csaf_2_1/mandatoryTests.js index 95c5c092..d31895cc 100644 --- a/csaf_2_1/mandatoryTests.js +++ b/csaf_2_1/mandatoryTests.js @@ -38,6 +38,7 @@ export { mandatoryTest_6_1_1 } from './mandatoryTests/mandatoryTest_6_1_1.js' export { mandatoryTest_6_1_8 } from './mandatoryTests/mandatoryTest_6_1_8.js' export { mandatoryTest_6_1_11 } from './mandatoryTests/mandatoryTest_6_1_11.js' export { mandatoryTest_6_1_13 } from './mandatoryTests/mandatoryTest_6_1_13.js' +export { mandatoryTest_6_1_27_12 } from './mandatoryTests/mandatoryTest_6_1_27_12.js' export { mandatoryTest_6_1_34 } from './mandatoryTests/mandatoryTest_6_1_34.js' export { mandatoryTest_6_1_35 } from './mandatoryTests/mandatoryTest_6_1_35.js' export { mandatoryTest_6_1_9 } from './mandatoryTests/mandatoryTest_6_1_9.js' diff --git a/csaf_2_1/mandatoryTests/mandatoryTest_6_1_27_12.js b/csaf_2_1/mandatoryTests/mandatoryTest_6_1_27_12.js new file mode 100644 index 00000000..2ba6c559 --- /dev/null +++ b/csaf_2_1/mandatoryTests/mandatoryTest_6_1_27_12.js @@ -0,0 +1,74 @@ +import Ajv from 'ajv/dist/jtd.js' + +const ajv = new Ajv() + +/* + This is the jtd schema that needs to match the input document so that the + test is activated. If this schema doesn't match it normally means that the input + document does not validate against the csaf json schema or optional fields that + the test checks are not present. + */ +const inputSchema = /** @type {const} */ ({ + additionalProperties: true, + properties: { + document: { + additionalProperties: true, + properties: { + category: { + type: 'string', + }, + }, + }, + vulnerabilities: { + elements: { + additionalProperties: true, + optionalProperties: { + product_status: { + additionalProperties: true, + optionalProperties: { + known_affected: { + elements: { + type: 'string', + }, + }, + }, + }, + }, + }, + }, + }, +}) + +const validate = ajv.compile(inputSchema) + +/** + * This implements the mandatory test 6.1.27.12 of the CSAF 2.1 standard. + * + * @param {unknown} doc + */ +export function mandatoryTest_6_1_27_12(doc) { + /* + The `ctx` variable holds the state that is accumulated during the test ran and is + finally returned by the function. + */ + const ctx = { + errors: + /** @type {Array<{ instancePath: string; message: string }>} */ ([]), + isValid: true, + } + + if (!validate(doc) || doc.document.category !== 'csaf_security_advisory') + return ctx + + for (const [index, vulnerability] of doc.vulnerabilities.entries()) { + if (!vulnerability.product_status?.known_affected) { + ctx.isValid = false + ctx.errors.push({ + instancePath: `/vulnerabilities/${index}/product_status`, + message: `missing the know_effected element`, + }) + } + } + + return ctx +} diff --git a/tests/csaf_2_1/mandatoryTest_6_1_27_12.js b/tests/csaf_2_1/mandatoryTest_6_1_27_12.js new file mode 100644 index 00000000..0643bc86 --- /dev/null +++ b/tests/csaf_2_1/mandatoryTest_6_1_27_12.js @@ -0,0 +1,38 @@ +import assert from 'node:assert/strict' +import { mandatoryTest_6_1_27_12 } from '../../csaf_2_1/mandatoryTests/mandatoryTest_6_1_27_12.js' + +describe('mandatoryTest_6_1_27_12', function () { + it('only runs on documents matching the input schema', function () { + assert.equal( + mandatoryTest_6_1_27_12({ + document: 'invalid json', + vulnerabilities: [ + { + product_status: { + under_investigation: ['CSAFPID-9080700'], + }, + }, + ], + }).isValid, + true + ) + }) + + it('only runs on csaf_security_advisory documents', function () { + assert.equal( + mandatoryTest_6_1_27_12({ + document: { + category: 'unknown category', + }, + vulnerabilities: [ + { + product_status: { + under_investigation: ['CSAFPID-9080700'], + }, + }, + ], + }).isValid, + true + ) + }) +}) diff --git a/tests/csaf_2_1/oasis.js b/tests/csaf_2_1/oasis.js index 6fb44c13..89d12404 100644 --- a/tests/csaf_2_1/oasis.js +++ b/tests/csaf_2_1/oasis.js @@ -20,7 +20,6 @@ const excluded = [ '6.1.27.4', '6.1.27.6', '6.1.27.11', - '6.1.27.12', '6.1.27.13', '6.1.27.14', '6.1.27.15',