UNPKG

@cyclonedx/cdxgen

Version:

Creates CycloneDX Software Bill of Materials (SBOM) from source or container image

161 lines (146 loc) 4.71 kB
import { readFileSync as actualReadFileSync } from "node:fs"; import esmock from "esmock"; import { assert, describe, it } from "poku"; import sinon from "sinon"; import { validateBom } from "./bomValidator.js"; const validCycloneDx20Bom = { specFormat: "CycloneDX", specVersion: "2.0", serialNumber: "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79", version: 1, metadata: { component: { "bom-ref": "pkg:generic/demo@1.0.0", name: "demo", purl: "pkg:generic/demo@1.0.0", type: "application", version: "1.0.0", }, tools: { components: [{ type: "application", name: "cdxgen", version: "12.4.0" }], }, }, components: [ { "bom-ref": "pkg:npm/lodash@4.17.21", name: "lodash", purl: "pkg:npm/lodash@4.17.21", type: "library", version: "4.17.21", }, ], dependencies: [ { ref: "pkg:generic/demo@1.0.0", dependsOn: ["pkg:npm/lodash@4.17.21"], }, { ref: "pkg:npm/lodash@4.17.21", dependsOn: [] }, ], }; describe("validateBom()", () => { it("validates CycloneDX 2.0-dev JSON against the bundled schema", () => { assert.strictEqual(validateBom(validCycloneDx20Bom), true); }); it("returns a clear validation failure for unsupported spec versions", async () => { const readFileSyncStub = sinon.stub(); const consoleLogStub = sinon.stub(console, "log"); try { const { validateBom } = await esmock("./bomValidator.js", { "node:fs": { readFileSync: readFileSyncStub, }, }); assert.strictEqual( validateBom({ bomFormat: "CycloneDX", specVersion: "2.0.1" }), false, ); sinon.assert.notCalled(readFileSyncStub); sinon.assert.calledWithMatch( consoleLogStub, "Unsupported CycloneDX specVersion '2.0.1'.", ); } finally { consoleLogStub.restore(); } }); it("caches compiled CycloneDX schema validators by spec version", async () => { const readFileSyncStub = sinon .stub() .callsFake((...args) => actualReadFileSync(...args)); const { validateBom } = await esmock("./bomValidator.js", { "node:fs": { readFileSync: readFileSyncStub, }, }); assert.strictEqual(validateBom(validCycloneDx20Bom), true); const readCountAfterFirstValidation = readFileSyncStub.callCount; assert.ok(readCountAfterFirstValidation > 0); assert.strictEqual(validateBom(validCycloneDx20Bom), true); assert.strictEqual( readFileSyncStub.callCount, readCountAfterFirstValidation, ); }); }); describe("validateSpdx()", () => { it("lazy-loads the bundled SPDX export schema on first validation call", async () => { const readFileSyncStub = sinon .stub() .returns( '{"type":"object","properties":{"@context":{"const":"https://spdx.org/rdf/3.0.1/spdx-context.jsonld"},"@graph":{"type":"array"}}}', ); const { validateSpdx } = await esmock("./bomValidator.js", { "node:fs": { readFileSync: readFileSyncStub, }, "../helpers/utils.js": { DEBUG_MODE: false, dirNameStr: "/tmp", isPartialTree: sinon.stub().returns(false), }, "../stages/postgen/spdxConverter.js": { SPDX_JSONLD_CONTEXT: "https://spdx.org/rdf/3.0.1/spdx-context.jsonld", SPDX_SPEC_VERSION: "3.0.1", }, }); sinon.assert.notCalled(readFileSyncStub); assert.strictEqual( validateSpdx({ "@context": "https://spdx.org/rdf/3.0.1/spdx-context.jsonld", "@graph": [], }), false, ); sinon.assert.calledOnce(readFileSyncStub); }); it("caches the bundled SPDX export schema between validation calls", async () => { const readFileSyncStub = sinon .stub() .returns( '{"type":"object","properties":{"@context":{"const":"https://spdx.org/rdf/3.0.1/spdx-context.jsonld"},"@graph":{"type":"array"}}}', ); const { validateSpdx } = await esmock("./bomValidator.js", { "node:fs": { readFileSync: readFileSyncStub, }, "../helpers/utils.js": { DEBUG_MODE: false, dirNameStr: "/tmp", isPartialTree: sinon.stub().returns(false), }, "../stages/postgen/spdxConverter.js": { SPDX_JSONLD_CONTEXT: "https://spdx.org/rdf/3.0.1/spdx-context.jsonld", SPDX_SPEC_VERSION: "3.0.1", }, }); validateSpdx({ "@context": "https://spdx.org/rdf/3.0.1/spdx-context.jsonld", "@graph": [], }); validateSpdx({ "@context": "https://spdx.org/rdf/3.0.1/spdx-context.jsonld", "@graph": [], }); sinon.assert.calledOnce(readFileSyncStub); }); });