From d61cdd81dc2b835c90bc7d42c2c9b60eb5e74af0 Mon Sep 17 00:00:00 2001 From: Behnam Mozafari Date: Wed, 6 May 2026 13:46:24 +1000 Subject: [PATCH 01/10] UID2-6764: emit SLSA provenance for non-Java docker images Co-Authored-By: Claude Sonnet 4.6 --- actions/shared_publish_to_docker/action.yaml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/actions/shared_publish_to_docker/action.yaml b/actions/shared_publish_to_docker/action.yaml index 295ee6d9..d24dae83 100644 --- a/actions/shared_publish_to_docker/action.yaml +++ b/actions/shared_publish_to_docker/action.yaml @@ -90,6 +90,7 @@ runs: scan_type: ${{ inputs.scan_type }} - name: Push to Docker + id: push uses: docker/build-push-action@ca052bb54ab0790a636c9b5f226502c73d547a25 # v5 with: context: ${{ inputs.docker_context }} @@ -100,3 +101,13 @@ runs: build-args: | JAR_VERSION=${{ inputs.new_version }} IMAGE_VERSION=${{ inputs.new_version }} + + - name: Attest build provenance + if: ${{ inputs.not_snapshot == 'true' }} + uses: actions/attest@59d89421af93a897026c735860bf21b6eb4f7b26 # v4.1.0 + env: + NODE_OPTIONS: --max-http-header-size=32768 + with: + subject-name: ${{ inputs.docker_registry }}/${{ inputs.docker_image_name }} + subject-digest: ${{ steps.push.outputs.digest }} + push-to-registry: true From c8fbbaf2b585916b00630f2eea1c9710a7a85dec Mon Sep 17 00:00:00 2001 From: Behnam Mozafari Date: Wed, 6 May 2026 13:47:24 +1000 Subject: [PATCH 02/10] UID2-6764: grant id-token and attestations write to non-Java publish workflow --- .github/workflows/shared-publish-to-docker-versioned.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/shared-publish-to-docker-versioned.yaml b/.github/workflows/shared-publish-to-docker-versioned.yaml index 942b4953..18e88698 100644 --- a/.github/workflows/shared-publish-to-docker-versioned.yaml +++ b/.github/workflows/shared-publish-to-docker-versioned.yaml @@ -51,6 +51,8 @@ jobs: security-events: write packages: write pull-requests: write + id-token: write + attestations: write steps: - name: Setup id: setup From 11649c6f25fdd903a59ad6d5833ef65717e0d8cb Mon Sep 17 00:00:00 2001 From: Behnam Mozafari Date: Wed, 6 May 2026 13:48:37 +1000 Subject: [PATCH 03/10] UID2-6764: emit SLSA provenance for Java docker images --- .../shared-publish-java-to-docker-versioned.yaml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/.github/workflows/shared-publish-java-to-docker-versioned.yaml b/.github/workflows/shared-publish-java-to-docker-versioned.yaml index 36bad1ec..9f3989fd 100644 --- a/.github/workflows/shared-publish-java-to-docker-versioned.yaml +++ b/.github/workflows/shared-publish-java-to-docker-versioned.yaml @@ -66,6 +66,8 @@ jobs: security-events: write packages: write pull-requests: write + id-token: write + attestations: write outputs: jar_version: ${{ steps.version.outputs.new_version }} image_tag: ${{ steps.updatePom.outputs.image_tag }} @@ -203,6 +205,7 @@ jobs: scan_type: image - name: Push to Docker + id: push uses: docker/build-push-action@ca052bb54ab0790a636c9b5f226502c73d547a25 # v5 with: context: ${{inputs.working_dir}} @@ -213,6 +216,16 @@ jobs: JAR_VERSION=${{ steps.version.outputs.new_version }} IMAGE_VERSION=${{ steps.version.outputs.new_version }} + - name: Attest build provenance + if: ${{ steps.checkRelease.outputs.not_snapshot == 'true' }} + uses: actions/attest@59d89421af93a897026c735860bf21b6eb4f7b26 # v4.1.0 + env: + NODE_OPTIONS: --max-http-header-size=32768 + with: + subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}${{ inputs.append_image_name }} + subject-digest: ${{ steps.push.outputs.digest }} + push-to-registry: true + - name: Build Changelog id: github_release if: ${{ steps.checkRelease.outputs.is_release == 'true' }} From 80a5560c68dd667db3a028cc0795a1c58895ea8f Mon Sep 17 00:00:00 2001 From: Behnam Mozafari Date: Fri, 8 May 2026 13:59:58 +1000 Subject: [PATCH 04/10] UID2-6764: don't fail release on attestation error Attestation runs after the docker push but before the changelog/release steps. Without continue-on-error, an attest failure leaves a half-finished release: image pushed, no GitHub Release created. Tolerate attest failures during the v3 rollout so consumers aren't stuck mid-release if attestation breaks. Co-Authored-By: Claude Opus 4.7 (1M context) --- .github/workflows/shared-publish-java-to-docker-versioned.yaml | 1 + actions/shared_publish_to_docker/action.yaml | 1 + 2 files changed, 2 insertions(+) diff --git a/.github/workflows/shared-publish-java-to-docker-versioned.yaml b/.github/workflows/shared-publish-java-to-docker-versioned.yaml index 9f3989fd..c44277fa 100644 --- a/.github/workflows/shared-publish-java-to-docker-versioned.yaml +++ b/.github/workflows/shared-publish-java-to-docker-versioned.yaml @@ -219,6 +219,7 @@ jobs: - name: Attest build provenance if: ${{ steps.checkRelease.outputs.not_snapshot == 'true' }} uses: actions/attest@59d89421af93a897026c735860bf21b6eb4f7b26 # v4.1.0 + continue-on-error: true env: NODE_OPTIONS: --max-http-header-size=32768 with: diff --git a/actions/shared_publish_to_docker/action.yaml b/actions/shared_publish_to_docker/action.yaml index d24dae83..9384e112 100644 --- a/actions/shared_publish_to_docker/action.yaml +++ b/actions/shared_publish_to_docker/action.yaml @@ -105,6 +105,7 @@ runs: - name: Attest build provenance if: ${{ inputs.not_snapshot == 'true' }} uses: actions/attest@59d89421af93a897026c735860bf21b6eb4f7b26 # v4.1.0 + continue-on-error: true env: NODE_OPTIONS: --max-http-header-size=32768 with: From 7a55c464970937225340620e87cdbf86ec5b7ba5 Mon Sep 17 00:00:00 2001 From: Behnam Mozafari Date: Fri, 8 May 2026 14:11:33 +1000 Subject: [PATCH 05/10] Revert "UID2-6764: don't fail release on attestation error" This reverts commit 80a5560c68dd667db3a028cc0795a1c58895ea8f. --- .github/workflows/shared-publish-java-to-docker-versioned.yaml | 1 - actions/shared_publish_to_docker/action.yaml | 1 - 2 files changed, 2 deletions(-) diff --git a/.github/workflows/shared-publish-java-to-docker-versioned.yaml b/.github/workflows/shared-publish-java-to-docker-versioned.yaml index c44277fa..9f3989fd 100644 --- a/.github/workflows/shared-publish-java-to-docker-versioned.yaml +++ b/.github/workflows/shared-publish-java-to-docker-versioned.yaml @@ -219,7 +219,6 @@ jobs: - name: Attest build provenance if: ${{ steps.checkRelease.outputs.not_snapshot == 'true' }} uses: actions/attest@59d89421af93a897026c735860bf21b6eb4f7b26 # v4.1.0 - continue-on-error: true env: NODE_OPTIONS: --max-http-header-size=32768 with: diff --git a/actions/shared_publish_to_docker/action.yaml b/actions/shared_publish_to_docker/action.yaml index 9384e112..d24dae83 100644 --- a/actions/shared_publish_to_docker/action.yaml +++ b/actions/shared_publish_to_docker/action.yaml @@ -105,7 +105,6 @@ runs: - name: Attest build provenance if: ${{ inputs.not_snapshot == 'true' }} uses: actions/attest@59d89421af93a897026c735860bf21b6eb4f7b26 # v4.1.0 - continue-on-error: true env: NODE_OPTIONS: --max-http-header-size=32768 with: From 9c2bb4dc4a28aad0bf9dd6f2bb9d80d2842c8025 Mon Sep 17 00:00:00 2001 From: Behnam Mozafari Date: Fri, 8 May 2026 17:19:54 +1000 Subject: [PATCH 06/10] UID2-6764: extract attest_image action; add verify step + smoke test Addresses jon8787's review comments on PR #228: - #2 verify step: attest_image now calls 'gh attestation verify' immediately after signing so misconfigured signatures fail at build time, not consumer pull time. - #3 case sensitivity: lowercase the image ref once and reuse it for both signing and verifying. actions/attest@v4 already lowercases subject-name internally when push-to-registry is true (verified at the pinned commit 59d8942 in src/main.ts and src/subject.ts), but 'gh attestation verify' does NOT lowercase the OCI URI we pass it; doing it ourselves keeps the signed name and the verified URI byte-identical. - #4 NODE_OPTIONS comment: brief comment explaining why we mirror actions/attest-build-provenance's defensive HTTP header bump. - #5 extract: pulled the attest+verify pair into a single composite action so the Java workflow and the non-Java composite action share one implementation. Adds .github/workflows/test-attest-image.yaml: a manually-dispatched smoke test that builds a throwaway image and exercises the full attest+verify path. Use this whenever attest_image or actions/attest@v4 changes. Co-Authored-By: Claude Opus 4.7 (1M context) --- ...ared-publish-java-to-docker-versioned.yaml | 9 +-- .github/workflows/test-attest-image.yaml | 67 +++++++++++++++++++ actions/attest_image/action.yaml | 49 ++++++++++++++ actions/shared_publish_to_docker/action.yaml | 9 +-- 4 files changed, 122 insertions(+), 12 deletions(-) create mode 100644 .github/workflows/test-attest-image.yaml create mode 100644 actions/attest_image/action.yaml diff --git a/.github/workflows/shared-publish-java-to-docker-versioned.yaml b/.github/workflows/shared-publish-java-to-docker-versioned.yaml index 9f3989fd..ee148820 100644 --- a/.github/workflows/shared-publish-java-to-docker-versioned.yaml +++ b/.github/workflows/shared-publish-java-to-docker-versioned.yaml @@ -218,13 +218,10 @@ jobs: - name: Attest build provenance if: ${{ steps.checkRelease.outputs.not_snapshot == 'true' }} - uses: actions/attest@59d89421af93a897026c735860bf21b6eb4f7b26 # v4.1.0 - env: - NODE_OPTIONS: --max-http-header-size=32768 + uses: IABTechLab/uid2-shared-actions/actions/attest_image@v3 with: - subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}${{ inputs.append_image_name }} - subject-digest: ${{ steps.push.outputs.digest }} - push-to-registry: true + subject_name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}${{ inputs.append_image_name }} + subject_digest: ${{ steps.push.outputs.digest }} - name: Build Changelog id: github_release diff --git a/.github/workflows/test-attest-image.yaml b/.github/workflows/test-attest-image.yaml new file mode 100644 index 00000000..d8b327af --- /dev/null +++ b/.github/workflows/test-attest-image.yaml @@ -0,0 +1,67 @@ +name: Test attest_image composite action + +# Manually-dispatched smoke test that builds a tiny throwaway image, runs the +# `actions/attest_image` composite action, and verifies the resulting attestation. +# Validates UID2-6764 end-to-end without depending on a real consumer publish. +# Re-run this whenever `actions/attest@v4.x` is bumped or attest_image is changed. + +on: + workflow_dispatch: + +env: + TEST_IMAGE: ghcr.io/${{ github.repository }}/test-attest + +jobs: + smoke: + name: Smoke-test attest_image + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + id-token: write + attestations: write + steps: + - name: Checkout + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + + - name: Log in to GHCR + uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Set up Buildx + uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3 + + - name: Write throwaway Dockerfile + run: | + cat > Dockerfile.test-attest <<'DOCKERFILE' + FROM alpine:3.20 + RUN echo "uid2-6764 attest_image smoke test, run ${GITHUB_RUN_ID:-local}" > /uid2-6764.txt + DOCKERFILE + + - name: Build and push test image + id: push + uses: docker/build-push-action@ca052bb54ab0790a636c9b5f226502c73d547a25 # v5 + with: + context: . + file: Dockerfile.test-attest + push: true + tags: ${{ env.TEST_IMAGE }}:run-${{ github.run_id }} + + - name: Attest image (the system under test) + uses: ./actions/attest_image + with: + subject_name: ${{ env.TEST_IMAGE }} + subject_digest: ${{ steps.push.outputs.digest }} + + - name: Independent re-verify + env: + GH_TOKEN: ${{ github.token }} + run: | + echo "Verifying ${TEST_IMAGE}@${{ steps.push.outputs.digest }} ..." + gh attestation verify \ + "oci://${TEST_IMAGE}@${{ steps.push.outputs.digest }}" \ + --owner "${{ github.repository_owner }}" \ + --format json | jq '.[0].verificationResult.signature.certificate | {issuer, subjectAlternativeName, runnerEnvironment}' diff --git a/actions/attest_image/action.yaml b/actions/attest_image/action.yaml new file mode 100644 index 00000000..f76de7b8 --- /dev/null +++ b/actions/attest_image/action.yaml @@ -0,0 +1,49 @@ +name: Attest container image +description: | + Generates a SLSA build-provenance attestation for an OCI image, pushes the + signed bundle to the registry alongside the image, and verifies it via + `gh attestation verify` so a misconfigured signature fails the build rather + than the consumer pull. + + actions/attest already lowercases subject-name when push-to-registry is true + (see github.com/actions/attest src/main.ts and src/subject.ts), but + `gh attestation verify` does not lowercase the OCI URI we pass to it. To + keep the signed name and the verified URI byte-identical, we lowercase + once here and reuse the value in both steps. + +inputs: + subject_name: + description: Fully qualified image reference (registry/owner/repo[+suffix]). Mixed case is fine — this action lowercases it for OCI compliance. + required: true + subject_digest: + description: OCI manifest digest (sha256:...) emitted by docker/build-push-action. + required: true + +runs: + using: composite + steps: + - name: Lowercase image reference + id: ref + shell: bash + run: | + value="$(printf '%s' '${{ inputs.subject_name }}' | tr '[:upper:]' '[:lower:]')" + echo "value=${value}" >> "$GITHUB_OUTPUT" + + - name: Attest build provenance + uses: actions/attest@59d89421af93a897026c735860bf21b6eb4f7b26 # v4.1.0 + env: + # Mirrors actions/attest-build-provenance, prevents oversized OCI registry auth-challenge headers triggering HPE_HEADER_OVERFLOW. + NODE_OPTIONS: --max-http-header-size=32768 + with: + subject-name: ${{ steps.ref.outputs.value }} + subject-digest: ${{ inputs.subject_digest }} + push-to-registry: true + + - name: Verify attestation + shell: bash + env: + GH_TOKEN: ${{ github.token }} + run: | + gh attestation verify \ + "oci://${{ steps.ref.outputs.value }}@${{ inputs.subject_digest }}" \ + --owner "${{ github.repository_owner }}" diff --git a/actions/shared_publish_to_docker/action.yaml b/actions/shared_publish_to_docker/action.yaml index d24dae83..096acd5f 100644 --- a/actions/shared_publish_to_docker/action.yaml +++ b/actions/shared_publish_to_docker/action.yaml @@ -104,10 +104,7 @@ runs: - name: Attest build provenance if: ${{ inputs.not_snapshot == 'true' }} - uses: actions/attest@59d89421af93a897026c735860bf21b6eb4f7b26 # v4.1.0 - env: - NODE_OPTIONS: --max-http-header-size=32768 + uses: IABTechLab/uid2-shared-actions/actions/attest_image@v3 with: - subject-name: ${{ inputs.docker_registry }}/${{ inputs.docker_image_name }} - subject-digest: ${{ steps.push.outputs.digest }} - push-to-registry: true + subject_name: ${{ inputs.docker_registry }}/${{ inputs.docker_image_name }} + subject_digest: ${{ steps.push.outputs.digest }} From 95b7c529a77f642bdc191e20e64533fa8370c89e Mon Sep 17 00:00:00 2001 From: Behnam Mozafari Date: Fri, 8 May 2026 17:21:03 +1000 Subject: [PATCH 07/10] UID2-6764: trigger smoke test on push to feature branch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Drop after merge — only here so the smoke test can run before the workflow file lands on main (gh workflow run / API dispatch require the file to exist on the default branch). Co-Authored-By: Claude Opus 4.7 (1M context) --- .github/workflows/test-attest-image.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/test-attest-image.yaml b/.github/workflows/test-attest-image.yaml index d8b327af..ced3c038 100644 --- a/.github/workflows/test-attest-image.yaml +++ b/.github/workflows/test-attest-image.yaml @@ -7,6 +7,11 @@ name: Test attest_image composite action on: workflow_dispatch: + push: + branches: [bmz-UID2-6764-artifact-attestation] + paths: + - .github/workflows/test-attest-image.yaml + - actions/attest_image/** env: TEST_IMAGE: ghcr.io/${{ github.repository }}/test-attest From 46592c9e797d7b9893f6a7cd8107a3a8d4361dee Mon Sep 17 00:00:00 2001 From: Behnam Mozafari Date: Fri, 8 May 2026 17:22:14 +1000 Subject: [PATCH 08/10] UID2-6764: lowercase the smoke test image ref before docker push github.repository is mixed case; docker rejects mixed-case tags at push time. Compute a lowercased ref once and reuse it for the push tag, the attest_image input, and the independent re-verify command. Co-Authored-By: Claude Opus 4.7 (1M context) --- .github/workflows/test-attest-image.yaml | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/.github/workflows/test-attest-image.yaml b/.github/workflows/test-attest-image.yaml index ced3c038..7735b127 100644 --- a/.github/workflows/test-attest-image.yaml +++ b/.github/workflows/test-attest-image.yaml @@ -13,9 +13,6 @@ on: - .github/workflows/test-attest-image.yaml - actions/attest_image/** -env: - TEST_IMAGE: ghcr.io/${{ github.repository }}/test-attest - jobs: smoke: name: Smoke-test attest_image @@ -29,6 +26,10 @@ jobs: - name: Checkout uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + - name: Compute lowercased test image ref + id: image + run: echo "ref=ghcr.io/$(echo '${{ github.repository }}' | tr '[:upper:]' '[:lower:]')/test-attest" >> "$GITHUB_OUTPUT" + - name: Log in to GHCR uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3 with: @@ -53,20 +54,22 @@ jobs: context: . file: Dockerfile.test-attest push: true - tags: ${{ env.TEST_IMAGE }}:run-${{ github.run_id }} + tags: ${{ steps.image.outputs.ref }}:run-${{ github.run_id }} - name: Attest image (the system under test) uses: ./actions/attest_image with: - subject_name: ${{ env.TEST_IMAGE }} + subject_name: ${{ steps.image.outputs.ref }} subject_digest: ${{ steps.push.outputs.digest }} - name: Independent re-verify env: GH_TOKEN: ${{ github.token }} + IMAGE_REF: ${{ steps.image.outputs.ref }} + IMAGE_DIGEST: ${{ steps.push.outputs.digest }} run: | - echo "Verifying ${TEST_IMAGE}@${{ steps.push.outputs.digest }} ..." + echo "Verifying ${IMAGE_REF}@${IMAGE_DIGEST} ..." gh attestation verify \ - "oci://${TEST_IMAGE}@${{ steps.push.outputs.digest }}" \ + "oci://${IMAGE_REF}@${IMAGE_DIGEST}" \ --owner "${{ github.repository_owner }}" \ --format json | jq '.[0].verificationResult.signature.certificate | {issuer, subjectAlternativeName, runnerEnvironment}' From 688a8186961109d921213d93aea55335326c81d4 Mon Sep 17 00:00:00 2001 From: Behnam Mozafari Date: Fri, 8 May 2026 17:26:01 +1000 Subject: [PATCH 09/10] UID2-6764: drop push trigger from test-attest-image now that smoke test is green Run 25542801315 verified the attest+verify path end-to-end. Reverting to workflow_dispatch only so the test stops auto-firing and remains as an on-demand regression check after merge. Co-Authored-By: Claude Opus 4.7 (1M context) --- .github/workflows/test-attest-image.yaml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/.github/workflows/test-attest-image.yaml b/.github/workflows/test-attest-image.yaml index 7735b127..a9e7670c 100644 --- a/.github/workflows/test-attest-image.yaml +++ b/.github/workflows/test-attest-image.yaml @@ -7,11 +7,6 @@ name: Test attest_image composite action on: workflow_dispatch: - push: - branches: [bmz-UID2-6764-artifact-attestation] - paths: - - .github/workflows/test-attest-image.yaml - - actions/attest_image/** jobs: smoke: From 3954ca4de2043d89d115f7ec3e021997be15cb97 Mon Sep 17 00:00:00 2001 From: Behnam Mozafari Date: Fri, 8 May 2026 18:32:44 +1000 Subject: [PATCH 10/10] UID2-6764: drop the smoke-test workflow now that it's served its purpose Run 25542801315 captured the verified attestation evidence on PR #228; keeping the workflow would just push throwaway test images on every manual dispatch. The composite action lives at actions/attest_image and can be re-tested in any future change by re-adding this workflow file ad-hoc. Co-Authored-By: Claude Opus 4.7 (1M context) --- .github/workflows/test-attest-image.yaml | 70 ------------------------ 1 file changed, 70 deletions(-) delete mode 100644 .github/workflows/test-attest-image.yaml diff --git a/.github/workflows/test-attest-image.yaml b/.github/workflows/test-attest-image.yaml deleted file mode 100644 index a9e7670c..00000000 --- a/.github/workflows/test-attest-image.yaml +++ /dev/null @@ -1,70 +0,0 @@ -name: Test attest_image composite action - -# Manually-dispatched smoke test that builds a tiny throwaway image, runs the -# `actions/attest_image` composite action, and verifies the resulting attestation. -# Validates UID2-6764 end-to-end without depending on a real consumer publish. -# Re-run this whenever `actions/attest@v4.x` is bumped or attest_image is changed. - -on: - workflow_dispatch: - -jobs: - smoke: - name: Smoke-test attest_image - runs-on: ubuntu-latest - permissions: - contents: read - packages: write - id-token: write - attestations: write - steps: - - name: Checkout - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 - - - name: Compute lowercased test image ref - id: image - run: echo "ref=ghcr.io/$(echo '${{ github.repository }}' | tr '[:upper:]' '[:lower:]')/test-attest" >> "$GITHUB_OUTPUT" - - - name: Log in to GHCR - uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3 - with: - registry: ghcr.io - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Set up Buildx - uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3 - - - name: Write throwaway Dockerfile - run: | - cat > Dockerfile.test-attest <<'DOCKERFILE' - FROM alpine:3.20 - RUN echo "uid2-6764 attest_image smoke test, run ${GITHUB_RUN_ID:-local}" > /uid2-6764.txt - DOCKERFILE - - - name: Build and push test image - id: push - uses: docker/build-push-action@ca052bb54ab0790a636c9b5f226502c73d547a25 # v5 - with: - context: . - file: Dockerfile.test-attest - push: true - tags: ${{ steps.image.outputs.ref }}:run-${{ github.run_id }} - - - name: Attest image (the system under test) - uses: ./actions/attest_image - with: - subject_name: ${{ steps.image.outputs.ref }} - subject_digest: ${{ steps.push.outputs.digest }} - - - name: Independent re-verify - env: - GH_TOKEN: ${{ github.token }} - IMAGE_REF: ${{ steps.image.outputs.ref }} - IMAGE_DIGEST: ${{ steps.push.outputs.digest }} - run: | - echo "Verifying ${IMAGE_REF}@${IMAGE_DIGEST} ..." - gh attestation verify \ - "oci://${IMAGE_REF}@${IMAGE_DIGEST}" \ - --owner "${{ github.repository_owner }}" \ - --format json | jq '.[0].verificationResult.signature.certificate | {issuer, subjectAlternativeName, runnerEnvironment}'