Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -460,6 +460,7 @@ export const recommendedTest_6_2_28: DocumentTest
export const recommendedTest_6_2_29: DocumentTest
export const recommendedTest_6_2_30: DocumentTest
export const recommendedTest_6_2_39_2: DocumentTest
export const recommendedTest_6_2_39_4: DocumentTest
export const recommendedTest_6_2_40: DocumentTest
export const recommendedTest_6_2_43: DocumentTest
```
Expand Down
1 change: 1 addition & 0 deletions csaf_2_1/recommendedTests.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,6 @@ export { recommendedTest_6_2_29 } from './recommendedTests/recommendedTest_6_2_2
export { recommendedTest_6_2_30 } from './recommendedTests/recommendedTest_6_2_30.js'
export { recommendedTest_6_2_38 } from './recommendedTests/recommendedTest_6_2_38.js'
export { recommendedTest_6_2_39_2 } from './recommendedTests/recommendedTest_6_2_39_2.js'
export { recommendedTest_6_2_39_4 } from './recommendedTests/recommendedTest_6_2_39_4.js'
export { recommendedTest_6_2_40 } from './recommendedTests/recommendedTest_6_2_40.js'
export { recommendedTest_6_2_43 } from './recommendedTests/recommendedTest_6_2_43.js'
111 changes: 111 additions & 0 deletions csaf_2_1/recommendedTests/recommendedTest_6_2_39_4.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import Ajv from 'ajv/dist/jtd.js'
import {
existsReferenceWithSummaryAndCategory,
getTranslationInDocumentLang,
isLangSpecifiedAndNotEnglish,
} from '../../lib/shared/languageSpecificTranslation.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' },
},
optionalProperties: {
lang: {
type: 'string',
},
references: {
elements: {
additionalProperties: true,
optionalProperties: {
category: {
type: 'string',
},
summary: {
type: 'string',
},
},
},
},
},
},
},
})

const validateSchema = ajv.compile(inputSchema)

/**
* If the document language is specified but not English, it MUST be tested that at least one item in document
* references exists that starts with the language-specific translation of the term Superseding Document as summary.
* The category of this item MUST be external. If no language-specific translation has been recorded,
* the test MUST be skipped and output an information to the user that no such translation is known.
*
* @param {unknown} doc
*/
export function recommendedTest_6_2_39_4(doc) {
/*
The `ctx` variable holds the state that is accumulated during the test run and is
finally returned by the function.
*/
/** @type { {warnings: Array<{ message: string; instancePath: string }>;
* infos: Array<{ message: string; instancePath: string }>}} */
const ctx = {
warnings: [],
infos: [],
}

const referenceCategory = 'external'
const documentCategoryCsafSuperseded = `csaf_superseded`

if (
!validateSchema(doc) ||
doc.document.category !== documentCategoryCsafSuperseded
) {
return ctx
}

const supersedingInDocLang = getTranslationInDocumentLang(
doc,
'superseding_document'
)
if (!supersedingInDocLang) {
ctx.infos.push({
instancePath: '/document/references',
message:
'no language specific translation for "Superseding Document" has been recorded',
})
return ctx
}

if (isLangSpecifiedAndNotEnglish(doc.document.lang)) {
const references = doc.document.references
if (
!references ||
!existsReferenceWithSummaryAndCategory(
references,
supersedingInDocLang,
referenceCategory
)
) {
ctx.warnings.push({
instancePath: '/document/references',
message:
`for document category "${documentCategoryCsafSuperseded}" at least one references must exist ` +
`with reference category "${referenceCategory}" and whose summary begins with ${supersedingInDocLang}`,
})
}
}

return ctx
}
23 changes: 23 additions & 0 deletions lib/shared/languageSpecificTranslation.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,29 @@ export function containsOneNoteWithTitleAndCategory(
)
}

/**
* test whether at least one item in document references exists that starts with the given summary
* and has the given category.
* @param {({} & { category?: string | undefined; summary?: string | undefined; } & Record<string, unknown>)[]} references
* @param {string} summaryStartsWith
* @param {string} category
* @returns {boolean} True if the reference was found, false otherwise
*/
export function existsReferenceWithSummaryAndCategory(
references,
summaryStartsWith,
category
) {
return (
references.filter(
(reference) =>
reference.category === category &&
reference.summary &&
reference.summary.startsWith(summaryStartsWith)
).length > 0
)
}

/**
* Get the language specific translation of the given i18nKey
* @param {{ document: { lang?: string; }; }} doc
Expand Down
1 change: 0 additions & 1 deletion tests/csaf_2_1/oasis.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ const excluded = [
'6.2.37',
'6.2.39.1',
'6.2.39.3',
'6.2.39.4',
'6.2.41',
'6.2.42',
'6.2.44',
Expand Down
46 changes: 46 additions & 0 deletions tests/csaf_2_1/recommendedTest_6_2_39_4.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { recommendedTest_6_2_39_4 } from '../../csaf_2_1/recommendedTests/recommendedTest_6_2_39_4.js'
import { expect } from 'chai'
import assert from 'node:assert'
import { getTranslationInDocumentLang } from '../../lib/shared/languageSpecificTranslation.js'

describe('recommendedTest_6_2_39_4', function () {
it('only runs on relevant documents', function () {
assert.equal(recommendedTest_6_2_39_4({}).warnings.length, 0)
})

it('only runs on valid category', function () {
const result = recommendedTest_6_2_39_4({
document: { category: '123', license_expression: 'MIT' },
})

assert.equal(result.warnings.length, 0)
assert.equal(result.infos.length, 0)
})

it('only runs on valid language', function () {
const result = recommendedTest_6_2_39_4({
document: {
category: 'csaf_superseded',
lang: '123',
license_expression: 'MIT',
},
})
assert.equal(result.warnings.length, 0)
assert.equal(result.infos.length, 1)
})

it('check get superseding_document in document lang', function () {
expect(
getTranslationInDocumentLang(
{ document: { lang: 'de' } },
'superseding_document'
)
).to.eq('Ersetzendes Dokument')
expect(
getTranslationInDocumentLang({ document: { lang: 'es' } }, 'v')
).to.eq(undefined)
expect(
getTranslationInDocumentLang({ document: {} }, 'superseding_document')
).to.eq(undefined)
})
})