Skip to content

Commit 71dc119

Browse files
feat(ci): attest build provenance (#60)
## Estate attestation rollout Adds GitHub native build-provenance attestation to `.github/workflows/ghcr-publish.yml`. **Push mechanism:** nerdctl (`nerdctl build` + `nerdctl push` to ghcr.io), image `ghcr.io/${{ github.repository }}`. **How the digest is obtained:** `nerdctl push` has no `--digestfile` flag, so immediately after the push the workflow reads the real `sha256:...` digest back from the registry with `skopeo inspect --format '{{.Digest}}'` (skopeo is pre-installed on `ubuntu-latest`), authenticating with the same `GITHUB_TOKEN`. That digest is exported as the `push` step output and fed to the attestation as `subject-digest` — it is the exact digest the registry holds for the pushed tag, not a guess. **Changes:** - Added `id-token: write` + `attestations: write` to the job permissions. - Captured the pushed digest via `skopeo inspect`. - Added an `actions/attest-build-provenance@e8998f94…` (v2, pinned) step with `push-to-registry: true`. Verify with: ``` gh attest verify oci://ghcr.io/hyperpolymath/zerostep:<tag> --repo hyperpolymath/zerostep ``` 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 7ed70f7 commit 71dc119

1 file changed

Lines changed: 21 additions & 0 deletions

File tree

.github/workflows/ghcr-publish.yml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ jobs:
1919
permissions:
2020
contents: read
2121
packages: write
22+
id-token: write # mint the OIDC token the attestation is signed with
23+
attestations: write # write the build-provenance attestation (the "claim")
2224

2325
steps:
2426
- name: Checkout repository
@@ -49,9 +51,28 @@ jobs:
4951
sudo nerdctl tag ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }} ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
5052
5153
- name: Push image
54+
id: push
5255
run: |
5356
sudo nerdctl push ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}
5457
sudo nerdctl push ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
58+
# nerdctl push has no --digestfile, so read the real sha256 back from
59+
# the registry with skopeo (pre-installed on ubuntu-latest). This is
60+
# the digest the registry actually holds for the pushed tag.
61+
DIGEST="$(skopeo inspect --format '{{.Digest}}' \
62+
--creds "${{ github.actor }}:${{ secrets.GITHUB_TOKEN }}" \
63+
docker://${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }})"
64+
echo "digest=$DIGEST" >> "$GITHUB_OUTPUT"
65+
66+
# GitHub native artifact attestation (build provenance) for the pushed
67+
# image. Verify with:
68+
# gh attest verify oci://ghcr.io/${{ github.repository }}:<tag> \
69+
# --repo ${{ github.repository }}
70+
- name: Attest container provenance
71+
uses: actions/attest-build-provenance@e8998f949152b193b063cb0ec769d69d929409be # v2
72+
with:
73+
subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
74+
subject-digest: ${{ steps.push.outputs.digest }}
75+
push-to-registry: true
5576

5677
- name: Tag release version
5778
if: github.event_name == 'release'

0 commit comments

Comments
 (0)