diff --git a/README.md b/README.md index 45924de..6b6d562 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,106 @@ HTTPS proves that a connection is secure. ProofPath proves that an action was au > HTTPS proves the channel. ProofPath proves the action. +## Agent Payment Guard + +> **Model output is a proposal, not authorization.** + +ProofPath is an external authorization and evidence layer for AI-agent payments. + +It verifies signed human intent before execution and exports tamper-evident evidence for every ACCEPT, HOLD, or BLOCK decision. + +```text +AI agents will need payment rails. +Payment rails need authorization. +Authorization needs evidence. +ProofPath provides that evidence. +``` + +**What it does:** + +- Requires a signed intent envelope before any payment is executed +- Enforces policy: asset allow-list, budget cap, recipient scope, recurring approval +- Persists spent nonces — a replayed envelope is always `BLOCK / INTENT_REPLAYED` +- Writes every decision to a hash-chained `audit.jsonl` that survives service restart +- Exports a portable evidence bundle verifiable offline without the live service + +**What it does not do:** no real wallet, no token transfer, no custody, no private keys, no SDK, no RPC, no JWS, no EIP-712. + +### Architecture + +```mermaid +flowchart TD + A(["AI Agent\n(model output = proposal)"]) + B(["Payment Proposal\nJSON"]) + C(["ProofPath\nGuard Service\n:8787"]) + D(["Policy Engine\npayment_policy.json"]) + E(["Signed Intent Verifier\ndemo-sha256-v0"]) + F(["Replay Store\n.proofpath/replay-store.json"]) + G(["Hash-Chained Audit Log\n.proofpath/audit.jsonl"]) + H(["Evidence Export Bundle\nproofpath-evidence-bundle/"]) + I(["Mock / Future Payment Rail"]) + J(["ACCEPT"]) + K(["BLOCK / HOLD"]) + + A -->|proposes| B + B -->|POST /v1/payment-proposals/evaluate| C + C -->|check asset, budget, recipient, scope| D + C -->|verify signature, expiry, nonce| E + E -->|nonce lookup| F + C -->|append record| G + G -->|export script| H + C --> J + C --> K + J -->|execution_allowed=true| I + K -->|execution_allowed=false| A + + style J fill:#d4f1d4,stroke:#4a9e4a,color:#1a4a1a + style K fill:#f7d4d4,stroke:#9e4a4a,color:#4a1a1a + style H fill:#d4e8f7,stroke:#4a7a9e,color:#1a3a4a +``` + +Full architecture diagrams: [`docs/architecture.md`](docs/architecture.md) + +### Quickstart + +```bash +# install: stdlib only, no dependencies + +# run all checks +bash examples/agent-payment-guard/run_demo_check.sh +bash examples/agent-payment-guard/run_service_check.sh +bash examples/agent-payment-guard/run_evidence_export_check.sh + +# full end-to-end story: ACCEPT -> replay BLOCK -> export -> verify +bash examples/agent-payment-guard/run_e2e_evidence_demo.sh +``` + +Expected output: + +```text +[e2e] step 1 — valid signed intent: ACCEPT + decision: ACCEPT + execution_allowed: true + +[e2e] step 2 — replay same envelope: BLOCK / INTENT_REPLAYED + decision: BLOCK + reason: INTENT_REPLAYED + execution_allowed: false + +[e2e] step 3 — export evidence bundle + hash chain: chain valid (2 records) + bundle ready: proofpath-evidence-bundle/ + +[e2e] step 4 — verify bundled audit log + audit log: OK (2 records, chain valid) + +[e2e] ✓ ProofPath Agent Payment Guard demo complete. +``` + +See [`docs/demo-transcript-payment-guard.md`](docs/demo-transcript-payment-guard.md) for full expected output. + +--- + ## 60-second reviewer summary **ProofPath is a defensive pre-execution gateway that prevents valid AI-agent/API credentials from becoming unsafe, unaudited, or irreversible actions.** @@ -20,12 +120,11 @@ ProofPath does **not** replace HTTPS, OAuth, IAM, API keys, or ordinary infrastr If you arrived here from an already-submitted grant application under an earlier name or framing, start with the [Submitted Application Reviewer Bridge](docs/SUBMITTED_APPLICATION_REVIEWER_BRIDGE.md). To understand how the related repositories fit together, see the [Ecosystem Graph](docs/ECOSYSTEM_GRAPH.md). -### Two ways to use ProofPath v0.1 - -ProofPath v0.1 now has two practical product surfaces: +### Three product surfaces | Surface | Path | What it gives you | | --- | --- | --- | +| Agent Payment Guard | [`examples/agent-payment-guard/`](examples/agent-payment-guard/) | Authorization and evidence layer for AI-agent payments. Signed intent, policy, replay protection, hash-chained audit, portable evidence bundle. | | CI evidence gate | [`action.yml`](action.yml), [`docs/GITHUB_ACTION_QUICKSTART.md`](docs/GITHUB_ACTION_QUICKSTART.md) | Turn ProofPath audit logs into CI-verifiable metrics and pass/fail checks. | | Personal Agent Guard | [`examples/personal-agent-guard/`](examples/personal-agent-guard/) | Add a local approval boundary and audit log around Claude Code / Codex-style AI coding tools. | @@ -71,7 +170,8 @@ The current prototype demonstrates: - hash-chained JSONL audit logs; - dangerous-action and real-model-agent demos; - reusable GitHub Action evidence gate; -- local Personal Agent Guard for Claude Code / Codex-style tools. +- local Personal Agent Guard for Claude Code / Codex-style tools; +- Agent Payment Guard with signed intent, replay protection, and portable evidence export. ### ACCEPT vs BLOCK @@ -108,6 +208,10 @@ Reviewers can run the path locally without trusting a hidden service: start with - [Audit log verification](docs/audit-log-verification.md) - [ProofPath v0.1 landing](docs/LANDING_V0_1.md) - [Personal Agent Guard](examples/personal-agent-guard/) +- [Agent Payment Guard](examples/agent-payment-guard/) +- [Architecture diagrams](docs/architecture.md) +- [Agent Payment Guard demo transcript](docs/demo-transcript-payment-guard.md) +- [Agent Payment Guard service docs](docs/agent-payment-guard-service.md) - [Reviewer summary](docs/reviewer-summary.md) - [ProofPath v0.1 Product Milestone](docs/RELEASE_V0_1.md) - [Evidence Packet v0.1](docs/EVIDENCE_PACKET_V0_1.md) @@ -343,6 +447,8 @@ Protected API Append-only audit log ``` +See [`docs/architecture.md`](docs/architecture.md) for full Mermaid system diagrams. + ## Planned components ```text diff --git a/docs/architecture.md b/docs/architecture.md new file mode 100644 index 0000000..1c24cbc --- /dev/null +++ b/docs/architecture.md @@ -0,0 +1,82 @@ +# ProofPath Architecture + +## Agent Payment Guard — System Diagram + +```mermaid +flowchart TD + A(["AI Agent\n(model output = proposal)"]) + B(["Payment Proposal\nJSON"]) + C(["ProofPath\nGuard Service\n:8787"]) + D(["Policy Engine\npayment_policy.json"]) + E(["Signed Intent Verifier\ndemo-sha256-v0"]) + F(["Replay Store\n.proofpath/replay-store.json"]) + G(["Hash-Chained Audit Log\n.proofpath/audit.jsonl"]) + H(["Evidence Export Bundle\nproofpath-evidence-bundle/"]) + I(["Mock / Future Payment Rail\n(not in scope)"]) + J(["ACCEPT"]) + K(["BLOCK / HOLD"]) + + A -->|proposes| B + B -->|POST /v1/payment-proposals/evaluate| C + C -->|check asset, budget, recipient, scope| D + C -->|verify signature, expiry, nonce| E + E -->|nonce lookup O1| F + C -->|append record| G + G -->|export_payment_guard_evidence.py| H + C -->|decision| J + C -->|decision| K + J -->|execution_allowed=true| I + K -->|execution_allowed=false| A + + style J fill:#d4f1d4,stroke:#4a9e4a,color:#1a4a1a + style K fill:#f7d4d4,stroke:#9e4a4a,color:#4a1a1a + style H fill:#d4e8f7,stroke:#4a7a9e,color:#1a3a4a + style F fill:#fffbe6,stroke:#a89a2a,color:#3a3010 +``` + +## Decision flow + +```mermaid +flowchart LR + P([Proposal]) --> G{Guard} + G -->|asset allowed?| A1{Yes} + G -->|No| BLOCK1([BLOCK\nASSET_NOT_ALLOWED]) + A1 -->|amount <= budget?| A2{Yes} + A1 -->|No| BLOCK2([BLOCK\nOVER_BUDGET]) + A2 -->|recipient allowed?| A3{Yes} + A2 -->|No| BLOCK3([BLOCK\nRECIPIENT_NOT_ALLOWED]) + A3 -->|recurring -> approval?| A4{OK} + A3 -->|missing approval| HOLD([HOLD\nRECURRING_REQUIRES_APPROVAL]) + A4 -->|intent envelope present?| A5{Yes} + A4 -->|No + strict mode| BLOCK4([BLOCK\nMISSING_INTENT_ENVELOPE]) + A5 -->|nonce fresh?| A6{Yes} + A5 -->|replayed| BLOCK5([BLOCK\nINTENT_REPLAYED]) + A6 -->|signature valid?| A7{Yes} + A6 -->|invalid| BLOCK6([BLOCK\nINVALID_INTENT_SIGNATURE]) + A7 --> ACCEPT([ACCEPT\nPAYMENT_WITHIN_SIGNED_INTENT_ENVELOPE]) + + style ACCEPT fill:#d4f1d4,stroke:#4a9e4a,color:#1a4a1a + style BLOCK1 fill:#f7d4d4,stroke:#9e4a4a,color:#4a1a1a + style BLOCK2 fill:#f7d4d4,stroke:#9e4a4a,color:#4a1a1a + style BLOCK3 fill:#f7d4d4,stroke:#9e4a4a,color:#4a1a1a + style BLOCK4 fill:#f7d4d4,stroke:#9e4a4a,color:#4a1a1a + style BLOCK5 fill:#f7d4d4,stroke:#9e4a4a,color:#4a1a1a + style BLOCK6 fill:#f7d4d4,stroke:#9e4a4a,color:#4a1a1a + style HOLD fill:#fff3cc,stroke:#b8860b,color:#3a2a00 +``` + +## Evidence layer + +```mermaid +flowchart LR + A([audit.jsonl\nhash-chained]) --> V([verify_audit_log.py]) + R([replay-store.json\nnonce index]) --> E + A --> E([export_payment_guard_evidence.py]) + C([payment_guard_service_config.json]) --> E + P([payment_policy.json]) --> E + E --> B(["proofpath-evidence-bundle/\naudit.jsonl\nreplay-store.json\nconfig.json\npolicy.json\nverification_report.json"]) + V --> OK([chain valid]) + + style B fill:#d4e8f7,stroke:#4a7a9e,color:#1a3a4a + style OK fill:#d4f1d4,stroke:#4a9e4a,color:#1a4a1a +``` diff --git a/docs/demo-transcript-payment-guard.md b/docs/demo-transcript-payment-guard.md new file mode 100644 index 0000000..6752919 --- /dev/null +++ b/docs/demo-transcript-payment-guard.md @@ -0,0 +1,82 @@ +# Agent Payment Guard — E2E Demo Transcript + +Expected output from `bash examples/agent-payment-guard/run_e2e_evidence_demo.sh`. + +## Story + +```text +AI agents will need payment rails. +Payment rails need authorization. +Authorization needs evidence. +ProofPath provides that evidence. +``` + +Core principle: + +```text +Model output is a proposal, not authorization. +``` + +## Expected output + +``` +[e2e] ProofPath Agent Payment Guard — end-to-end evidence demo +[e2e] starting guard service (enforce mode, signed intent required)... +[e2e] service ready. + +[e2e] step 1 — valid signed intent: ACCEPT + decision: ACCEPT + execution_allowed: true + audit_hash: sha256:... + +[e2e] step 2 — replay same envelope: BLOCK / INTENT_REPLAYED + decision: BLOCK + reason: INTENT_REPLAYED + execution_allowed: false + +[e2e] step 3 — stopping service and exporting evidence bundle +[export] hash chain: chain valid (2 records) +[export] copied .proofpath/audit.jsonl -> proofpath-evidence-bundle/audit.jsonl +[export] copied examples/agent-payment-guard/payment_guard_service_config.json -> proofpath-evidence-bundle/payment_guard_service_config.json +[export] copied examples/agent-payment-guard/payment_policy.json -> proofpath-evidence-bundle/payment_policy.json +[export] copied .proofpath/replay-store.json -> proofpath-evidence-bundle/replay-store.json +[export] wrote proofpath-evidence-bundle/verification_report.json + +[export] bundle ready: proofpath-evidence-bundle/ + records : 2 + nonces : 1 + chain : OK + +[e2e] step 4 — verifying bundled audit log hash chain + audit log: OK (2 records, chain valid) + +[e2e] ✓ ProofPath Agent Payment Guard demo complete. + +Bundle contents: + proofpath-evidence-bundle/ + audit.jsonl (2 records) + replay-store.json (1 spent nonce) + payment_guard_service_config.json + payment_policy.json + verification_report.json + +What was demonstrated: + ACCEPT valid signed intent envelope + BLOCK replayed intent (INTENT_REPLAYED) + EXPORT portable evidence bundle + VERIFY hash-chain integrity confirmed +``` + +## Decisions + +| Step | Proposal | Envelope | Decision | Reason | +|---|---|---|---|---| +| 1 | valid_micro_payment | intent.valid.json | ACCEPT | PAYMENT_WITHIN_SIGNED_INTENT_ENVELOPE | +| 2 | valid_micro_payment | intent.valid.json (same) | BLOCK | INTENT_REPLAYED | + +## What this proves + +- The guard enforces signed human intent before payment execution. +- A spent nonce cannot be reused — replay protection is persistent across restarts. +- Every decision is hash-chained in `audit.jsonl` — the chain is verifiable offline. +- The evidence bundle is portable: any reviewer can re-run `verify_audit_log.py` without access to the live service. diff --git a/examples/agent-payment-guard/run_e2e_evidence_demo.sh b/examples/agent-payment-guard/run_e2e_evidence_demo.sh new file mode 100644 index 0000000..aa2ae1e --- /dev/null +++ b/examples/agent-payment-guard/run_e2e_evidence_demo.sh @@ -0,0 +1,141 @@ +#!/usr/bin/env bash +# ProofPath Agent Payment Guard — end-to-end evidence demo. +# +# Runs the full product story in one script: +# 1. Start guard service (enforce mode, signed intent required) +# 2. Send valid signed-intent proposal -> ACCEPT +# 3. Replay same envelope -> BLOCK / INTENT_REPLAYED +# 4. Stop service, export evidence bundle +# 5. Verify bundled audit log hash chain +# 6. Print summary +# +# Run from repo root: +# bash examples/agent-payment-guard/run_e2e_evidence_demo.sh +set -euo pipefail + +ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" +cd "$ROOT_DIR" + +rm -rf proofpath-evidence-bundle/ +rm -f .proofpath/audit.jsonl .proofpath/replay-store.json + +HOST="127.0.0.1" +PORT="18789" +SERVICE="examples/agent-payment-guard/payment_guard_service.py" +CONFIG="examples/agent-payment-guard/payment_guard_service_config.json" + +echo +echo "[e2e] ProofPath Agent Payment Guard \xe2\x80\x94 end-to-end evidence demo" +echo "[e2e] starting guard service (enforce mode, signed intent required)..." + +python3 "$SERVICE" \ + --config "$CONFIG" \ + --port "$PORT" \ + >/tmp/payment_guard_e2e.log 2>&1 & +SERVICE_PID=$! +cleanup() { + kill "$SERVICE_PID" >/dev/null 2>&1 || true + rm -rf proofpath-evidence-bundle/ +} +trap cleanup EXIT + +for _ in $(seq 1 50); do + if curl -fsS "http://$HOST:$PORT/v1/health" >/dev/null 2>&1; then + break + fi + sleep 0.1 +done +echo "[e2e] service ready." +echo + +VALID_INTENT=$(cat examples/agent-payment-guard/intent_envelopes/intent.valid.json) +VALID_PROPOSAL=$(cat examples/agent-payment-guard/payment_proposal.valid_micro_payment.json) + +# --- step 1: ACCEPT --- +echo "[e2e] step 1 \xe2\x80\x94 valid signed intent: ACCEPT" +RESP=$(curl -fsS -X POST "http://$HOST:$PORT/v1/payment-proposals/evaluate" \ + -H 'content-type: application/json' \ + -d "{\"mode\":\"enforce\",\"proposal\":$VALID_PROPOSAL,\"intent_envelope\":$VALID_INTENT}") +python3 - </dev/null 2>&1 || true +sleep 0.2 + +python3 scripts/export_payment_guard_evidence.py \ + --out proofpath-evidence-bundle/ +echo + +# --- step 4: verify bundled audit log --- +echo "[e2e] step 4 \xe2\x80\x94 verifying bundled audit log hash chain" +python3 - <<'PYEOF' +import json, pathlib, sys +from hashlib import sha256 + +def canonical(r): return json.dumps(r, sort_keys=True, separators=(',', ':'), ensure_ascii=False) +def compute_hash(r): + p = dict(r); p.pop('hash', None) + return 'sha256:' + sha256(canonical(p).encode()).hexdigest() + +path = pathlib.Path('proofpath-evidence-bundle/audit.jsonl') +lines = [l for l in path.read_text().splitlines() if l.strip()] +prev = 'GENESIS' +for i, line in enumerate(lines, 1): + rec = json.loads(line) + assert rec.get('previous_hash') == prev, f"line {i}: previous_hash mismatch" + assert rec.get('hash') == compute_hash(rec), f"line {i}: hash mismatch" + prev = rec['hash'] +print(f" audit log: OK ({len(lines)} records, chain valid)") +PYEOF +echo + +# --- summary --- +RECORDS=$(python3 -c "import pathlib; lines=[l for l in pathlib.Path('.proofpath/audit.jsonl').read_text().splitlines() if l.strip()]; print(len(lines))") +NONCES=$(python3 -c "import json,pathlib; d=json.loads(pathlib.Path('.proofpath/replay-store.json').read_text()); print(len(d))") + +echo "[e2e] \xe2\x9c\x93 ProofPath Agent Payment Guard demo complete." +echo +echo "Bundle contents:" +echo " proofpath-evidence-bundle/" +echo " audit.jsonl ($RECORDS records)" +echo " replay-store.json ($NONCES spent nonce)" +echo " payment_guard_service_config.json" +echo " payment_policy.json" +echo " verification_report.json" +echo +echo "What was demonstrated:" +echo " ACCEPT valid signed intent envelope" +echo " BLOCK replayed intent (INTENT_REPLAYED)" +echo " EXPORT portable evidence bundle" +echo " VERIFY hash-chain integrity confirmed" + +# disable cleanup trap for bundle (leave for user inspection) +trap - EXIT +kill "$SERVICE_PID" >/dev/null 2>&1 || true