# Reference Pipeline — from AI-agent PR to cryptographically-attested merge End-to-end walkthrough of the Occasio attestation pipeline. Read top-to-bottom; every step has a copy-paste artefact and an explanation of what it proves. ## What this pipeline is for When an AI coding agent (Claude Code, Cline, MCP-routed, etc.) opens a PR, the reviewer's question is *"What did the agent actually do?"* — every tool call, every blocked attempt, every secret redacted, under which policy, on what audit-chain commitment. This pipeline answers that question with a signed artifact that can be verified offline by any third party using only `cosign` and the published predicate type. Three deliverables land on the PR: 1. A **Check Run** with a human-readable summary of the run. 2. A workflow **artifact** containing the signed predicate JSON and the Sigstore Bundle. 3. A **View Evidence** link that opens the standalone viewer page with both files pre-loaded. ## Try it locally in 30 seconds ```bash occasio demo attest ``` This builds a synthetic audit chain, an unsigned attestation, runs the canonical-JSON round-trip check, and previews the Check Run summary. No Sigstore, no GitHub, no API key — just the pipeline working against in-memory data. Use this to validate the build end-to-end before deploying any of the rest. ## Step 1 — your agent runs under Occasio A Occasio session must produce events into `~/.occasio/pipeline-events.jsonl`. The simplest way is to invoke Claude Code (or any supported agent) through the local proxy: ```bash occasio claude --hardened ``` `--hardened` routes `Read`/`Glob`/`Grep` through the unified runtime so tool calls are intercepted locally, distillation applied, and secret scanning runs on every tool result. The `~/.occasio/session.json` file gets a fresh `run_id` per session. ## Step 2 — produce an attestation locally (sanity check) After a session ends, run: ```bash occasio attest --run-id "$(jq -r .run_id ~/.occasio/session.json)" ``` This writes `attestation.json` to the cwd. The predicate is unsigned (`signature: null`) — that part lands in the GitHub Action step below. Inspect the predicate; the file is human-readable JSON. The `audit_chain.last_hash` is the commitment: signing it later transitively commits to every event in the slice. ## Step 3 — drop in the GitHub Action Create `.github/workflows/attest-on-pr.yml` in your repo: ```yaml name: Attest AI-generated PR on: pull_request: branches: [main] permissions: id-token: write # Sigstore keyless via GitHub OIDC checks: write # post the PR Check Run contents: read jobs: attest: runs-on: ubuntu-latest steps: - uses: actions/checkout@v5 with: fetch-depth: 2 # so files-changed can diff HEAD^..HEAD # ── Your AI-agent step here ──────────────────────────────────── # The agent must run under Occasio so its tool calls land in # ~/.occasio/pipeline-events.jsonl. Example with Claude Code: - run: npm i -g @occasiolabs/occasio @anthropic-ai/claude-code - run: occasio claude --hardened < .github/agent-prompt.txt env: ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} # ── Sign + Check Run ─────────────────────────────────────────── - uses: occasiolabs/occasio/integrations/attest-action@v1 # All inputs optional — run_id auto-resolves from session.json, # paths default to ~/.occasio/*. Defaults are tuned for the # 95% case. ``` That's it. The composite Action handles: - `occasio bundle --sign` using the workflow's OIDC token (no key management) - Self-verifying the bundle with `occasio verify --strict`, then uploading the single `run.occasio.json` evidence bundle as a workflow artifact (90-day retention) - Creating the Check Run via the GitHub API ## Step 4 — what reviewers see The Check Run lands on the PR as: ``` ✓ Occasio Attested · 47 calls · 2 blocked Claude Opus 4.7 · Policy strict-v2.1 (sha a126…3a) Chain ✓ verified · Signature ✓ Sigstore keyless [View evidence ↗] [Artifact ↗] ``` Click **View evidence** to open the [viewer](https://occasiolabs.github.io/attest-view) with the artifact's two JSON files. The viewer runs two browser-side checks (DSSE-payload equivalence + audit-chain replay) and surfaces the Rekor transparency log link for cryptographic verification. The viewer **deliberately does not** verify the Sigstore certificate chain in-browser — bundling Fulcio/Rekor trust roots in-browser is a serious build problem we have not solved cheaply, and we are honest about it on the page itself. Offline crypto-verification is one CLI call: ```bash occasio verify --strict run.occasio.json ``` That command runs six checks in order, all of which must pass — schema, manifest integrity, chain-slice integrity (anchored to the attestation's `first_hash`/`last_hash`), policy binding, git-state cross-check, and the Sigstore signature. See [VERIFY.md](VERIFY.md) for the full list, and [python-verifier.md](python-verifier.md) for the independent Python re-verification (`python docs/verify_bundle.py run.occasio.json --strict`). ## Step 5 — what auditors do Auditors do not need access to the producer's machine. They download the workflow artifact, install Occasio (or `cosign`), and verify offline. The signed artifact is portable and self-contained: predicate JSON + Sigstore Bundle + (optionally) the chain file. For a SOC2 audit period the workflow becomes: 1. Pull all `occasio-evidence-bundle` artifacts from the period (GitHub API) 2. For each: `occasio verify --strict run.occasio.json` and capture the exit code 3. Aggregate the `execution_summary` data: how many runs, how many blocks, what rules, what files The audit chain is hash-linked across all of an agent's runs on the same machine; verifying any one slice does not require touching the producer's full log. ## Compatibility and what's stable - **Predicate URI** `https://github.com/occasiolabs/occasio/spec/agent-attestation/v1` is **canonical**. It will not be moved or re-pointed. - **Required fields** in v1 do not change without bumping the URI to `/v2`. - **New optional fields** can land in v1.x (currently reserved: `subject.git_commit`, `subject.files_changed` — already in the schema, populated by the GitHub Action). - The **Sigstore Bundle** is the standard `sigstore-bundle+json;version=0.2` shape — works with `cosign`, `sigstore-js`, `sigstore-python`, any future conformant tool. ## What this does NOT yet do - **Multi-commit attestations.** Today the predicate binds to a single `run_id`. v1.1 will likely add `subject.git_commits[]` and a way to merge slices for a PR that includes N commits from M runs. - **Policy provenance.** `policy.file_hash` commits to the file bytes. We do not yet carry the *origin* of the policy (was it committed to a repo? signed by a security team?). v1.1 may add `policy.attestation_url` for nested signed claims. ## Reference / further reading - [`spec/agent-attestation/v1/README.md`](../spec/agent-attestation/v1/README.md) — predicate type specification - [`schemas/agent-attestation-v1.json`](../schemas/agent-attestation-v1.json) — authoritative JSON Schema - [`integrations/attest-action/`](../integrations/attest-action/) — the GitHub Action - [`integrations/attest-view/`](../integrations/attest-view/) — the static viewer page