Skip to main content

Module sbom

Module sbom 

Source
Expand description

Build-time SBOM generation (issue #457).

Emits a CycloneDX 1.5 JSON Software Bill of Materials at the root of the generated site (sbom.cdx.json) and links to it from every HTML page via <link rel="sbom" type="application/vnd.cyclonedx+json">.

§Why ship an SBOM with the static site?

Procurement teams in regulated industries (finance, healthcare, government) increasingly require SBOMs for any deployed software — including the build pipeline that produced static assets. The scheduled.yml workflow already generates a CycloneDX SBOM via cargo cyclonedx and attaches a Sigstore provenance attestation, but those artifacts live in CI; they’re not discoverable from the deployed site. This plugin fixes that gap by embedding the SBOM into every site, making the supply chain machine- introspectable from the consumer’s browser.

§Format

Minimal CycloneDX 1.5 (the JSON Schema is documented at https://cyclonedx.org/docs/1.5/json/). The component list covers the SSG package itself; transitive Cargo dependencies are out of scope here (they’re in the CI-generated SBOM published as a release artifact). The rendered SBOM declares:

  • bomFormat: “CycloneDX”
  • specVersion: “1.5”
  • serialNumber: urn:uuid:…, derived from the build (see below)
  • version: 1
  • metadata.timestamp: build time (ISO 8601, UTC)
  • metadata.tools[]: SSG name + version
  • metadata.component: the site itself (type: “application”)
  • components[]: SSG generator

§Discoverability

Every HTML page emitted by the build receives a <link rel="sbom" type="application/vnd.cyclonedx+json" href="<base-url-path>/sbom.cdx.json"> element in <head>. This is the IANA-registered link relation for SBOM discovery (registered 2023; see https://www.iana.org/assignments/link-relations/).

§Serial number

serialNumber is optional in the CycloneDX schema, but consumers use it to tell the format apart from SPDX. GitHub’s attestation action, for one, recognises CycloneDX only when bomFormat, serialNumber and specVersion are all present, and otherwise fails a release with “Unsupported SBOM format”. An SBOM without it is therefore valid but not attestable.

The value is derived from the build rather than drawn at random, so SOURCE_DATE_EPOCH pins it along with the timestamp and the determinism gate still holds. Two builds that differ only in wall clock still get different serials, which is what CycloneDX asks for.

§Idempotency

The HTML transform is idempotent — pages that already contain rel="sbom" are left unchanged. The JSON file is rewritten on every build (so timestamps stay current).

Structs§

SbomPlugin
Plugin that emits a CycloneDX SBOM and links to it from every HTML page.