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 mandatoryTest_6_1_46: DocumentTest
export const mandatoryTest_6_1_51: DocumentTest
export const mandatoryTest_6_1_52: DocumentTest
export const mandatoryTest_6_1_53: DocumentTest
export const mandatoryTest_6_1_56: DocumentTest
export const mandatoryTest_6_1_57: DocumentTest
export const mandatoryTest_6_1_58: DocumentTest
export const mandatoryTest_6_1_61: DocumentTest
Expand Down
1 change: 1 addition & 0 deletions csaf_2_1/mandatoryTests.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ export { mandatoryTest_6_1_46 } from './mandatoryTests/mandatoryTest_6_1_46.js'
export { mandatoryTest_6_1_51 } from './mandatoryTests/mandatoryTest_6_1_51.js'
export { mandatoryTest_6_1_52 } from './mandatoryTests/mandatoryTest_6_1_52.js'
export { mandatoryTest_6_1_53 } from './mandatoryTests/mandatoryTest_6_1_53.js'
export { mandatoryTest_6_1_56 } from './mandatoryTests/mandatoryTest_6_1_56.js'
export { mandatoryTest_6_1_57 } from './mandatoryTests/mandatoryTest_6_1_57.js'
export { mandatoryTest_6_1_58 } from './mandatoryTests/mandatoryTest_6_1_58.js'
export { mandatoryTest_6_1_61 } from './mandatoryTests/mandatoryTest_6_1_61.js'
153 changes: 153 additions & 0 deletions csaf_2_1/mandatoryTests/mandatoryTest_6_1_56.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
import Ajv from 'ajv/dist/jtd.js'

/** @typedef {string} Product

/** @typedef {import('ajv/dist/jtd.js').JTDDataType<typeof inputSchema>} InputSchema */

/** @typedef {InputSchema['vulnerabilities'][number]} Vulnerability */

/** @typedef {NonNullable<Vulnerability['metrics']>[number]} Metric */

const jtdAjv = new Ajv()

Check failure on line 11 in csaf_2_1/mandatoryTests/mandatoryTest_6_1_56.js

View workflow job for this annotation

GitHub Actions / test (22.x)

This expression is not constructable.

Check failure on line 11 in csaf_2_1/mandatoryTests/mandatoryTest_6_1_56.js

View workflow job for this annotation

GitHub Actions / test (20.x)

This expression is not constructable.

const inputSchema = /** @type {const} */ ({
additionalProperties: true,
properties: {
vulnerabilities: {
elements: {
additionalProperties: true,
optionalProperties: {
metrics: {
elements: {
additionalProperties: true,
optionalProperties: {
source: {
type: 'string',
},
products: {
elements: { type: 'string' },
},
content: {
additionalProperties: true,
optionalProperties: {
cvss_v2: {
additionalProperties: true,
optionalProperties: {
version: { type: 'string' },
},
},
cvss_v3: {
additionalProperties: true,
optionalProperties: {
version: { type: 'string' },
},
},
cvss_v4: {
additionalProperties: true,
optionalProperties: {
version: { type: 'string' },
},
},
qualitative_severity_rating: {
type: 'string',
},
},
},
},
},
},
},
},
},
},
})

const validate = jtdAjv.compile(inputSchema)

/**
* For each item in `/vulnerabilities` it MUST be tested that no Qualitative Severity Rating and CVSS values are
* listed for the tuple of Product ID and source.
* @param {unknown} doc
*/
export function mandatoryTest_6_1_56(doc) {
const ctx = {
errors:
/** @type {Array<{ instancePath: string; message: string }>} */ ([]),
isValid: true,
}

/** @type {Array<{ message: string; instancePath: string }>} */
const errors = []

if (!validate(doc)) {
return ctx
}

/** @type {Array<Vulnerability>} */
const vulnerabilities = doc.vulnerabilities

Check failure on line 87 in csaf_2_1/mandatoryTests/mandatoryTest_6_1_56.js

View workflow job for this annotation

GitHub Actions / test (22.x)

'doc' is of type 'unknown'.

Check failure on line 87 in csaf_2_1/mandatoryTests/mandatoryTest_6_1_56.js

View workflow job for this annotation

GitHub Actions / test (20.x)

'doc' is of type 'unknown'.

/**
* Create a unique string for the tuple of productId and source
* to compare them easily
* @param {string} productId
* @param {string | undefined} source
*
* @return string
*/
function createTupleStringForProductAndSource(productId, source) {
return JSON.stringify({ productId: productId, source: source ?? '' })
}

/**
* check whether the given metric contains a cvss (v2, v3 or v4) content
* @param {Metric} metric
* @returns {boolean}
*/
function hasCvssContent(metric) {
return (
metric.content?.cvss_v2?.version !== undefined ||
metric.content?.cvss_v3?.version !== undefined ||
metric.content?.cvss_v4?.version !== undefined
)
}

vulnerabilities.forEach((vulnerabilityItem, vulnerabilityIndex) => {
/** @type {Map<string,string>} */
const productIdServiceTuplesCvss = new Map()
/** @type {Map<string,string>} */
const productIdServiceTuplesRating = new Map()

/** @type {Array<Metric> | undefined} */
const metrics = vulnerabilityItem.metrics
metrics?.forEach((metric, metricIndex) => {
/** @type {Array<Product> | undefined} */
const productsOfMetric = metric.products
productsOfMetric?.forEach((product, productIndex) => {
if (hasCvssContent(metric)) {
productIdServiceTuplesCvss.set(
createTupleStringForProductAndSource(product, metric.source),
`/vulnerabilities/${vulnerabilityIndex}/metrics/${metricIndex}/products/${productIndex}`
)
}
if (metric.content?.qualitative_severity_rating) {
productIdServiceTuplesRating.set(
createTupleStringForProductAndSource(product, metric.source),
`/vulnerabilities/${vulnerabilityIndex}/metrics/${metricIndex}/products/${productIndex}`
)
}
})
})

productIdServiceTuplesCvss.forEach((value, key) => {
if (productIdServiceTuplesRating.has(key))
errors.push({
message:
'in the metrics of the vulnerability a Qualitative Severity Rating and CVSS value ' +
'with the same product id and source is used.',
instancePath: value,
})
})
})

return { errors: errors, isValid: errors.length === 0 }
}
8 changes: 8 additions & 0 deletions tests/csaf_2_1/mandatoryTest_6_1_56.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import assert from 'node:assert/strict'
import { mandatoryTest_6_1_56 } from '../../csaf_2_1/mandatoryTests/mandatoryTest_6_1_56.js'

describe('mandatoryTest_6_1_56', function () {
it('only runs on relevant documents', function () {
assert.equal(mandatoryTest_6_1_56({ document: 'mydoc' }).isValid, true)
})
})
1 change: 0 additions & 1 deletion tests/csaf_2_1/oasis.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ const excluded = [
'6.1.53',
'6.1.54',
'6.1.55',
'6.1.56',
'6.1.59',
'6.1.60.1',
'6.1.60.2',
Expand Down
Loading