2.7 KiB
sbom
(no submodules)
Purpose
Generates CycloneDX 1.5 compatible Software Bill of Materials documents for
packages in Suaveplan. An SBOM lists every component a package
depends on, keyed by purl, enabling downstream vulnerability scanners,
license audits, and provenance correlation. Alongside generation, this
module exports canonical serialisation, SHA-256 digesting, and purl
construction so other packages (notably the publish pipeline) can
reproduce the same output bytes.
Features
- CycloneDX 1.5 schema adherence, validated by the sibling Zod schema.
- Scoped-package
purlconstruction (pkg:npm/%40scope/name@ver). - Workspace/catalog placeholder resolution (
workspace:*→*,catalog:key→catalog-key). - Deterministic sort-key serialisation via
canonicalize. - Injectable
clockandserialfactories for deterministic tests.
Usage: Basic Example
import { generateSbom } from "@suaveplan/slsa";
const sbom = generateSbom({
packageName: "@suaveplan/utils",
packageVersion: "1.2.3",
dependencies: { lodash: "4.17.21" },
});
Usage: Advanced Example
import { generateSbom, hashSbom, serializeSbom } from "@suaveplan/slsa";
const sbom = generateSbom(
{
packageName: "@suaveplan/app",
packageVersion: "2.0.0",
packageLicense: "MIT",
componentType: "application",
dependencies: {
"@suaveplan/crypto": "workspace:*",
vitest: "catalog:testing",
},
},
{
clock: () => 0,
serial: () => "urn:uuid:deadbeef-dead-beef-dead-beefdeadbeef",
}
);
console.log(hashSbom(sbom)); // stable across runs
await fs.writeFile("sbom.json", serializeSbom(sbom));
API Reference
generateSbom(input, opts?): Sbom— constructs the SBOM. ThrowsInvalidSbomErrorwhenpackageName,packageVersion, ordependenciesis missing.GenerateSbomOptions { clock?, serial? }— deterministic seam.serializeSbom(sbom): string— canonical JSON encoding.hashSbom(sbom): string— SHA-256 hex digest of the canonical encoding.buildPurl(name, version): string— constructs apurlfor either a scoped or unscoped npm package.
Implementation Notes
crypto.randomUUID is the default serial source; the fallback construction
using Math.random is retained only to keep the module universally
importable — runtimes that land in the fallback should be considered a
configuration bug and should inject serial explicitly. resolveVersion
maps catalog references to a stable catalog-<key> form rather than the
resolved pin because catalog resolution happens at publish time, not at
SBOM generation time; the downstream publisher can post-process the
document if stricter pins are required.