ci(release): generate provenance in an isolated reusable workflow (SLSA L3) - #45
Merged
Merged
Conversation
…SA L3) Move artifact provenance out of the build jobs into a reusable workflow (.github/workflows/attest.yml). A reusable workflow runs with its own OIDC identity that the calling build steps cannot reach, which is the SLSA Build L3 requirement; in-job attestations are only L2. Provenance still lives on GitHub's attestation API (gh attestation verify keeps working) — the signer-workflow is now attest.yml. - attest.yml (new, workflow_call): one isolated `attest` job that does binary checksums (actions/attest --subject-checksums) and OCI provenance (actions/attest-build-provenance, used for both the image and the chart). - release.yml: drop the three inline `actions/attest` provenance steps; add attest-binaries / attest-image / attest-chart caller jobs (the user's Option A: the Helm chart provenance is isolated too). binary-release-assets now uploads checksums.txt as an artifact for the binary caller; keyless cosign + the syft image SBOM attestation stay inline (separate controls, not the SLSA provenance). - Every caller grants packages: write — a reusable workflow cannot request more than its caller, and the shared attest job declares it for the image/chart push-to-registry; attest.yml carries its own GHCR login since the build job's login does not cross the reusable-workflow boundary. - charts/template-k8s/values.yaml: flip the Kyverno trusted signer attestor.subjectRegExp from release.yml to attest.yml, in lockstep with where provenance is now signed. attest-build-provenance emits the same slsa.dev/provenance/v1 predicate + actions/buildtypes/workflow/v1 buildType the policy already requires, so only the signer identity changes. The chart-render test (test/chart/rbac_test.go) is updated to expect the attest.yml signer. - Release inspection summary: gh attestation verify now points at attest.yml for binaries/image/chart; cosign verify stays release.yml (cosign signer unchanged). - DELETE_ME: document attest.yml as the provenance signer and the Kyverno coupling. The attest.yml path is unreachable by the dry-run (which never attests) — only a real release tag exercises it, so a throwaway-tag rehearsal is the final check. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
jmgilman
force-pushed
the
ci/slsa-l3-provenance
branch
from
June 28, 2026 22:02
41184f1 to
f8b2696
Compare
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.
Summary
Moves artifact provenance out of the build jobs into a reusable workflow
(
.github/workflows/attest.yml) so the signing OIDC identity is unreachable bythe build steps — the SLSA Build L3 requirement. Provenance still lives on
GitHub's attestation API (
gh attestation verifykeeps working); thesigner-workflow is now
attest.yml. This is PR3 of the template-go-apisession-015 reproduction (mise → melange/apko → SLSA L3 → skills/docs).
attest.yml(new,workflow_call): one isolatedattestjob — binarychecksums (
actions/attest --subject-checksums) + OCI provenance(
actions/attest-build-provenance@v4.1.1, for both the image and the chart).Carries its own GHCR login (the build job's login doesn't cross the
reusable-workflow boundary).
release.yml: drop the 3 inlineactions/attestprovenance steps; addattest-binaries/attest-image/attest-chartcallers (Option A — theHelm chart provenance is isolated too). Keyless cosign + the syft image
SBOM attestation stay inline (separate controls). Every caller grants
packages: write(a reusable workflow can't request more than its caller).values.yamlattestor.subjectRegExprelease.yml→attest.yml, in lockstep with where provenance is now signed.attest-build-provenanceemits the sameslsa.dev/provenance/v1predicate +buildtypes/workflow/v1buildType the policy already requires, so only thesigner identity changes.
gh attestation verify→attest.ymlfor binaries/image/chart;cosign verifystaysrelease.yml. DELETE_ME documents the coupling.Testing
moon run root:checkgreen;helm template --set kyverno.imageVerification.enabled=truenow renders the policy trusting
attest.ymlwith the unchangedtype/buildType.
v0.1.2image attestation carriesslsa.dev/provenance/v1+buildtypes/workflow/v1— exactly whatattest-build-provenanceproduces, so the Kyverno predicate contract ispreserved.
signer/predicate alignment, job-graph completeness) returned zero findings.
attest.ymlis unreachable by the dry-run (which never attests); only a realrelease tag exercises it, so a throwaway-tag rehearsal is the final check.
🤖 Generated with Claude Code