Add PCTR: see what your agents can cause, route them safely, prove what happened #9
Workflow file for this run
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: TTP / Governed Execution Proof | |
| on: | |
| pull_request: | |
| types: [opened, synchronize, reopened, ready_for_review] | |
| jobs: | |
| govern: | |
| name: Governed Execution | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| pull-requests: write | |
| outputs: | |
| decision: ${{ steps.authorize.outputs.decision }} | |
| receipt: ${{ steps.authorize.outputs.receipt }} | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Detect changes | |
| id: changes | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| BASE="${{ github.event.pull_request.base.sha }}" | |
| HEAD="${{ github.event.pull_request.head.sha }}" | |
| git diff --name-only "$BASE" "$HEAD" > changed.txt || true | |
| echo "Changed files:" | |
| cat changed.txt || true | |
| PATHS_JSON=$(jq -Rsc 'split("\n") | map(select(length > 0))' changed.txt) | |
| echo "paths=$PATHS_JSON" >> "$GITHUB_OUTPUT" | |
| FILE_COUNT=$(wc -l < changed.txt | tr -d ' ') | |
| echo "count=$FILE_COUNT" >> "$GITHUB_OUTPUT" | |
| - name: Authorize execution | |
| id: authorize | |
| env: | |
| AUTH_URL: ${{ secrets.RUNTIME_AUTH_URL }} | |
| AUTH_TOKEN: ${{ secrets.RUNTIME_AUTH_TOKEN }} | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| if [ ! -s changed.txt ]; then | |
| echo "No changes detected; emitting local deny receipt." | |
| echo "decision=DENY" >> "$GITHUB_OUTPUT" | |
| echo "receipt=local-noop-receipt" >> "$GITHUB_OUTPUT" | |
| exit 0 | |
| fi | |
| jq -n \ | |
| --arg repo "${{ github.repository }}" \ | |
| --arg actor "${{ github.actor }}" \ | |
| --arg pr "${{ github.event.pull_request.number }}" \ | |
| --arg sha "${{ github.event.pull_request.head.sha }}" \ | |
| --arg branch "${{ github.head_ref }}" \ | |
| --arg run_id "${{ github.run_id }}" \ | |
| --argjson paths '${{ steps.changes.outputs.paths }}' \ | |
| '{ | |
| subject: "wi://github/actions/runner", | |
| action: "pull_request.execute", | |
| resource: ("repo:" + $repo + ":pr/" + $pr), | |
| repo: $repo, | |
| branch: $branch, | |
| commitSha: $sha, | |
| workflowRunId: $run_id, | |
| actor: $actor, | |
| invokingActor: $actor, | |
| trustScore: 0.95, | |
| freshnessSeconds: 60, | |
| attestationRef: "att://github/actions/local-fallback", | |
| authorityGrantRef: "grant://github/pull-request-review", | |
| pathsTouched: $paths, | |
| context: { | |
| event: "pull_request", | |
| repo: $repo | |
| } | |
| }' > request.json | |
| echo "Authorization request:" | |
| cat request.json | |
| if [ -z "${AUTH_URL:-}" ] || [ -z "${AUTH_TOKEN:-}" ]; then | |
| echo "Runtime authority endpoint is not configured; using local non-production receipt." | |
| node .github/scripts/ttp-local-authorize.mjs request.json response.json | |
| else | |
| HTTP_CODE=$(curl -sS \ | |
| -o response.json \ | |
| -w "%{http_code}" \ | |
| -H "Authorization: Bearer $AUTH_TOKEN" \ | |
| -H "Content-Type: application/json" \ | |
| -X POST "$AUTH_URL/re/authorize" \ | |
| -d @request.json) | |
| echo "HTTP status: $HTTP_CODE" | |
| if [ "$HTTP_CODE" != "200" ]; then | |
| echo "Authority endpoint returned HTTP $HTTP_CODE; using local non-production deny receipt." | |
| node .github/scripts/ttp-local-authorize.mjs request.json response.json | |
| fi | |
| fi | |
| echo "Authority response:" | |
| cat response.json | |
| DECISION=$(jq -r '.decision // "DENY"' response.json) | |
| RECEIPT=$(jq -r '.receiptId // .receipt.receiptId // ""' response.json) | |
| if [ -z "$RECEIPT" ]; then | |
| echo "Authority response did not include receiptId; using local missing-receipt marker." | |
| RECEIPT="local-missing-receipt" | |
| fi | |
| echo "Decision: $DECISION" | |
| echo "Receipt: $RECEIPT" | |
| echo "decision=$DECISION" >> "$GITHUB_OUTPUT" | |
| echo "receipt=$RECEIPT" >> "$GITHUB_OUTPUT" | |
| step-up: | |
| name: Step-Up Approval | |
| runs-on: ubuntu-latest | |
| needs: govern | |
| if: needs.govern.outputs.decision == 'STEP_UP' | |
| environment: | |
| name: protected-execution | |
| steps: | |
| - name: Manual authorization granted | |
| run: | | |
| echo "Manual authorization granted via environment gate." | |
| echo "Receipt: ${{ needs.govern.outputs.receipt }}" | |
| enforce: | |
| name: Enforce Authority Decision | |
| runs-on: ubuntu-latest | |
| needs: [govern, step-up] | |
| if: always() | |
| steps: | |
| - name: Enforce authority decision | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| DECISION="${{ needs.govern.outputs.decision }}" | |
| RECEIPT="${{ needs.govern.outputs.receipt }}" | |
| STEP_UP_RESULT="${{ needs.step-up.result }}" | |
| echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" | |
| echo " TTP / Governed Execution Enforcement" | |
| echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" | |
| echo " Decision : $DECISION" | |
| echo " Receipt : ${RECEIPT:-<none>}" | |
| echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" | |
| if [ -z "$RECEIPT" ]; then | |
| echo "" | |
| echo "Missing receipt — hard deny." | |
| echo "Every governed execution requires a verifiable receipt." | |
| exit 1 | |
| fi | |
| if [ "$RECEIPT" = "local-noop-receipt" ]; then | |
| echo "No governed file changes detected; policy gate is a no-op for this PR." | |
| exit 0 | |
| fi | |
| if [ "$RECEIPT" = "local-missing-receipt" ]; then | |
| echo "Authority response was missing a receipt; deny." | |
| exit 1 | |
| fi | |
| case "$DECISION" in | |
| PERMIT) | |
| echo "Execution permitted." | |
| exit 0 | |
| ;; | |
| STEP_UP) | |
| if [ "$STEP_UP_RESULT" = "success" ]; then | |
| echo "Step-up approval granted. Execution permitted." | |
| exit 0 | |
| fi | |
| echo "Step-up approval required." | |
| exit 1 | |
| ;; | |
| DENY) | |
| if [[ "$RECEIPT" == er-* ]]; then | |
| echo "Local authority produced a deny receipt for review." | |
| fi | |
| echo "Execution denied." | |
| exit 1 | |
| ;; | |
| *) | |
| echo "Unknown authority decision: $DECISION" | |
| exit 1 | |
| ;; | |
| esac |