Full C++23 framework tree: runtime, observability, security, data, app, realtime, supervisor, clients, CLI, example plus enterprise tenancy, audit, operability, governance, supplychain. Postgres via docker compose for tests.
16 KiB
15 - Supply Chain and Trust
File: plans/15-supply-chain.md Scope: plan.md sections 4 (wolfSSL exception), 9 (autonomous releases). Topics: SBOM generation, signed release artifacts, dependency policy and wolfSSL exception handling, vulnerability-scan pipeline hook, provenance and release attestation.
1. Purpose and philosophy
MoloApp ships almost no supply chain: stdlib plus OS syscalls plus wolfSSL as the sole third-party dependency. This file makes that claim verifiable. Every release carries a machine-readable SBOM, a signed provenance statement describing where, when and how it was built, and detached signatures over all artifacts, so a consumer can answer "what is inside this binary and who built it" without trusting the download server.
Philosophy:
- Minimal surface, maximal proof. One allowed exception (wolfSSL) is pinned, hashed and attested; everything else in-house is versioned by git commit.
- Proof over promise. SBOM, provenance and signatures are generated by the release pipeline in 10-workflow-example.md, never hand-edited.
- Standards first. SPDX and CycloneDX for SBOM, in-toto plus SLSA for provenance, Sigstore/cosign for signing, NIST SSDF for practice grouping.
- Closed by default. A new dependency, an unsigned artifact, or a failing vuln gate blocks the release. Overrides are explicit, logged and expire.
2. Best practices (from research)
- SLSA provenance is verifiable information about where, when and how an artifact was produced, defined as an in-toto attestation predicate with predicateType
https://slsa.dev/provenance/v1, where the build platform attests it produced artifacts by executing a buildDefinition (Source: https://slsa.dev/spec/v1.0/provenance, retrieved 2026-10-23; triangulated by https://slsa.dev/spec/v1.0/about, retrieved 2026-10-23). - The in-toto attestation framework is the envelope: a Statement binds subjects (artifact digests) to a predicateType plus predicate, and SLSA provenance is one predicate type inside it (Source: https://github.com/in-toto/attestation, retrieved 2026-10-23; triangulated by SLSA provenance spec above).
- SPDX (Linux Foundation, ISO/IEC 5962:2021 for SPDX 2.2.1) and CycloneDX (OWASP, ECMA-424) are the two interoperable machine-readable SBOM formats satisfying the NTIA minimum elements: supplier name, component name, version, other unique identifiers, dependency relationship, SBOM author, timestamp (Source: https://spdx.dev/learn/overview/, retrieved 2026-10-23; Source: https://cyclonedx.org/specification/overview/, retrieved 2026-10-23; NTIA element list triangulated by https://github.com/spdx/ntia-conformance-checker, retrieved 2026-10-23). MoloApp emits SPDX JSON as canonical and CycloneDX JSON as secondary.
- Sigstore cosign keyless blob signing (
cosign sign-blobwithout--key) obtains a short-lived certificate from Fulcio via OIDC identity and records the signature in the Rekor transparency log, producing a.sigstore.jsonbundle verified against the expected signer identity (--certificate-identity) and OIDC issuer (Source: https://docs.sigstore.dev/cosign/signing/signing_with_blobs/, retrieved 2026-10-23; triangulated by https://docs.sigstore.dev/about/overview/, retrieved 2026-10-23). - NIST SP 800-218 v1.1 (SSDF, Feb 2022) defines outcome-based secure development practices in four groups: Prepare the Organization (PO), Protect the Software (PS), Produce Well-Secured Software (PW), Respond to Vulnerabilities (RV); it mandates outcomes, not tools (Source: https://csrc.nist.gov/pubs/sp/800/218/final, retrieved 2026-10-23).
- Triangulated release rule from (1)+(4)+(5): a trustworthy release needs all three of SBOM (PW.4.1 lineage), signed provenance from the build platform (PS.3, SLSA Build L2+), and a vulnerability response hook (RV) that blocks or discloses known CVEs before ship. Missing any one fails the gate.
3. Structure
Directories (one class or concern per file, deep over flat):
tools/supply/ release-time only, never linked into the framework
SbomGenerator.hpp/.cpp molo::supply::sbom::Generator (inventory assembly)
SpdxEmitter.hpp/.cpp molo::supply::sbom::SpdxEmitter (SPDX 2.3 JSON)
CycloneDxEmitter.hpp/.cpp molo::supply::sbom::CycloneDxEmitter (CycloneDX 1.6 JSON)
SbomCheck.hpp/.cpp molo::supply::sbom::ConformanceCheck (NTIA elements)
include/molo/supply/
src/supply/
policy/DependencyPolicy.hpp molo::supply::policy::DependencyPolicy (allow-list)
policy/WolfPin.hpp/.cpp molo::supply::policy::WolfPin (version, digest, license receipt)
attest/ProvenanceBuilder.hpp molo::supply::attest::ProvenanceBuilder (SLSA v1 predicate)
attest/Attestor.hpp/.cpp molo::supply::attest::Attestor (in-toto Statement envelope)
attest/Signer.hpp/.cpp molo::supply::attest::Signer (cosign wrapper, keyless first)
attest/Verify.hpp/.cpp molo::supply::attest::Verifier (bundle + digest verify)
scan/VulnHook.hpp/.cpp molo::supply::scan::VulnHook (SBOM in, verdict out)
scan/OsdvClient.hpp/.cpp molo::supply::scan::OsvClient (OSV API query, capped)
sbom/ generated per release, committed as tag asset only
specs/supply.md normative spec mirror (owned by 10-workflow-example.md template)
Namespaces: molo::supply::sbom, ::policy, ::attest, ::scan. No other namespace signs, attests or scans. Signing keys never enter src/; only digests and bundle paths cross into tools/release/ from 10-workflow-example.md.
4. Rules (hard, numbered)
R15-1: wolfSSL is the sole third-party dependency. Any second dependency blocks the build until this spec is amended and the SBOM schema covers it.
R15-2: Every tagged release ships four artifacts minimum: binary or tarball, sbom.spdx.json, sbom.cdx.json, provenance.intoto.jsonl plus one .sigstore.json bundle per signed file. Missing file blocks the tag.
R15-3: SPDX JSON is canonical and must pass NTIA minimum-element conformance; CycloneDX JSON must describe the same component set (same name/version/digest triples).
R15-4: Provenance predicateType is exactly https://slsa.dev/provenance/v1 inside an in-toto Statement; subject digests are SHA-256 over released bytes.
R15-5: Signing is Sigstore keyless first (OIDC identity of the release workflow); long-lived keys are forbidden unless a human-approved exception with expiry exists.
R15-6: The vuln-scan hook runs on the final SBOM before signing; a CRITICAL with a fix available blocks release, others attach as disclosed advisories.
R15-7: wolfSSL is pinned by exact version plus SHA-256 of the vendored tarball plus license receipt path; any mismatch fails the build loudly.
R15-8: Reproducibility: same git commit plus same toolchain record plus same wolfSSL tarball yields byte-identical SBOM component section (timestamps only in metadata, never in digests).
R15-9: No network fetch during normal build. The only network allowed is the release pipeline calling OSV, Fulcio and Rekor, each behind timeout, retry cap and offline fail-closed behavior.
R15-10: Verification is public and offline-capable: molo verify checks digests, bundle chain and provenance subject match using only release assets plus Sigstore roots.
R15-11: All caps in section 6 are static constants. No silent growth of SBOM size, scan window or signature count.
R15-12: This file never duplicates sibling scope: no TLS config (03-security.md), no git/tag mechanics (10-workflow-example.md), no CLI UX (09-cli-ops.md), no audit log schema (12-audit-compliance.md). It provides SBOM, policy verdicts, provenance and bundles those siblings consume.
5. Development guidelines
- Build order follows section 7: policy pin first, then SBOM, then scan hook, then provenance, then signing, then verify. Each step lands with its spec delta and template output checked in as golden files.
- Generators are pure functions over (git commit, toolchain file, wolfSSL pin, file manifest). No timestamps inside hashed content; timestamps live only in SBOM metadata and provenance
buildMetadata.finishedOn. - Treat the SBOM as code: diff it in review, fail CI on unexpected component delta, keep golden SBOMs for the last three releases in
sbom/golden/. - Wrap external CLIs (cosign) behind
Signerwith a fake for tests; never shell out from framework code, only fromtools/supply/. - Log every policy decision with reason code (allow, pin-mismatch, vuln-block, exception-expired) through 02-observability.md; denials are loud, never silent skips.
- License hygiene: wolfSSL commercial license receipt path is recorded in the SBOM supplier field and provenance materials; receipt missing blocks release.
6. Specifications (concrete behaviors, caps, formats)
Dependency policy:
- Allow-list file
supply.allow.json: exactly one entry{name: wolfssl, version: X.Y.Z, sha256: hex, source: vendored-tarball-url-or-path, license: commercial, receipt: path}. Unknown entry or version drift failsmake supply-check. - Toolchain record
supply.toolchain.json: compiler id plus version, linker, CMake or Make version, build flags hash. Max 100 entries, max 64 KB file.
SBOM:
- Formats: SPDX 2.3 JSON (
sbom.spdx.json) canonical, CycloneDX 1.6 JSON (sbom.cdx.json) secondary. Both UTF-8, LF, sorted keys, 2-space indent. - Components:
moloapp(supplier MoloApp, version from VERSION, id git commit),wolfssl(supplier wolfSSL Inc, pinned version, externalRefs: url plus purlpkg:generic/wolfssl@X.Y.Z),toolchain(supplier recorded, version string). Each carries SHA-256 checksum, license declared plus concluded, downloadLocation or NOASSERTION with justification. - NTIA fields mandatory on every component: supplier, name, version, unique id (SPDXID plus purl/CPE where known), relationship (DEPENDS_ON from moloapp), author (
MoloApp release pipeline), timestamp (RFC 3339 UTC). - Caps: max 64 components, max 256 relationships, SBOM JSON max 1 MB per format, component name max 256 chars, version max 64 chars.
Vuln-scan hook:
- Input: canonical SPDX JSON. Query OSV API
https://api.osv.dev/v1/queryper component (purl plus version), timeout 10 s per request, max 64 queries per release, 1 retry, offline yieldsunknownverdict which blocks signing until a human override with 7-day expiry. - Verdicts:
clean,disclosed(non-critical or no fix, attached asadvisories.json),blocked(critical CVSS >= 9.0 with fix, or wolfSSL CVE with fix regardless of score). Blocked stops the pipeline before provenance generation.
Provenance and signing:
- Provenance: in-toto Statement v1,
predicateType: https://slsa.dev/provenance/v1, subjects are{name, digest: {sha256: hex}}per released file,buildDefinition.buildTypeishttps://moloapp.dev/build/v1,externalParametersholds git commit, toolchain hash, wolfSSL pin digest;runDetails.builder.idis the release workflow identity URI;runDetails.metadata.invocationIdis the pipeline run id. - Signing:
cosign sign-blob --yes --bundle <file>.sigstore.json <file>per artifact; verify withcosign verify-blob --bundle --certificate-identity <workflow-id> --certificate-oidc-issuer https://token.actions.githubusercontent.com <file>. SHA-256SUMS file signed as one blob additionally. - Layout per tag
vX.Y.Z:molo-X.Y.Z.tar.gz,SHA256SUMS,sbom.spdx.json,sbom.cdx.json,advisories.json,provenance.intoto.jsonl, plus.sigstore.jsonper file. Max 32 signed files per release. molo verify <dir>: recompute SHA-256, check bundle chain, check provenance subjects match digests, check SBOM component digests match wolfSSL pin; exit 0 verified, 1 mismatch (first mismatch quoted), 2 usage error. No network required.
7. Execution steps (in build order)
E15-1: DependencyPolicy plus WolfPin: allow-list schema, pin check in make supply-check, golden fixtures (good pin, drifted version, bad digest).
E15-2: SbomGenerator plus SpdxEmitter: inventory assembly, canonical JSON, sorted output, NTIA conformance self-check.
E15-3: CycloneDxEmitter plus equivalence test: same triples as SPDX, golden pair diff in CI.
E15-4: VulnHook plus OsvClient: query, verdict mapping, advisories.json writer, offline fail-closed path.
E15-5: ProvenanceBuilder plus Attestor: SLSA v1 predicate, in-toto Statement envelope, subject digest binding.
E15-6: Signer plus Verifier: cosign keyless wrapper, bundle layout, offline molo verify command core.
E15-7: Pipeline wiring into 10-workflow-example.md release order (suite green, SBOM, scan, provenance, sign, tag) and 09-cli-ops.md molo release surface.
E15-8: Hardening: golden SBOMs for three releases, tamper drills (bit-flip, pin drift, expired exception), docs and living-example supply page.
8. Validation (how to verify each step)
V15-1: Pin fixtures: correct tarball passes, one-byte change fails with digest quoted, version bump without allow-list edit fails, missing license receipt fails.
V15-2: SPDX golden test: regenerate twice, byte-identical except timestamp; NTIA checker passes; component count is exactly 3 (moloapp, wolfssl, toolchain) on a clean tree.
V15-3: Equivalence test: extract (name, version, sha256) triples from both SBOMs, sets equal; CycloneDX validates against its JSON schema.
V15-4: Scan matrix: clean SBOM yields clean; fixture with known-fixed critical yields blocked; fixture with no-fix advisory yields disclosed plus advisories.json entry; network cut yields unknown and signing refused.
V15-5: Provenance test: subjects match sha256sum of release files; predicateType exact; builder id equals workflow identity; tampered artifact fails subject match.
V15-6: Sign and verify round-trip against local Sigstore stub plus one manual live run: valid bundle verifies, wrong identity fails, bit-flipped file fails, offline verify works with cached roots.
V15-7: End-to-end dry run on fixture repo: full order executes, a blocked verdict stops before signing, a green run produces all files in the layout with caps respected.
V15-8: Drill suite: expired exception blocks, oversized SBOM (>1 MB) rejected, 33rd signed file rejected, living-example supply page shows SBOM plus verify instructions on a small-phone viewport.
9. References (sibling files this depends on or feeds)
- Depends on 03-security.md: wolfSSL version and TLS posture, hash and RNG primitives for digests, secret redaction in SBOM and provenance.
- Depends on 09-cli-ops.md:
molo release,molo verify,molo versionUX, embedder manifest hash reuse, exit-code mapping. - Depends on 10-workflow-example.md: release pipeline order, tag gating, VERSION and CHANGELOG linkage, spec and test templates.
- Depends on 02-observability.md: structured logs and metrics for policy verdicts and scan outcomes.
- Feeds 12-audit-compliance.md: SBOM, provenance, bundles and advisories as audit evidence; retention pointers.
- Feeds 14-api-governance.md: SBOM and provenance as governed release contracts (formats versioned, breaking changes major).
- Feeds 11-tenancy.md and 13-operability.md: per-tenant build identity inputs and SBOM exchange notes (formats defined here, transport there).
- Never duplicates: 10-workflow-example.md owns git mechanics, 09-cli-ops.md owns CLI flags, 12-audit-compliance.md owns audit retention.
10. Open questions
Q1: SLSA Build L3 (hardened builder, non-falsifiable provenance) in v1 or L2 first with a documented L3 path? Proposal: L2 now, L3 tracked as gap. Q2: OSV only, or OSV plus a second feed (wolfSSL security list, CISA KEV) for the vuln hook? Proposal: OSV plus wolfSSL advisory check, KEV later. Q3: Rekor transparency proof required at verify time, or bundle signature plus identity sufficient for v1? Proposal: bundle sufficient, checkpoint proof optional flag. Q4: SPDX 3.0 migration timeline? Proposal: stay on SPDX 2.3 JSON until tooling converges, track 3.0 as gap.
11. Sources (exact URLs with retrieval dates)
- SLSA Provenance specification v1.0 (predicateType, model, purpose): https://slsa.dev/spec/v1.0/provenance (retrieved 2026-10-23)
- SLSA About page (SSDF link, supply-chain rationale): https://slsa.dev/spec/v1.0/about (retrieved 2026-10-23)
- in-toto Attestation Framework repository (Statement, predicate model): https://github.com/in-toto/attestation (retrieved 2026-10-23)
- SPDX Project overview (formats, ISO standard): https://spdx.dev/learn/overview/ (retrieved 2026-10-23)
- CycloneDX Specification Overview (object model, ECMA-424): https://cyclonedx.org/specification/overview/ (retrieved 2026-10-23)
- Sigstore cosign Signing Blobs (keyless sign-blob, bundles): https://docs.sigstore.dev/cosign/signing/signing_with_blobs/ (retrieved 2026-10-23)
- NIST SP 800-218 SSDF v1.1 project page (PO, PS, PW, RV practice groups): https://csrc.nist.gov/pubs/sp/800/218/final (retrieved 2026-10-23)