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
135 changes: 132 additions & 3 deletions csaf_2_1/recommendedTests/recommendedTest_6_2_16.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,137 @@
import { optionalTest_6_2_16 } from '../../optionalTests.js'
import { Ajv } from 'ajv/dist/jtd.js'

const ajv = new Ajv()

const inputSchema = /** @type {const} */ ({
additionalProperties: true,
optionalProperties: {
product_tree: {
additionalProperties: true,
optionalProperties: {
branches: {
elements: { additionalProperties: true, properties: {} },
},
full_product_names: {
elements: { additionalProperties: true, properties: {} },
},
product_paths: {
elements: { additionalProperties: true, properties: {} },
},
},
},
},
})

const branchSchema = /** @type {const} */ ({
additionalProperties: true,
optionalProperties: {
branches: {
elements: {
additionalProperties: true,
properties: {},
},
},
product: {
additionalProperties: true,
optionalProperties: {
product_identification_helper: {
additionalProperties: true,
properties: {},
},
},
},
},
})

const productPathSchema = /** @type {const} */ ({
additionalProperties: true,
optionalProperties: {
full_product_name: {
additionalProperties: true,
optionalProperties: {
product_identification_helper: {
additionalProperties: true,
properties: {},
},
},
},
},
})

const validateInput = ajv.compile(inputSchema)
const validateBranch = ajv.compile(branchSchema)
const validateProductPath = ajv.compile(productPathSchema)

/**
* @param {unknown} doc
* @param {any} doc
*/
export function recommendedTest_6_2_16(doc) {
return optionalTest_6_2_16(doc)
const ctx = {
warnings:
/** @type {Array<{ instancePath: string; message: string }>} */ ([]),
}

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

doc.product_tree?.full_product_names?.forEach(
(fullProductName, fullProductNameIndex) => {
if (!fullProductName.product_identification_helper) {
ctx.warnings.push({
instancePath: `/product_tree/full_product_names/${fullProductNameIndex}`,
message: 'missing product identification helper',
})
}
}
)

/**
* @param {object} params
* @param {string} params.path
* @param {unknown[]} params.branches
*/
function checkBranches({ path, branches }) {
branches.forEach((branch, branchIndex) => {
if (!validateBranch(branch)) {
return
}
if (branch.product && !branch.product.product_identification_helper) {
ctx.warnings.push({
instancePath: `${path}/${branchIndex}/product`,
message: 'missing product identification helper',
})
}
if (Array.isArray(branch.branches)) {
checkBranches({
path: `${path}/${branchIndex}/branches`,
branches: branch.branches,
})
}
})
}

if (doc.product_tree?.branches) {
checkBranches({
path: '/product_tree/branches',
branches: doc.product_tree.branches,
})
}

doc.product_tree?.product_paths?.forEach((productPath, productPathIndex) => {
if (!validateProductPath(productPath)) {
return
}
if (
productPath.full_product_name &&
!productPath.full_product_name.product_identification_helper
) {
ctx.warnings.push({
instancePath: `/product_tree/product_paths/${productPathIndex}/full_product_name`,
message: 'missing product identification helper',
})
}
})

return ctx
}
56 changes: 56 additions & 0 deletions tests/csaf_2_1/recommendedTest_6_2_16.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import assert from 'node:assert'
import { recommendedTest_6_2_16 } from '../../csaf_2_1/recommendedTests.js'

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

it('returns no warnings for invalid inputSchema (product_tree is not an object)', function () {
const result = recommendedTest_6_2_16({
product_tree: 'not-an-object',
})
assert.equal(result.warnings.length, 0)
})

it('skips invalid branch entries and does not throw', function () {
const result = recommendedTest_6_2_16({
product_tree: {
branches: [{ product: 'not-an-object' }],
},
})
assert.equal(result.warnings.length, 0)
})

it('skips invalid product_paths entries and does not throw', function () {
const result = recommendedTest_6_2_16({
product_tree: {
product_paths: [{ full_product_name: 'not-an-object' }],
},
})
assert.equal(result.warnings.length, 0)
})

it('warns when a product_paths entry is missing product_identification_helper', function () {
const result = recommendedTest_6_2_16({
product_tree: {
product_paths: [
{
full_product_name: {
name: 'Product A',
product_id: 'CSAFPID-0001',
},
},
],
},
})
assert.equal(result.warnings.length, 1)
assert.equal(
result.warnings[0].instancePath,
'/product_tree/product_paths/0/full_product_name'
)
})
})
Loading