How to Add Build Provenance With attest-build-provenance
actions/attest-build-provenance produces a signed SLSA provenance statement binding an artifact to the build that made it.
After building, pass the artifact path or image digest to actions/attest-build-provenance. It signs a SLSA provenance predicate with the workflow OIDC identity and stores it as a GitHub artifact attestation.
Steps
- Grant
id-token: writeandattestations: writeto the job. - Build the artifact or push the image and capture its digest.
- Call
actions/attest-build-provenancewithsubject-pathorsubject-digest.
Workflow
jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write
attestations: write
steps:
- uses: actions/checkout@v4
- run: make build
- uses: actions/attest-build-provenance@v1
with:
subject-path: 'dist/app.tar.gz'Gotchas
- The job needs both
id-token: writeandattestations: write, or the attestation call fails. - For images, prefer
subject-digestplussubject-nameso the attestation binds to the exact digest.
Verify it actually works
A workflow that runs is not a workflow that works. Confirm the behaviour on a real event rather than on a manual dispatch, because trigger conditions, permissions, and context values all differ between the two.
# 1. validate the file before pushing
docker run --rm -v "$(pwd):/repo" --workdir /repo rhysd/actionlint:latest -color
# 2. trigger the real event, not workflow_dispatch
git commit --allow-empty -m "ci: verify trigger" && git push
# 3. watch it and read the conclusion, not just the colour
gh run watch
gh run view --log-failedWhat usually goes wrong first
- The workflow file must exist on the default branch before scheduled or dispatch triggers appear at all.
GITHUB_TOKENpermissions default to read-only in many organisations. Declare apermissions:block listing every scope the job needs.- Fork pull requests get a read-only token and no access to secrets, regardless of workflow configuration.
actions/checkoutgives you depth 1 on a detached HEAD, so anything needing history or a branch name needsfetch-depth: 0.