Skip to content

Commit 0633584

Browse files
feat(CSAF2.1): #402 add mandatory test 6.2.39.3
1 parent 1e4bb23 commit 0633584

File tree

5 files changed

+147
-1
lines changed

5 files changed

+147
-1
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -462,6 +462,7 @@ export const recommendedTest_6_2_18: DocumentTest
462462
export const recommendedTest_6_2_22: DocumentTest
463463
export const recommendedTest_6_2_23: DocumentTest
464464
export const recommendedTest_6_2_39_2: DocumentTest
465+
export const recommendedTest_6_2_39_3: DocumentTest
465466
```
466467
467468
[(back to top)](#bsi-csaf-validator-lib)

csaf_2_1/recommendedTests.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,4 @@ export { recommendedTest_6_2_28 } from './recommendedTests/recommendedTest_6_2_2
3333
export { recommendedTest_6_2_29 } from './recommendedTests/recommendedTest_6_2_29.js'
3434
export { recommendedTest_6_2_38 } from './recommendedTests/recommendedTest_6_2_38.js'
3535
export { recommendedTest_6_2_39_2 } from './recommendedTests/recommendedTest_6_2_39_2.js'
36+
export { recommendedTest_6_2_39_3 } from './recommendedTests/recommendedTest_6_2_39_3.js'
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
import Ajv from 'ajv/dist/jtd.js'
2+
import {
3+
containsOneNoteWithTitleAndCategory,
4+
getTranslationInDocumentLang,
5+
isLangSpecifiedAndNotEnglish,
6+
} from '../../lib/shared/languageSpecificTranslation.js'
7+
8+
const ajv = new Ajv()
9+
10+
/*
11+
This is the jtd schema that needs to match the input document so that the
12+
test is activated. If this schema doesn't match it normally means that the input
13+
document does not validate against the csaf json schema or optional fields that
14+
the test checks are not present.
15+
*/
16+
const inputSchema = /** @type {const} */ ({
17+
additionalProperties: true,
18+
properties: {
19+
document: {
20+
additionalProperties: true,
21+
properties: {
22+
category: { type: 'string' },
23+
},
24+
optionalProperties: {
25+
lang: {
26+
type: 'string',
27+
},
28+
notes: {
29+
elements: {
30+
additionalProperties: true,
31+
optionalProperties: {
32+
category: {
33+
type: 'string',
34+
},
35+
title: {
36+
type: 'string',
37+
},
38+
},
39+
},
40+
},
41+
},
42+
},
43+
},
44+
})
45+
46+
const validateSchema = ajv.compile(inputSchema)
47+
48+
/**
49+
* If the document language is specified but not English, it MUST be tested that exactly one item
50+
* in document notes exists that has the language specific translation of the term Reasoning for Supersession as title,
51+
* The category of this item MUST be description. If no language specific translation has been recorded,
52+
* the test MUST be skipped and output an information to the user that no such translation is known.
53+
*
54+
* @param {unknown} doc
55+
*/
56+
export function recommendedTest_6_2_39_3(doc) {
57+
/*
58+
The `ctx` variable holds the state that is accumulated during the test run and is
59+
finally returned by the function.
60+
*/
61+
const ctx = {
62+
warnings:
63+
/** @type {Array<{ instancePath: string; message: string }>} */ ([]),
64+
}
65+
66+
const noteCategory = 'description'
67+
68+
if (!validateSchema(doc) || doc.document.category !== 'csaf_superseded') {
69+
return ctx
70+
}
71+
72+
const supersessionInDocLang = getTranslationInDocumentLang(
73+
doc,
74+
'reasoning_for_supersession'
75+
)
76+
if (!supersessionInDocLang) {
77+
ctx.warnings.push({
78+
instancePath: '/document/notes',
79+
message:
80+
'no language specific translation for "Reasoning for Supersession" has been recorded',
81+
})
82+
return ctx
83+
}
84+
85+
if (isLangSpecifiedAndNotEnglish(doc.document.lang)) {
86+
const notes = doc.document.notes
87+
if (
88+
!notes ||
89+
!containsOneNoteWithTitleAndCategory(
90+
notes,
91+
supersessionInDocLang,
92+
noteCategory
93+
)
94+
) {
95+
ctx.warnings.push({
96+
instancePath: '/document/notes',
97+
message:
98+
`for document category "csaf_withdrawn" exactly one note must exist ` +
99+
`with note category "${noteCategory}" and title "${supersessionInDocLang}`,
100+
})
101+
}
102+
}
103+
104+
return ctx
105+
}

tests/csaf_2_1/oasis.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,6 @@ const excluded = [
4848
'6.2.36',
4949
'6.2.37',
5050
'6.2.39.1',
51-
'6.2.39.3',
5251
'6.2.39.4',
5352
'6.2.40',
5453
'6.2.41',
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import { recommendedTest_6_2_39_3 } from '../../csaf_2_1/recommendedTests/recommendedTest_6_2_39_3.js'
2+
import { expect } from 'chai'
3+
import assert from 'node:assert'
4+
import { getTranslationInDocumentLang } from '../../lib/shared/languageSpecificTranslation.js'
5+
6+
describe('recommendedTest_6_2_39_3', function () {
7+
it('only runs on relevant documents', function () {
8+
assert.equal(recommendedTest_6_2_39_3({}).warnings.length, 0)
9+
})
10+
11+
it('only runs on valid language', function () {
12+
assert.equal(
13+
recommendedTest_6_2_39_3({
14+
document: { lang: '123', license_expression: 'MIT' },
15+
}).warnings.length,
16+
0
17+
)
18+
})
19+
20+
it('check get ReasoningForWithdrawal in document lang', function () {
21+
expect(
22+
getTranslationInDocumentLang(
23+
{ document: { lang: 'de' } },
24+
'reasoning_for_supersession'
25+
)
26+
).to.eq('Begründung für die Ersetzung')
27+
expect(
28+
getTranslationInDocumentLang(
29+
{ document: { lang: 'jp' } },
30+
'reasoning_for_supersession'
31+
)
32+
).to.eq(undefined)
33+
expect(
34+
getTranslationInDocumentLang(
35+
{ document: {} },
36+
'reasoning_for_supersession'
37+
)
38+
).to.eq(undefined)
39+
})
40+
})

0 commit comments

Comments
 (0)