From 88038c33ebd8aa1818ea1b58eefef248d155cd5c Mon Sep 17 00:00:00 2001 From: hyperpolymath <6759885+hyperpolymath@users.noreply.github.com> Date: Thu, 25 Jun 2026 09:15:46 +0100 Subject: [PATCH] feat(ci): attest build provenance Add GitHub native build-provenance attestation to the GHCR publish workflow. The image is built and pushed with nerdctl, which has no --digestfile; the real sha256 digest is read back from the registry with skopeo after push and bound to the attestation via actions/attest-build-provenance. Co-Authored-By: Claude Opus 4.8 --- .github/workflows/ghcr-publish.yml | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/.github/workflows/ghcr-publish.yml b/.github/workflows/ghcr-publish.yml index 6153f26..d55dc07 100644 --- a/.github/workflows/ghcr-publish.yml +++ b/.github/workflows/ghcr-publish.yml @@ -19,6 +19,8 @@ jobs: permissions: contents: read packages: write + id-token: write # mint the OIDC token the attestation is signed with + attestations: write # write the build-provenance attestation (the "claim") steps: - name: Checkout repository @@ -49,9 +51,28 @@ jobs: sudo nerdctl tag ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }} ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest - name: Push image + id: push run: | sudo nerdctl push ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }} sudo nerdctl push ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest + # nerdctl push has no --digestfile, so read the real sha256 back from + # the registry with skopeo (pre-installed on ubuntu-latest). This is + # the digest the registry actually holds for the pushed tag. + DIGEST="$(skopeo inspect --format '{{.Digest}}' \ + --creds "${{ github.actor }}:${{ secrets.GITHUB_TOKEN }}" \ + docker://${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }})" + echo "digest=$DIGEST" >> "$GITHUB_OUTPUT" + + # GitHub native artifact attestation (build provenance) for the pushed + # image. Verify with: + # gh attest verify oci://ghcr.io/${{ github.repository }}: \ + # --repo ${{ github.repository }} + - name: Attest container provenance + uses: actions/attest-build-provenance@e8998f949152b193b063cb0ec769d69d929409be # v2 + with: + subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + subject-digest: ${{ steps.push.outputs.digest }} + push-to-registry: true - name: Tag release version if: github.event_name == 'release'