Assayward Release Gate #4
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Assayward Release Gate | |
| # Triggered on the RELEASE WORKFLOW COMPLETING, not on `release: published`. | |
| # GoReleaser creates the release using GITHUB_TOKEN, and GitHub deliberately | |
| # suppresses events raised by that token so a workflow cannot trigger itself in | |
| # a loop. The side effect is that a `release: published` trigger never fires on | |
| # the normal release path: this gate had zero runs across every tagged release | |
| # before this change. Keying off workflow_run makes the gate actually run. | |
| on: | |
| workflow_run: | |
| workflows: ["Release"] | |
| types: [completed] | |
| workflow_dispatch: | |
| permissions: | |
| contents: read | |
| id-token: write | |
| jobs: | |
| assayward-gate: | |
| runs-on: ubuntu-latest | |
| # A failed release has nothing worth gating. | |
| if: github.event_name == 'workflow_dispatch' || github.event.workflow_run.conclusion == 'success' | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: actions/setup-go@v5 | |
| with: | |
| go-version: '1.23' | |
| - name: Build | |
| run: make build | |
| - name: Self-attest with forgeseal pipeline | |
| run: | | |
| ./bin/forgeseal pipeline \ | |
| --dir . \ | |
| --output-dir ./forgeseal-output \ | |
| --sign \ | |
| --attest \ | |
| --keyed=false | |
| # The gated artifact must be the one the provenance actually attests. | |
| # `forgeseal pipeline --attest` records the dependency SBOM as its | |
| # subject, so hashing the binary here produced a digest that appears in | |
| # no attestation: assayward answered SUBJECT_DIGEST_MISMATCH and every | |
| # downstream check then reported its evidence missing. Hashing the | |
| # attested subject binds the policy to real evidence. (Never caught | |
| # before because this workflow's trigger meant it never ran.) | |
| - name: Compute attested subject digest | |
| id: digest | |
| run: | | |
| test -f ./forgeseal-output/sbom.cdx.json | |
| DIGEST="sha256:$(sha256sum ./forgeseal-output/sbom.cdx.json | awk '{print $1}')" | |
| echo "value=$DIGEST" >> "$GITHUB_OUTPUT" | |
| - name: Obtain svidmint SVID | |
| id: svid | |
| if: vars.SVIDMINT_URL != '' | |
| run: | | |
| # Exchange GitHub OIDC token for a SPIFFE SVID from svidmint | |
| OIDC_TOKEN=$(curl -sSfL \ | |
| -H "Authorization: bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" \ | |
| "${ACTIONS_ID_TOKEN_REQUEST_URL}&audience=svidmint" | jq -r .value) | |
| RESPONSE=$(curl -sSfL \ | |
| -X POST "${{ vars.SVIDMINT_URL }}/v1/attest" \ | |
| -H "Content-Type: application/json" \ | |
| -d "{\"token\": \"${OIDC_TOKEN}\", \"audience\": \"${{ steps.digest.outputs.value }}\"}") | |
| echo "svid=$(echo "$RESPONSE" | jq -r .svid)" >> "$GITHUB_OUTPUT" | |
| echo "bundle=$(echo "$RESPONSE" | jq -r .spiffe_bundle)" >> "$GITHUB_OUTPUT" | |
| env: | |
| ACTIONS_ID_TOKEN_REQUEST_URL: ${{ env.ACTIONS_ID_TOKEN_REQUEST_URL }} | |
| ACTIONS_ID_TOKEN_REQUEST_TOKEN: ${{ env.ACTIONS_ID_TOKEN_REQUEST_TOKEN }} | |
| - name: Note SVID skipped | |
| if: vars.SVIDMINT_URL == '' | |
| run: echo "SVIDMINT_URL not configured; SVID identity step skipped" | |
| - name: Assayward gate | |
| uses: sns45/assayward-action@v0.1 | |
| with: | |
| forgeseal-output: ./forgeseal-output | |
| image: forgeseal-artifact@${{ steps.digest.outputs.value }} | |
| svid: ${{ steps.svid.outputs.svid }} | |
| spiffe-bundle: ${{ steps.svid.outputs.bundle }} | |
| policy-file: ./assayward-dogfood-policy.yaml |