Skip to content

Commit a02b3ba

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

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
@@ -16,6 +16,8 @@ jobs:
1616
permissions:
1717
contents: read
1818
packages: write
19+
id-token: write # mint the OIDC token the attestation is signed with
20+
attestations: write # write the build-provenance attestation (the "claim")
1921
steps:
2022
- name: Checkout repository
2123
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4
@@ -41,9 +43,27 @@ jobs:
4143
sudo nerdctl build -f Containerfile -t ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }} .
4244
sudo nerdctl tag ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }} ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
4345
- name: Push image
46+
id: push
4447
run: |
4548
sudo nerdctl push ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}
4649
sudo nerdctl push ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
50+
# nerdctl push has no --digestfile, so read the real sha256 back from
51+
# the registry with skopeo (pre-installed on ubuntu-latest). This is
52+
# the digest the registry actually holds for the pushed tag.
53+
DIGEST="$(skopeo inspect --format '{{.Digest}}' \
54+
--creds "${{ github.actor }}:${{ secrets.GITHUB_TOKEN }}" \
55+
docker://${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }})"
56+
echo "digest=$DIGEST" >> "$GITHUB_OUTPUT"
57+
# GitHub native artifact attestation (build provenance) for the pushed
58+
# image. Verify with:
59+
# gh attest verify oci://ghcr.io/${{ github.repository }}:<tag> \
60+
# --repo ${{ github.repository }}
61+
- name: Attest container provenance
62+
uses: actions/attest-build-provenance@e8998f949152b193b063cb0ec769d69d929409be # v2
63+
with:
64+
subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
65+
subject-digest: ${{ steps.push.outputs.digest }}
66+
push-to-registry: true
4767
- name: Tag release version
4868
if: github.event_name == 'release'
4969
run: |

0 commit comments

Comments
 (0)