From 369a21f09603235f6c6c298dfed21ae7a82bebf3 Mon Sep 17 00:00:00 2001 From: hyperpolymath <6759885+hyperpolymath@users.noreply.github.com> Date: Thu, 25 Jun 2026 09:15:40 +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 | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/.github/workflows/ghcr-publish.yml b/.github/workflows/ghcr-publish.yml index d5d0b9c..ea35758 100644 --- a/.github/workflows/ghcr-publish.yml +++ b/.github/workflows/ghcr-publish.yml @@ -16,6 +16,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 uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4 @@ -41,9 +43,27 @@ jobs: sudo nerdctl build -f Containerfile -t ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }} . 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' run: |