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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -332,7 +332,6 @@ The following tests are not yet implemented and therefore missing:
- Recommended Test 6.2.26
- Recommended Test 6.2.31
- Recommended Test 6.2.32
- Recommended Test 6.2.33
- Recommended Test 6.2.34
- Recommended Test 6.2.35
- Recommended Test 6.2.36
Expand Down Expand Up @@ -460,6 +459,7 @@ export const recommendedTest_6_2_27: DocumentTest
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_33: 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 @@ -33,5 +33,6 @@ export { recommendedTest_6_2_27 } from './recommendedTests/recommendedTest_6_2_2
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_30 } from './recommendedTests/recommendedTest_6_2_30.js'
export { recommendedTest_6_2_33 } from './recommendedTests/recommendedTest_6_2_33.js'
export { recommendedTest_6_2_38 } from './recommendedTests/recommendedTest_6_2_38.js'
export { recommendedTest_6_2_43 } from './recommendedTests/recommendedTest_6_2_43.js'
98 changes: 98 additions & 0 deletions csaf_2_1/recommendedTests/recommendedTest_6_2_33.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import Ajv from 'ajv/dist/jtd.js'
import { compareZonedDateTimes } from '../dateHelper.js'
import { Temporal } from 'temporal-polyfill'

const ajv = new Ajv()

const inputSchema = /** @type {const} */ ({
additionalProperties: true,
properties: {
document: {
additionalProperties: true,
properties: {
tracking: {
additionalProperties: true,
properties: {
revision_history: {
elements: {
additionalProperties: true,
optionalProperties: {
date: { type: 'string' },
},
},
},
},
},
},
},
vulnerabilities: {
elements: {
additionalProperties: true,
optionalProperties: {
disclosure_date: { type: 'string' },
},
},
},
},
})

const validate = ajv.compile(inputSchema)

/**
* This implements the recommended test 6.2.33 of the CSAF 2.1 standard.
*
* @param {any} doc
*/
export function recommendedTest_6_2_33(doc) {
/** @type {Array<{ message: string; instancePath: string }>} */
const warnings = []
const context = { warnings }

if (!validate(doc)) {
return context
}
const currentTimestampUtc = Temporal.Now.zonedDateTimeISO('UTC').toString()
for (let i = 0; i < doc.vulnerabilities.length; ++i) {
const disclosureDate = doc.vulnerabilities[i].disclosure_date
// check if the disclosure date is in the past
if (
disclosureDate &&
compareZonedDateTimes(disclosureDate, currentTimestampUtc) < 1
) {
const revisionHistory = doc.document.tracking.revision_history
// sort the revision history (ascending) so one don't need to loop through it
// to find the date of its newest item
revisionHistory.sort((a, b) => {
// if both dates are undefined, consider them equal
if (!a.date && !b.date) {
return 0
}
// move undefined items to the beginning of the array
if (!a.date) {
return -1
}
if (!b.date) {
return 1
}

// if both dates are not undefined, compare them
return compareZonedDateTimes(a.date, b.date)
})
// compare the disclosure date with the date of the newest item of the revision history
const newestItemInRevisionHistory =
revisionHistory[revisionHistory.length - 1].date
if (
newestItemInRevisionHistory &&
compareZonedDateTimes(disclosureDate, newestItemInRevisionHistory) > 0
) {
context.warnings.push({
message:
'The disclosure_date is in the past but newer than the date of the newest item of the revision_history.',
instancePath: `/vulnerabilities/${i}/disclosure_date`,
})
}
}
}

return context
}
1 change: 0 additions & 1 deletion tests/csaf_2_1/oasis.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ const excluded = [
'6.2.26',
'6.2.31',
'6.2.32',
'6.2.33',
'6.2.34',
'6.2.35',
'6.2.36',
Expand Down
36 changes: 36 additions & 0 deletions tests/csaf_2_1/recommendedTest_6_2_33.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import assert from 'node:assert'
import { recommendedTest_6_2_33 } from '../../csaf_2_1/recommendedTests.js'

describe('recommendedTest_6_2_33', function () {
it('only runs on relevant documents', function () {
assert.equal(
recommendedTest_6_2_33({ vulnerabilities: 'mydoc' }).warnings.length,
0
)
})
it('skips empty objects', function () {
assert.equal(
recommendedTest_6_2_33({
document: {
tracking: {
revision_history: [
{
date: '2024-01-22T10:00:00.000Z',
number: '1',
summary: 'Initial version.',
},
{}, // should be ignored
],
},
},
vulnerabilities: [
{
disclosure_date: '2024-02-24T10:00:00.000Z',
},
{}, // should be ignored
],
}).warnings.length,
1
)
})
})