Skip to content

Release provenance (SBOM, dependency scan)

tools/generate-sbom.ts, tools/dependency-scan.ts, and tools/release-provenance.ts (WU-3517, INIT-091 phase 2) generate release provenance mechanically for every published @hellmai/lumenflow-* package and pack: an SBOM, a dependency vulnerability scan, a checksum, a signature reference, and a compatibility declaration.

pnpm lumenflow:release --release-version 7.0.0 --verify-provenance

When passed, the gate runs after packed-artifact validation and before npm publish (Phase 3.5 of the release pipeline) for every package in the publish set.

The local release launcher has a separate, mandatory executable-coherence check. release is always rebuilt through the ownership-safe fresh-dist path and can run only when cli-artifact-provenance.json matches all of:

  • the authoritative CLI source digest;
  • the package and lockfile dependency digest;
  • the root/package build configuration digest (TypeScript and bundler config);
  • the running Node major and ABI; and
  • the expected dist entry path.

This check is content- and runtime-based; dist timestamps are not trusted. A missing, stale, corrupt, or ABI-incompatible sidecar triggers the singleflight rebuild. If the rebuilt output still cannot be proven coherent, the command fails closed before any release mutation. Use the deterministic remediation printed by the launcher, normally pnpm install && pnpm build, then retry under Node 26.

generate-sbom.ts emits a CycloneDX 1.5 JSON document (sbom.cdx.json) per package, built from pnpm list --json --depth Infinity --prod — no new generator dependency (@cyclonedx/cyclonedx-npm or similar) was added, since CycloneDX is a JSON schema, not a runtime library requirement.

import { generateSbomForPackage } from './tools/generate-sbom.ts';

const { sbomPath, sbom } = generateSbomForPackage('packages/@lumenflow/agent/package.json');

dependency-scan.ts runs pnpm audit --json per artifact and fails the release on any critical or high finding (dossier launch gate 12) — no new scanner dependency, since pnpm audit is already part of the toolchain.

import { runDependencyScan } from './tools/dependency-scan.ts';

const { report } = runDependencyScan('@hellmai/lumenflow-agent', {
  cwd: 'packages/@lumenflow/agent',
});
report.ok; // false if any critical/high finding was found

release-provenance.ts assembles the full record — SBOM, dependency scan, a recursive sha256 checksum over the built dist/, a signature reference, and a compatibility declaration — then runs assertProvenanceGateFailsClosed, which throws (never returns a silent ok: false) when any of the following is missing or stale:

  • SBOM missing, or its component version doesn’t match the artifact version
  • Dependency scan missing, or it found a blocking (critical/high) finding
  • Checksum missing
  • Signature missing
  • Compatibility declaration missing
import { assertProvenanceGateFailsClosed } from './tools/release-provenance.ts';

assertProvenanceGateFailsClosed(record); // throws a descriptive Error on any gap

Signature reference: consumed, not generated

Section titled “Signature reference: consumed, not generated”

resolveSignatureReference looks for an existing signature sidecar (.sig, .sigstore.json, .intoto.jsonl) next to the SBOM. This module is intentionally a consumer, not a producer, of signatures. Real cryptographic signing shipped in WU-3371/WU-3372 (pack signing and OCI distribution, INIT-087) — but for the OCI-distributed pack artifacts pack:publish/pack:install --source registry move, which never pass through this SBOM-sidecar path. No equivalent signer exists yet for the npm-published @hellmai/lumenflow-* packages this module covers, so the gate above still fails closed rather than fabricating a signature — which is exactly why --verify-provenance stays opt-in today.

When an artifact’s version crosses a compatibility-manifest MAJOR boundary, writeMigrationGuideIfNeeded writes a MIGRATION.md alongside the provenance record, naming the previous and new versions and the required migration steps. Below a MAJOR boundary, no migration guide is written.

The provenance gate is one stage in a larger fail-closed release pipeline:

  1. Preconditions: the release refuses to proceed — for a real cut and for --dry-run alike — unless governed local validation and the complete pre-release checks pass. Normal CI is an optional pull-request/manual diagnostic, not a release authority.
  2. Packed-consumer smoke lane: every publishable package is installed into a fresh consumer fixture from a staging registry and exercised through lumenflow init and a minimal WU lifecycle before any real publish. See Release verification.
  3. Cross-harness capability certification (WU-3829): the local gate covers filesystem/shell, MCP stdio, authenticated MCP HTTP, direct runtime, and an unknown future front door across spawn/no-spawn and model/effort-control / no-control permutations. It validates the effective catalogs and canonical skill digest, treats a bounded 258-file adversarial corpus (256 native-memory entries, one stale summary, and one synthetic bypass brief) as advisory only, and records requested/resolved/applied/unattested/fallback/blocked/deviation without provider-name branches. Its hashed machine-readable evidence is written beneath the ignored .lumenflow/tmp/certification/release/ path and shared by pre-release:check, release dry-run, and tag-publish backstops.
  4. Capability and packed-artifact validation.
  5. Provenance gate (this page, opt-in via --verify-provenance): SBOM, dependency scan, checksum, signature reference, compatibility declaration.
  6. Publish.

For the governed v7 cut, npm package publication and signed OCI pack publication are distinct artifact lanes. The tag workflow must produce and read back the OCI signature, SBOM, and provenance for the Reliability Operations pack. The optional npm --verify-provenance flag must not be used as an unsigned fallback or as a substitute for that signed OCI evidence.

A release fails closed at the first stage that cannot be satisfied. Protected tag workflows still own npm credentials, Actions OIDC/Sigstore identity, signed OCI read-back, GitHub release creation, and docs deployment; removing normal CI from release authorization does not bypass those boundaries.

This module replaces the manual “verify provenance and SBOM” step previously required for the Reliability Operations pack (WU-3383) with a mechanical, per-artifact gate. It does not implement pack signing or OCI distribution itself — see Signed OCI pack distribution (WU-3371/WU-3372, INIT-087) for that shipped, separate pipeline — and it does not yet have an npm-package-signing counterpart to consume.

  • Contract spine — the compatibility manifest this module’s compatibility declaration complements.