mirror of
https://github.com/wolfSSL/wolfssl.git
synced 2026-08-10 23:01:23 +02:00
Add tooling to produce Software Bills of Materials and build provenance for wolfSSL, supporting EU Cyber Resilience Act (CRA) obligations. SBOM generation: - New `make sbom` target producing SPDX 2.3 output with NTIA minimum elements, urn:uuid document namespaces, and SPDX LicenseRef compliance. - Reproducible library discovery across autotools and CMake builds, with liboqs recorded as a linked artefact. - Standalone `scripts/gen-sbom` for embedded / RTOS / custom-builder flows that do not use the main build system, plus --srcs-file, --no-artifact-hash, and hash-source options. Build provenance (OmniBOR / bomsh): - End-to-end bomsh tracing of the built binaries with ArtifactID insertion, snapshotting the traced library before libtool relink and hashing the bomsh-traced binary. - `scripts/bomsh_verify.py` to validate provenance against the traced gitoid. Security advisories: - `scripts/gen-advisory` generating CSAF 2.0 and CycloneDX VEX, with a `make` target, VEX overlay schema/example, and CWE name data. Docs, tests, and CI: - doc/SBOM.md and doc/CRA.md, plus README/INSTALL updates. - Unit and regression tests for gen-sbom and gen-advisory. - New sbom.yml and advisory.yml workflows: SPDX validation via pyspdxtools, CSAF validation, bomsh provenance verification, SBOM artifact archiving, macOS coverage, and actions pinned to SHAs. Signed-off-by: Sameeh Jubran <sameeh@wolfssl.com>
84 lines
3.0 KiB
JavaScript
84 lines
3.0 KiB
JavaScript
// CSAF 2.0 conformance gate for documents emitted by scripts/gen-advisory.
|
|
//
|
|
// JSON-schema validity is necessary but NOT sufficient for CSAF: the standard
|
|
// defines a battery of *mandatory tests* (section 6.1.*) -- CVSS/vector
|
|
// consistency, contradicting product status, product_id defined/used,
|
|
// tracking.version vs revision_history, and so on -- that a bare schema pass
|
|
// happily accepts. This runner uses the Secvisogram reference implementation
|
|
// (@secvisogram/csaf-validator-lib) which bundles every schema (incl. the
|
|
// first.org CVSS schemas) and implements those mandatory tests, so the check
|
|
// is fully offline and reproducible once the pinned dependency is installed.
|
|
//
|
|
// Gate = the strict CSAF 2.0 schema test + all mandatory tests. Optional and
|
|
// informative tests are reported as warnings only (they encode house-style
|
|
// preferences, not conformance).
|
|
//
|
|
// Usage: node scripts/csaf_validate.mjs <doc.csaf.json> [<doc2.csaf.json> ...]
|
|
// Exit 0 if every document passes the gate, 1 otherwise.
|
|
|
|
import { readFileSync } from 'node:fs'
|
|
import validate from '@secvisogram/csaf-validator-lib/validate.js'
|
|
import * as schemaTests from '@secvisogram/csaf-validator-lib/schemaTests.js'
|
|
import * as mandatoryTests from '@secvisogram/csaf-validator-lib/mandatoryTests.js'
|
|
import * as optionalTests from '@secvisogram/csaf-validator-lib/optionalTests.js'
|
|
|
|
const files = process.argv.slice(2)
|
|
if (files.length === 0) {
|
|
console.error('usage: node scripts/csaf_validate.mjs <doc.csaf.json> ...')
|
|
process.exit(2)
|
|
}
|
|
|
|
// The gate: strict 2.0 schema + every mandatory test.
|
|
const gateTests = [schemaTests.csaf_2_0_strict, ...Object.values(mandatoryTests)]
|
|
// Reported for visibility but non-fatal.
|
|
const advisoryTests = [...Object.values(optionalTests)]
|
|
|
|
function summarize(testResults) {
|
|
// testResults: [{ name, isValid, errors, warnings, infos }]
|
|
const failed = []
|
|
for (const t of testResults) {
|
|
if (t.isValid === false || (t.errors && t.errors.length > 0)) {
|
|
failed.push(t)
|
|
}
|
|
}
|
|
return failed
|
|
}
|
|
|
|
let anyInvalid = false
|
|
|
|
for (const file of files) {
|
|
let doc
|
|
try {
|
|
doc = JSON.parse(readFileSync(file, 'utf8'))
|
|
} catch (e) {
|
|
console.error(`ERROR: cannot read/parse ${file}: ${e.message}`)
|
|
anyInvalid = true
|
|
continue
|
|
}
|
|
|
|
const gate = await validate(gateTests, doc)
|
|
const advisory = await validate(advisoryTests, doc)
|
|
|
|
if (gate.isValid) {
|
|
console.log(`OK ${file} (strict schema + ${Object.keys(mandatoryTests).length} mandatory tests)`)
|
|
} else {
|
|
anyInvalid = true
|
|
console.error(`FAIL ${file}`)
|
|
for (const t of summarize(gate.tests)) {
|
|
for (const err of t.errors || []) {
|
|
console.error(` [${t.name}] ${err.instancePath || '/'}: ${err.message}`)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Surface optional-test warnings without failing the build.
|
|
const optWarn = summarize(advisory.tests)
|
|
for (const t of optWarn) {
|
|
for (const err of t.errors || []) {
|
|
console.warn(` warn ${file} [${t.name}] ${err.instancePath || '/'}: ${err.message}`)
|
|
}
|
|
}
|
|
}
|
|
|
|
process.exit(anyInvalid ? 1 : 0)
|