feat(supply-chain): SLSA Build L3 provenance + npm provenance (#3)#29
Merged
Conversation
Add SLSA build provenance generation, end-to-end provenance verification, and npm-native publish provenance on top of the cosign signing wired up in #2. What ships in this change: - .github/workflows/release.yml — goreleaser job now exposes a hashes output (base64 of checksums.txt, which is already in the <sha256> <filename> format slsa-github-generator expects); new provenance job calls the canonical slsa-framework/slsa-github-generator generic_slsa3 reusable workflow pinned at v2.0.0, which produces cronix-<tag>.intoto.jsonl and uploads it to the GitHub release; new verify-provenance job installs slsa-verifier and verifies the produced attestation against every binary and the checksum file, failing the workflow if anything does not verify. Catches "we generated provenance for the wrong subject set" or "the reusable workflow contract changed" before a release ships out the door silently. - .github/workflows/release.yml — npm job adds --provenance to pnpm publish so every @awbx/cronix-* package carries an npm-native attestation bound to the same workflow identity. No new permission needed; id-token: write was already added at the workflow level in #2. - .goreleaser.yaml — release.footer extends to cover SLSA, npm provenance, and the previously-shipped cosign verification, so every release page surfaces all three verification routes inline. - README.md — §Verify a release rewritten to cover all three attestation channels (cosign, SLSA, npm) with explicit "wrong identity" guidance. Calls out that SLSA verify-artifact is the canonical CI check because it fails closed if source repo, tag, or artifact hash diverge. Out of scope: - syft SBOM attached to every release (#4) — different tool, output, and verification story; warrants its own PR. - arm64 image manifest list (#5) — pre-existing gap; needs a docker_manifests block in .goreleaser.yaml. - Promoting the release to "draft" until SLSA verification passes and then flipping it public. Cleaner failure semantics but a meaningful workflow restructure; defer to follow-up. Signed-off-by: Abdelhadi Sabani <asabani.work@gmail.com>
awbx
added a commit
that referenced
this pull request
May 19, 2026
Add SLSA build provenance generation, end-to-end provenance verification, and npm-native publish provenance on top of the cosign signing wired up in #2. What ships in this change: - .github/workflows/release.yml — goreleaser job now exposes a hashes output (base64 of checksums.txt, which is already in the <sha256> <filename> format slsa-github-generator expects); new provenance job calls the canonical slsa-framework/slsa-github-generator generic_slsa3 reusable workflow pinned at v2.0.0, which produces cronix-<tag>.intoto.jsonl and uploads it to the GitHub release; new verify-provenance job installs slsa-verifier and verifies the produced attestation against every binary and the checksum file, failing the workflow if anything does not verify. Catches "we generated provenance for the wrong subject set" or "the reusable workflow contract changed" before a release ships out the door silently. - .github/workflows/release.yml — npm job adds --provenance to pnpm publish so every @awbx/cronix-* package carries an npm-native attestation bound to the same workflow identity. No new permission needed; id-token: write was already added at the workflow level in #2. - .goreleaser.yaml — release.footer extends to cover SLSA, npm provenance, and the previously-shipped cosign verification, so every release page surfaces all three verification routes inline. - README.md — §Verify a release rewritten to cover all three attestation channels (cosign, SLSA, npm) with explicit "wrong identity" guidance. Calls out that SLSA verify-artifact is the canonical CI check because it fails closed if source repo, tag, or artifact hash diverge. Out of scope: - syft SBOM attached to every release (#4) — different tool, output, and verification story; warrants its own PR. - arm64 image manifest list (#5) — pre-existing gap; needs a docker_manifests block in .goreleaser.yaml. - Promoting the release to "draft" until SLSA verification passes and then flipping it public. Cleaner failure semantics but a meaningful workflow restructure; defer to follow-up. Signed-off-by: Abdelhadi Sabani <asabani.work@gmail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #3.
Summary
Adds SLSA Build L3 provenance generation on top of the cosign signing from #2, plus npm-native publish provenance for the TypeScript packages. Every release now ships three independent attestation channels, all bound to this repository's GitHub Actions release workflow identity:
What changes
Why the smoke verify
The slsa-github-generator reusable workflow is well-tested upstream but its inputs are repo-specific (base64-encoded checksum file, expected subject set). A subtle bug — e.g., GoReleaser changing the columns in checksums.txt, or a future GoReleaser bump producing artifacts that don't match my `shopt -s nullglob` patterns — would silently ship provenance that nobody can verify against the artifacts users download. The smoke job runs the actual `slsa-verifier verify-artifact` call against every published artifact, on the runner, immediately after publish. If it can't verify, the release workflow fails red and the user gets paged at the first broken release, not the first time an adopter tries to verify it.
Out of scope
Test plan
First real validation
The first tagged release after merge. On that release:
Version pins worth knowing