Skip to content

Add PCTR: see what your agents can cause, route them safely, prove what happened #9

Add PCTR: see what your agents can cause, route them safely, prove what happened

Add PCTR: see what your agents can cause, route them safely, prove what happened #9

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