diff --git a/.github/workflows/.test.yml b/.github/workflows/.test.yml index 3fa44fa..7a35253 100644 --- a/.github/workflows/.test.yml +++ b/.github/workflows/.test.yml @@ -59,6 +59,39 @@ jobs: username: ${{ secrets.AWS_ACCESS_KEY_ID }} password: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + build-aws-verify: + runs-on: ubuntu-latest + if: ${{ github.event_name != 'pull_request' }} + needs: + - build-aws + steps: + - + name: Install Cosign + uses: sigstore/cosign-installer@faadad0cce49287aee09b3a48701e75088a2c6ad # v4.0.0 + with: + cosign-release: ${{ needs.build-aws.outputs.cosign-version }} + - + name: Login to registry + uses: docker/login-action@v3 + with: + registry: public.ecr.aws + username: ${{ secrets.AWS_ACCESS_KEY_ID }} + password: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + - + name: Verify signatures + uses: actions/github-script@v8 + env: + INPUT_COSIGN-VERSION: ${{ needs.build-aws.outputs.cosign-version }} + INPUT_COSIGN-VERIFY-COMMANDS: ${{ needs.build-aws.outputs.cosign-verify-commands }} + with: + script: | + const cosignVersion = core.getInput('cosign-version'); + core.info(`Cosign version used by Docker GitHub Builder: ${cosignVersion}`); + const cosignVerifyCommands = core.getMultilineInput('cosign-verify-commands'); + for (const cmd of cosignVerifyCommands) { + await exec.exec(cmd); + } + build-ghcr: uses: ./.github/workflows/build.yml permissions: @@ -154,3 +187,34 @@ jobs: build-file: test/hello.Dockerfile build-sbom: true build-platforms: linux/amd64,linux/arm64 + + build-local-verify: + runs-on: ubuntu-latest + if: ${{ github.event_name != 'pull_request' }} + needs: + - build-local + steps: + - + name: Install Cosign + uses: sigstore/cosign-installer@faadad0cce49287aee09b3a48701e75088a2c6ad # v4.0.0 + with: + cosign-release: ${{ needs.build-local.outputs.cosign-version }} + - + name: Download artifact + uses: actions/download-artifact@v5 + with: + name: ${{ needs.build-local.outputs.artifact-name }} + - + name: Verify signatures + uses: actions/github-script@v8 + env: + INPUT_COSIGN-VERSION: ${{ needs.build-local.outputs.cosign-version }} + INPUT_COSIGN-VERIFY-COMMANDS: ${{ needs.build-local.outputs.cosign-verify-commands }} + with: + script: | + const cosignVersion = core.getInput('cosign-version'); + core.info(`Cosign version used by Docker GitHub Builder: ${cosignVersion}`); + const cosignVerifyCommands = core.getMultilineInput('cosign-verify-commands'); + for (const cmd of cosignVerifyCommands) { + await exec.exec(cmd); + } diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 86c3425..3298ab7 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -108,15 +108,30 @@ on: github-token: description: "GitHub Token used to authenticate against a repository for Git context" required: false + outputs: + cosign-version: + description: Cosign version used for verification + value: ${{ jobs.build.outputs.cosign-version }} + cosign-verify-commands: + description: Cosign verify commands + value: ${{ jobs.build.outputs.cosign-verify-commands }} + artifact-name: + description: Name of the uploaded artifact (for local output) + value: ${{ jobs.build.outputs.artifact-name }} env: DOCKER_ACTIONS_TOOLKIT_MODULE: "@docker/actions-toolkit@0.67.0" COSIGN_VERSION: "v3.0.2" LOCAL_EXPORT_DIR: "/tmp/buildx-output" + LOCAL_ARTIFACT_NAME: "docker-github-builder-assets" jobs: build: runs-on: ubuntu-latest + outputs: + cosign-version: ${{ env.COSIGN_VERSION }} + cosign-verify-commands: ${{ steps.signing-attestation-manifests.outputs.verify-commands || steps.signing-local-artifacts.outputs.verify-commands }} + artifact-name: ${{ env.LOCAL_ARTIFACT_NAME }} permissions: contents: read id-token: write # needed for signing the images with GitHub OIDC Token @@ -266,6 +281,7 @@ jobs: await cosign.printVersion(); - name: Signing attestation manifests + id: signing-attestation-manifests if: ${{ inputs.output == 'registry' }} uses: actions/github-script@v8 env: @@ -288,8 +304,19 @@ jobs: { certificateIdentityRegexp: `^https://github.com/docker/github-builder-experimental/.github/workflows/build.yml.*$` }, signResults ); + + await core.group(`Verify commands`, async () => { + const verifyCommands = []; + for (const [attestationRef, verifyResult] of Object.entries(verifyResults)) { + const cmd = `cosign ${verifyResult.cosignArgs.join(' ')} ${attestationRef}`; + core.info(cmd); + verifyCommands.push(cmd); + } + core.setOutput('verify-commands', verifyCommands.join('\n')); + }); - name: Signing local artifacts + id: signing-local-artifacts if: ${{ inputs.output == 'local' }} uses: actions/github-script@v8 env: @@ -309,6 +336,16 @@ jobs: { certificateIdentityRegexp: `^https://github.com/docker/github-builder-experimental/.github/workflows/build.yml.*$` }, signResults ); + + await core.group(`Verify commands`, async () => { + const verifyCommands = []; + for (const [artifactPath, verifyResult] of Object.entries(verifyResults)) { + const cmd = `cosign ${verifyResult.cosignArgs.join(' ')} --bundle ${path.relative(inplocalExportDir, verifyResult.bundlePath)} ${path.relative(inplocalExportDir, artifactPath)}`; + core.info(cmd); + verifyCommands.push(cmd); + } + core.setOutput('verify-commands', verifyCommands.join('\n')); + }); - name: Create manifest if: ${{ inputs.output == 'registry' }} @@ -343,6 +380,6 @@ jobs: if: ${{ inputs.output == 'local' }} uses: actions/upload-artifact@v5 with: - name: docker-github-builder-assets + name: ${{ env.LOCAL_ARTIFACT_NAME }} path: ${{ env.LOCAL_EXPORT_DIR }} if-no-files-found: error diff --git a/README.md b/README.md index 4c9ec67..7e8a43d 100644 --- a/README.md +++ b/README.md @@ -51,6 +51,35 @@ on: - registry: docker.io username: ${{ vars.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} + + build-verify: + runs-on: ubuntu-latest + if: ${{ github.event_name != 'pull_request' }} + needs: + - build + steps: + - + name: Install Cosign + uses: sigstore/cosign-installer@faadad0cce49287aee09b3a48701e75088a2c6ad # v4.0.0 + with: + cosign-release: ${{ needs.build.outputs.cosign-version }} + - + name: Login to registry + uses: docker/login-action@v3 + with: + registry: docker.io + username: ${{ vars.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + - + name: Verify signatures + uses: actions/github-script@v8 + env: + INPUT_COSIGN-VERIFY-COMMANDS: ${{ needs.build.outputs.cosign-verify-commands }} + with: + script: | + for (const cmd of core.getMultilineInput('cosign-verify-commands')) { + await exec.exec(cmd); + } ``` You can find the list of available inputs in [`.github/workflows/build.yml`](.github/workflows/build.yml).