Skip to content

Commit b6c815e

Browse files
feat(ci): attest build provenance (#101)
## 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/wokelang:<tag> --repo hyperpolymath/wokelang ``` 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 5e5d116 commit b6c815e

1 file changed

Lines changed: 20 additions & 0 deletions

File tree

.github/workflows/ghcr-publish.yml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ jobs:
1515
permissions:
1616
contents: read
1717
packages: write
18+
id-token: write # mint the OIDC token the attestation is signed with
19+
attestations: write # write the build-provenance attestation (the "claim")
1820
steps:
1921
- name: Checkout repository
2022
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4
@@ -40,9 +42,27 @@ jobs:
4042
sudo nerdctl build -f Containerfile -t ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }} .
4143
sudo nerdctl tag ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }} ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
4244
- name: Push image
45+
id: push
4346
run: |
4447
sudo nerdctl push ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}
4548
sudo nerdctl push ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
49+
# nerdctl push has no --digestfile, so read the real sha256 back from
50+
# the registry with skopeo (pre-installed on ubuntu-latest). This is
51+
# the digest the registry actually holds for the pushed tag.
52+
DIGEST="$(skopeo inspect --format '{{.Digest}}' \
53+
--creds "${{ github.actor }}:${{ secrets.GITHUB_TOKEN }}" \
54+
docker://${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }})"
55+
echo "digest=$DIGEST" >> "$GITHUB_OUTPUT"
56+
# GitHub native artifact attestation (build provenance) for the pushed
57+
# image. Verify with:
58+
# gh attest verify oci://ghcr.io/${{ github.repository }}:<tag> \
59+
# --repo ${{ github.repository }}
60+
- name: Attest container provenance
61+
uses: actions/attest-build-provenance@e8998f949152b193b063cb0ec769d69d929409be # v2
62+
with:
63+
subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
64+
subject-digest: ${{ steps.push.outputs.digest }}
65+
push-to-registry: true
4666
- name: Tag release version
4767
if: github.event_name == 'release'
4868
run: |

0 commit comments

Comments
 (0)