-
Notifications
You must be signed in to change notification settings - Fork 0
Governed execution demo #41
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| name: Quickstart feedback | ||
| description: Report friction from the first TTP demo or integration path. | ||
| title: "[Quickstart]: " | ||
| labels: | ||
| - docs | ||
| - developer-experience | ||
| body: | ||
| - type: markdown | ||
| attributes: | ||
| value: | | ||
| Use this when the local demo, getting started guide, or first integration path is unclear or does not work. | ||
| - type: input | ||
| id: path | ||
| attributes: | ||
| label: Path tried | ||
| description: Which path were you using? | ||
| placeholder: npm run demo, SDK install, Trust Authority setup, GitHub Actions gate | ||
| validations: | ||
| required: true | ||
| - type: textarea | ||
| id: expected | ||
| attributes: | ||
| label: Expected outcome | ||
| description: What did you expect to happen? | ||
| validations: | ||
| required: true | ||
| - type: textarea | ||
| id: actual | ||
| attributes: | ||
| label: Actual outcome | ||
| description: What happened instead? Include command output if useful. | ||
| validations: | ||
| required: true | ||
| - type: textarea | ||
| id: environment | ||
| attributes: | ||
| label: Environment | ||
| description: Node version, OS, package manager, and any relevant runtime context. | ||
| placeholder: Node 20, macOS/Linux/Windows, npm/pnpm/yarn |
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,106 +1,24 @@ | ||
| name: CI / Repository Health | ||
| name: CI | ||
|
|
||
| on: | ||
| push: | ||
| branches: ["**"] | ||
| pull_request: | ||
| push: | ||
| branches: | ||
| - main | ||
|
|
||
| jobs: | ||
| test: | ||
| name: Test and Smoke Checks | ||
| verify: | ||
| name: Demo and Tests | ||
| runs-on: ubuntu-latest | ||
| permissions: | ||
| contents: read | ||
|
|
||
| steps: | ||
| - uses: actions/checkout@v4 | ||
|
|
||
| - name: Setup Node | ||
| uses: actions/setup-node@v4 | ||
| - uses: actions/setup-node@v4 | ||
| with: | ||
| node-version: '20' | ||
|
|
||
| - name: Run test suite | ||
| run: npm test | ||
|
|
||
| - name: Compile Python SDK | ||
| run: python -m py_compile sdk/python/client.py | ||
|
|
||
| - name: SDK + gate smoke matrix | ||
| shell: bash | ||
| run: | | ||
| set -euo pipefail | ||
|
|
||
| node reference-implementations/runtime-authority-gate/server.mjs >/tmp/runtime-gate.log 2>&1 & | ||
| GATE_PID=$! | ||
| trap 'kill $GATE_PID' EXIT | ||
|
|
||
| for i in {1..20}; do | ||
| if curl -fsS http://127.0.0.1:8080/healthz >/dev/null; then | ||
| break | ||
| fi | ||
| sleep 0.2 | ||
| done | ||
|
|
||
| # PERMIT | ||
| curl -fsS -X POST http://127.0.0.1:8080/re/authorize \ | ||
| -H 'content-type: application/json' \ | ||
| -d '{"requestId":"ci-permit","subject":"ci-agent","action":"pipeline.deploy","resource":{"id":"prod"},"context":{"trustScore":0.9,"environment":"dev"},"authorityGrant":{"grantId":"grant-local-001"}}' \ | ||
| | jq -e '.decision=="PERMIT" and .mode=="FULL" and .rapDecision=="allow"' >/dev/null | ||
|
|
||
| # STEP_UP | ||
| STEP_UP_RECEIPT=$(curl -fsS -X POST http://127.0.0.1:8080/re/authorize \ | ||
| -H 'content-type: application/json' \ | ||
| -d '{"requestId":"ci-stepup","subject":"ci-agent","action":"pipeline.deploy","resource":{"id":"prod"},"context":{"trustScore":0.55,"environment":"dev"},"authorityGrant":{"grantId":"grant-local-001"}}' \ | ||
| | jq -r 'select(.decision=="STEP_UP" and .rapDecision=="step_up") | .receiptId') | ||
| test -n "$STEP_UP_RECEIPT" | ||
|
|
||
| # ESCALATE | ||
| curl -fsS -X POST http://127.0.0.1:8080/re/authorize \ | ||
| -H 'content-type: application/json' \ | ||
| -d '{"requestId":"ci-escalate","subject":"mythos-agent","action":"tool.invoke.delete_secret","resource":{"id":"prod-secret"},"context":{"trustScore":0.95,"environment":"prod","agentType":"mythos"},"authorityGrant":{"grantId":"grant-local-001"}}' \ | ||
| | jq -e '.decision=="ESCALATE" and .rapDecision=="escalate"' >/dev/null | ||
|
|
||
| # DENY | ||
| curl -fsS -X POST http://127.0.0.1:8080/re/authorize \ | ||
| -H 'content-type: application/json' \ | ||
| -d '{"requestId":"ci-deny","subject":"ci-agent","action":"pipeline.deploy","resource":{"id":"prod"},"context":{"trustScore":0.1,"environment":"dev"},"authorityGrant":{"grantId":"grant-local-001"}}' \ | ||
| | jq -e '.decision=="DENY" and .rapDecision=="deny"' >/dev/null | ||
|
|
||
| # REAUTHORIZE | ||
| curl -fsS -X POST http://127.0.0.1:8080/re/reauthorize \ | ||
| -H 'content-type: application/json' \ | ||
| -d "{\"requestId\":\"ci-reauth\",\"priorReceiptId\":\"$STEP_UP_RECEIPT\",\"approval\":{\"approvedBy\":\"ops-admin\",\"evidenceRef\":\"ticket-ci\"}}" \ | ||
| | jq -e '.decision=="PERMIT" and .mode=="CONSTRAINED" and .rapDecision=="throttle"' >/dev/null | ||
| node-version: 20 | ||
|
|
||
| python - <<'PY' | ||
| from sdk.python import authorize, AuthorizeRequest, Principal, Resource, AuthorityGrant | ||
| resp = authorize(AuthorizeRequest( | ||
| base_url='http://127.0.0.1:8080', | ||
| requestId='ci-py-1', | ||
| principal=Principal(id='py-ci-agent', type='service-agent'), | ||
| action='pipeline.deploy', | ||
| resource=Resource(type='environment', id='prod'), | ||
| context={'trustScore': 0.91, 'environment': 'dev'}, | ||
| authorityGrant=AuthorityGrant(grantId='grant-local-001', expiresAt='2030-01-01T00:00:00Z', scope=['pipeline.deploy:prod']) | ||
| )) | ||
| assert resp.decision.value == 'PERMIT' | ||
| PY | ||
| - name: Run local adoption demo | ||
| run: npm run demo | ||
|
|
||
| node --input-type=module - <<'JS' | ||
| import { authorize } from './sdk/node/index.js'; | ||
| const resp = await authorize({ | ||
| baseUrl: 'http://127.0.0.1:8080', | ||
| requestId: 'ci-node-1', | ||
| principal: { id: 'node-ci-agent', type: 'service-agent' }, | ||
| action: 'pipeline.deploy', | ||
| resource: { type: 'environment', id: 'prod' }, | ||
| context: { trustScore: 0.92, environment: 'dev' }, | ||
| authorityGrant: { | ||
| grantId: 'grant-local-001', | ||
| expiresAt: '2030-01-01T00:00:00Z', | ||
| scope: ['pipeline.deploy:prod'] | ||
| } | ||
| }); | ||
| if (resp.decision !== 'PERMIT') throw new Error('Expected PERMIT'); | ||
| JS | ||
| - name: Run trust-routing tests | ||
| run: npm run test:trust-routing |
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,131 @@ | ||
| 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: | ||
| # 1️⃣ Full checkout (safe and correct) | ||
| - uses: actions/checkout@v4 | ||
| with: | ||
| fetch-depth: 0 | ||
|
|
||
| # 2️⃣ Detect changed files | ||
| - 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 -R . < changed.txt | jq -s .) | ||
| echo "paths=$PATHS_JSON" >> "$GITHUB_OUTPUT" | ||
|
|
||
| # 3️⃣ Ask external authority for permission | ||
| - 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 → deny by policy" | ||
| echo "decision=DENY" >> "$GITHUB_OUTPUT" | ||
| echo "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 }}" \ | ||
| --argjson paths "$(jq -s . changed.txt | jq -R .)" \ | ||
| '{ | ||
| subject: "wi://github/actions/runner", | ||
| action: "pull_request.execute", | ||
| resource: ("repo:" + $repo + ":pr/" + $pr), | ||
| commitSha: $sha, | ||
| actor: $actor, | ||
| pathsTouched: $paths, | ||
| context: { | ||
| event: "pull_request", | ||
| repo: $repo | ||
| } | ||
| }' > request.json | ||
|
|
||
| curl -sS \ | ||
| -H "Authorization: Bearer $AUTH_TOKEN" \ | ||
| -H "Content-Type: application/json" \ | ||
| -X POST "$AUTH_URL/re/authorize" \ | ||
| -d @request.json \ | ||
| > response.json | ||
|
|
||
| cat response.json | ||
|
|
||
| DECISION=$(jq -r '.decision // "DENY"' response.json) | ||
| RECEIPT=$(jq -r '.receiptId // ""' response.json) | ||
|
|
||
| echo "decision=$DECISION" >> "$GITHUB_OUTPUT" | ||
| echo "receipt=$RECEIPT" >> "$GITHUB_OUTPUT" | ||
|
|
||
| # 4️⃣ Human approval if required | ||
| step-up: | ||
| name: Step‑Up Approval | ||
| runs-on: ubuntu-latest | ||
| needs: govern | ||
| if: needs.govern.outputs.decision == 'STEP_UP' | ||
| environment: | ||
| name: protected-execution | ||
| steps: | ||
| - run: | | ||
| echo "Manual authorization granted via environment." | ||
| echo "Receipt: ${{ needs.govern.outputs.receipt }}" | ||
|
|
||
| # 5️⃣ Final enforcement gate | ||
| enforce: | ||
| name: Enforce Authority Decision | ||
| runs-on: ubuntu-latest | ||
| needs: [govern, step-up] | ||
| if: always() | ||
| steps: | ||
| - run: | | ||
| DECISION="${{ needs.govern.outputs.decision }}" | ||
| RECEIPT="${{ needs.govern.outputs.receipt }}" | ||
|
|
||
| echo "Final decision: $DECISION" | ||
| echo "Receipt: $RECEIPT" | ||
|
|
||
| if [ -z "$RECEIPT" ]; then | ||
| echo "Missing receipt → hard deny" | ||
| exit 1 | ||
| fi | ||
|
|
||
| if [ "$DECISION" = "PERMIT" ]; then | ||
| echo "✅ Execution permitted" | ||
| exit 0 | ||
| fi | ||
|
|
||
| echo "❌ Execution denied" | ||
| exit 1 | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This adds a second pull_request workflow with the same name and body as the already-present
.github/workflows/governed_execution.yml(checked that file in the repo). With both files active, every PR runs the governed execution gate twice and calls the external/re/authorizeservice twice, which can leave contributors with duplicate checks to satisfy and duplicate authorization side effects; delete one copy or replace the existing file instead of adding another.Useful? React with 👍 / 👎.