Skip to content

Tier-1 build-pipeline hardening: GCS Nix cache + self-managed signing/provenance#189

Merged
mdheller merged 4 commits into
mainfrom
nix-binary-cache
Jun 22, 2026
Merged

Tier-1 build-pipeline hardening: GCS Nix cache + self-managed signing/provenance#189
mdheller merged 4 commits into
mainfrom
nix-binary-cache

Conversation

@mdheller

@mdheller mdheller commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

Two Tier-1 build-pipeline improvements that share scripts/build-custom-image.sh.

1. GCS-backed Nix binary cache (replaces sunset magic-nix-cache)

magic-nix-cache is sunset by Determinate and threw 418 / ResourceExhausted throttling — during the desktop build it produced ~1,571 disabled-substituter errors. Cold builds also rebuild every path.

  • .github/actions/setup-nix — composite: installs Nix + (when NIX_CACHE_URL/NIX_CACHE_PUBKEY vars are set) adds the GCS HTTPS prefix as an extra substituter. Graceful — no vars → just Nix + cache.nixos.org.
  • scripts/nix-cache-push.sh — best-effort push of built closures to gs://<bucket>/nix-cache (signed file:// copy → gsutil rsync). Called by build-custom-image.sh, so both the GitHub and GCP lanes seed the cache → later custom builds pull the heavy edition base warm.
  • Swapped all 5 workflows; every magic-nix-cache use removed.
  • docs/NIX_CACHE_SETUP.md.

2. Self-managed signing + provenance (NO third-party authority)

No Apple Developer ID, no Google/Play signing, no notarization — a self-sovereign ed25519 minisign keypair we generate ourselves.

  • scripts/sign-and-provenance.sh — signs each artifact (graceful no-op without the key), emits an in-toto Statement, a SLSA v1 provenance predicate, a Nix-closure SBOM, and for ISOs a sourceos-spec v2 OSImage doc whose provenance refs resolve to all of it. The OSImage output is validated against schemas.srcos.ai/v2/OSImage.json with ajv.
  • scripts/verify-image.sh — anyone-can-verify with the public key; cross-checks the in-toto subject digest. Tested: good → verified, tampered → rejected.
  • build-custom.yml + GCP startup script pass the key (+ version, + cache) through; docs/SIGNING_SETUP.md covers one-time keygen (minisign -W) and publishing the pubkey.

One-time setup before either turns on: see docs/NIX_CACHE_SETUP.md and docs/SIGNING_SETUP.md (generate keys, set the vars/secrets). Until then everything no-ops safely — nothing breaks.

Validation: all YAML valid, bash -n clean, sign+verify round-trip + schema-validation run locally.

mdheller added 2 commits June 22, 2026 13:31
magic-nix-cache (Determinate-sunset) threw 418/ResourceExhausted throttling on
large builds — it disabled the substituter mid-run during the desktop build.
Replace it everywhere with a persistent cache:
- .github/actions/setup-nix: composite that installs Nix + (if NIX_CACHE_URL/
  PUBKEY vars set) adds the GCS HTTPS prefix as a substituter. Graceful: with no
  vars it just falls back to cache.nixos.org (already more reliable than before).
- scripts/nix-cache-push.sh: best-effort push of built closures to
  gs://<bucket>/nix-cache via signed file:// copy + gsutil rsync (no-op without
  NIX_CACHE_BUCKET/SECRET_KEY). build-custom-image.sh calls it after each build,
  so both the GitHub and GCP lanes seed the cache → later custom builds pull warm.
- swapped all 5 workflows (release-images, build-custom, image-tests,
  nix-build-images, nix-ci) onto the composite; removed every magic-nix-cache use.
- docs/NIX_CACHE_SETUP.md: one-time setup (keypair, public prefix, vars/secret).
All YAML + scripts validate.
Every built image now gets a self-sovereign signature + provenance bundle —
NO third-party signing authority (no Apple Developer ID, no Google/Play signing,
no notarization). The key is an ed25519 minisign keypair we generate ourselves.

scripts/sign-and-provenance.sh (best-effort, never fails the build):
- minisign-signs each artifact with SOURCEOS_SIGN_SECRET_KEY (graceful no-op
  without it — still emits unsigned provenance). Falls back to `nix run
  nixpkgs#minisign` when minisign isn't on PATH.
- emits an in-toto Statement (statementRef urn:srcos:attestation:…), a SLSA v1
  provenance predicate (slsaPredicateRef urn:srcos:slsa:…), a Nix-closure SBOM,
  and for ISOs a sourceos-spec v2 OSImage doc whose provenance refs resolve to
  the above. OSImage validated against schemas.srcos.ai/v2/OSImage.json (ajv).
- build-custom-image.sh calls it after the build and uploads the sidecars; the
  GCP lane passes the key (+version, +cache) via instance metadata.
scripts/verify-image.sh: anyone-can-verify with the public key; also cross-checks
the in-toto subject digest. Tampered artifacts are rejected (tested).
build-custom.yml: SOURCEOS_SIGN_SECRET_KEY secret + SOURCEOS_SIGN_PUBKEY var +
VERSION/SOURCE_REV. docs/SIGNING_SETUP.md: one-time keygen (minisign -W) + publish.

Closes the gap where OSImage.provenance had no real attestation behind it.
@mdheller mdheller changed the title Replace sunset magic-nix-cache with a GCS-backed Nix binary cache Tier-1 build-pipeline hardening: GCS Nix cache + self-managed signing/provenance Jun 22, 2026
mdheller added 2 commits June 22, 2026 13:45
Pre-existing failure on main: 57c9cab added `lib.mkForce` to
hosts/exit-x86_64/default.nix's `sourceos.mesh.role = "exit"` to resolve a
NixOS assertion conflict, but the contract grep matched the literal
`role = "exit"` and so broke. Make the grep tolerate the optional mkForce
wrapper — it validates the role value, not the exact syntax. Was blocking
nix flake check on every PR.
Second pre-existing nix-ci failure, previously masked by the exit-contract
failure: `shellcheck -S warning` flagged LIMA_KEY/IS_INTERNAL (deploy-stage2.sh)
and EFI_SIZE (install-on-device.sh) as unused. These are intentional diagnostic
probes in destructive disk scripts; annotate with shellcheck disable=SC2034
rather than touch the control flow. Verified clean with shellcheck 0.11.0.
@mdheller mdheller merged commit 69ed0ae into main Jun 22, 2026
6 checks passed
@mdheller mdheller deleted the nix-binary-cache branch June 22, 2026 22:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant