Skip to content

Verify Enclave

Verify Enclave #33

Workflow file for this run

name: Verify Enclave
on:
schedule:
- cron: '0 8 * * *'
workflow_dispatch:
permissions:
contents: read
id-token: write # Mint OIDC tokens (custom webhook + Sigstore signing).
attestations: write # Publish verify-result attestation to GitHub's attestations API.
jobs:
verify:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: stable
- name: Install enclave CLI
run: go install github.com/ArkLabsHQ/introspector-enclave/cli/cmd/enclave@latest
- name: Fetch deployment manifest
id: manifest
env:
GH_TOKEN: ${{ github.token }}
run: |
gh release download -p deployment.json || {
echo "No deployment manifest found. Run the deploy workflow first."
exit 1
}
base_url=$(jq -r '.base_url // empty' deployment.json)
pcr0=$(jq -r '.pcr0' deployment.json)
pcr1=$(jq -r '.pcr1' deployment.json)
pcr2=$(jq -r '.pcr2' deployment.json)
echo "base_url=${base_url}" >> "$GITHUB_OUTPUT"
echo "pcr0=${pcr0}" >> "$GITHUB_OUTPUT"
echo "pcr1=${pcr1}" >> "$GITHUB_OUTPUT"
echo "pcr2=${pcr2}" >> "$GITHUB_OUTPUT"
- name: Verify attestation
id: verify
if: steps.manifest.outputs.base_url != '' || vars.ENCLAVE_BASE_URL != ''
env:
BASE_URL: ${{ steps.manifest.outputs.base_url || vars.ENCLAVE_BASE_URL }}
PCR0: ${{ steps.manifest.outputs.pcr0 }}
run: |
output=$(enclave verify \
--base-url "${BASE_URL}" \
--expected-pcr0 "${PCR0}" \
--wait 60 2>&1) && status="pass" || status="fail"
echo "status=${status}" >> "$GITHUB_OUTPUT"
echo "output<<EOF" >> "$GITHUB_OUTPUT"
echo "${output}" >> "$GITHUB_OUTPUT"
echo "EOF" >> "$GITHUB_OUTPUT"
{
echo "## Enclave Verification"
echo "- **Status:** ${status}"
echo "- **PCR0:** ${PCR0}"
echo '```'
echo "${output}"
echo '```'
} >> "$GITHUB_STEP_SUMMARY"
- name: Build attestation predicate
if: steps.verify.outcome != 'skipped'
env:
STATUS: ${{ steps.verify.outputs.status }}
PCR0: ${{ steps.manifest.outputs.pcr0 }}
PCR1: ${{ steps.manifest.outputs.pcr1 }}
PCR2: ${{ steps.manifest.outputs.pcr2 }}
BASE_URL: ${{ steps.manifest.outputs.base_url || vars.ENCLAVE_BASE_URL }}
VERIFIER: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}
run: |
jq -n \
--arg status "$STATUS" \
--arg pcr0 "$PCR0" \
--arg pcr1 "$PCR1" \
--arg pcr2 "$PCR2" \
--arg base_url "$BASE_URL" \
--arg verifier "$VERIFIER" \
--argjson verifiedAt "$(date -u +%s)" \
'{
status: $status,
expectedPcr0: $pcr0,
expectedPcr1: $pcr1,
expectedPcr2: $pcr2,
baseUrl: $base_url,
verifier: $verifier,
verifiedAt: $verifiedAt
}' > predicate.json
# Anchor the attestation to image.eif from the eif-latest release.
# actions/attest@v2 computes sha256(image.eif) as the subject digest, which
# composes with `gh attestation verify image.eif --predicate-type ...`.
# The PCR0/1/2 values still live in the predicate envelope above; this
# subject just gives auditors a verifiable anchor — the same file the
# build-provenance attestation in release-eif.yml is also anchored to.
- name: Download EIF for attestation subject
if: steps.verify.outcome != 'skipped'
env:
GH_TOKEN: ${{ github.token }}
run: gh release download eif-latest -p image.eif --clobber
- name: Attest enclave verification result
if: steps.verify.outcome != 'skipped'
uses: actions/attest@v2
with:
subject-path: image.eif
predicate-type: https://github.com/BitspendPayment/MPCWallet/predicates/enclave-verify/v1
predicate-path: predicate.json
- name: Mint OIDC token
id: oidc
if: always() && steps.verify.outcome != 'skipped'
run: |
TOKEN=$(curl -sLS \
-H "Authorization: bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" \
"$ACTIONS_ID_TOKEN_REQUEST_URL&audience=attestation-api" \
| jq -r .value)
echo "::add-mask::$TOKEN"
echo "token=$TOKEN" >> "$GITHUB_OUTPUT"
- name: Publish to attestation API
if: always() && steps.verify.outcome != 'skipped'
env:
API_URL: ${{ vars.ATTESTATION_API_URL }}
OIDC_TOKEN: ${{ steps.oidc.outputs.token }}
STATUS: ${{ steps.verify.outputs.status || 'unknown' }}
VERIFY_OUTPUT: ${{ steps.verify.outputs.output || '' }}
PCR0: ${{ steps.manifest.outputs.pcr0 }}
PCR1: ${{ steps.manifest.outputs.pcr1 }}
PCR2: ${{ steps.manifest.outputs.pcr2 }}
BASE_URL: ${{ steps.manifest.outputs.base_url || vars.ENCLAVE_BASE_URL }}
run: |
payload=$(jq -n \
--arg status "$STATUS" \
--arg pcr0 "$PCR0" \
--arg pcr1 "$PCR1" \
--arg pcr2 "$PCR2" \
--arg verify_output "$VERIFY_OUTPUT" \
--arg commit_sha "$GITHUB_SHA" \
--arg run_id "$GITHUB_RUN_ID" \
--arg base_url "$BASE_URL" \
--argjson verified_at "$(date -u +%s)" \
'{
status: $status,
pcr0: $pcr0,
pcr1: $pcr1,
pcr2: $pcr2,
verify_output: $verify_output,
commit_sha: $commit_sha,
run_id: $run_id,
base_url: $base_url,
verified_at: $verified_at
}')
curl --fail-with-body -sSL --retry 3 -X POST "$API_URL/api/attestations/webhook" \
-H "Authorization: Bearer $OIDC_TOKEN" \
-H "Content-Type: application/json" \
-d "$payload"