ProductsProductsnew
Proof Room
Run the standalone server and CLI that recompute a bundle's verifier report from source inputs before serving a dashboard.
Source
crates/products/chio-proof-room (the chio-proof-room binary, server, and bundle verification modules), spec/schemas/chio-proof-room/v1, deploy/docker/Dockerfile, and examples/docker/compose.yaml.What it verifies
A Proof Room bundle is a signed directory containing a manifest (chio.proof-room.bundle.v1), a root transaction passport, an evidence graph, a claimed verifier report, receipt evidence, and a set of negative-case fixtures. The server sits at an untrusted edge. It reads the bundle a caller supplies and treats the manifest's verdict as an assertion that must be checked before rendering.
The server recomputes the report. It does not read verifier_report_ref and rendering it, the server routes evidence-graph subsets to the domain verifier crates named by each policy's required_claims, rebuilds the report, and compares the results. The domain verifiers are the same ones the chio CLI uses: chio-transaction-passport (root passport, evidence graph, runtime security), chio-swarm-authority, chio-runtime-proof-parity, chio-web3 settlement proofs, chio-commerce-order, chio-disclosure-lineage, chio-selective-disclosure (BBS), and the enterprise, risk, trust-market, and agent-web verifiers.
Recomputed verdicts
verifier_report_ref that claims verified fails the comparison with the recomputed report and is not served.The Docker Quickstart
The quickstart ships as a single image target, chio-proof-room-quickstart, in deploy/docker/Dockerfile. It bakes the chio-proof-room binary, the built dashboard SPA, and the fixtures/proof-room tree, then runs verification before it binds. Build it against the checked-in bundle:
# Build the quickstart image.
docker build -f deploy/docker/Dockerfile \
--target chio-proof-room-quickstart \
-t chio-proof-room:local .
# Run it: the dashboard is on port 7391.
docker run -d -p 127.0.0.1:7391:7391 chio-proof-room:local
# Open the verified dashboard.
open http://127.0.0.1:7391/?view=proof-roomOr bring it up alongside the other demo services with Compose. The chio-proof-room service builds the same target and publishes 7391:
chio-proof-room:
image: chio-proof-room:local
build:
context: ../..
dockerfile: deploy/docker/Dockerfile
target: chio-proof-room-quickstart
ports:
- "${CHIO_PROOF_ROOM_PORT:-7391}:7391"The image runs as the non-root chio user (uid/gid 10001) on a digest-pinned Alpine 3.22 base with tini as pid 1. The binary lands at /usr/local/bin/chio-proof-room, built in a dedicated proof-room-builder stage with cargo build --release --locked -p chio-proof-room. The container CMD is the serve invocation, pinned to the shipped first-run bundle:
EXPOSE 7391
CMD ["/sbin/tini", "--", "/usr/local/bin/chio-proof-room", \
"--bundle", "/opt/chio/fixtures/proof-room/first-run/single-call-authority/proof-room-bundle", \
"--ui-dir", "/opt/chio/dashboard/dist", \
"--fixture-root", "/opt/chio/fixtures/proof-room", \
"--listen", "0.0.0.0:7391", \
"--doctor-report", "/opt/chio/proof-doctor-report.json"]The image is the same multi-stage pattern documented in Container Images, sharing the Rust builder and the Vite dashboard builder with the other demo targets.
The Binary
chio-proof-room is a supported public entry point, distinct from the full chio CLI and marked public_entrypoint = true in its manifest metadata. It has two modes: serve, and verify-only.
# Serve mode: verify, then bind and serve the dashboard.
chio-proof-room --bundle <proof-room-bundle> --ui-dir <dashboard-dist> \
[--fixture-root <fixtures/proof-room>] [--listen <addr>] \
[--doctor-report <path>]
# Verify-only: run the pipeline and exit without binding a listener.
chio-proof-room --bundle <proof-room-bundle> --verify-only \
[--doctor-report <path>]| Flag | Required | Purpose |
|---|---|---|
--bundle <dir> | always | Bundle directory containing manifest.json. |
--ui-dir <dir> | serve mode | Built dashboard SPA directory; must contain index.html. Defaults to CHIO_PROOF_ROOM_UI_DIR. |
--fixture-root <dir> | no | Root of the fixture catalog. Defaults to CHIO_PROOF_FIXTURE_ROOT. |
--listen <addr> | no | Bind address. Defaults to 0.0.0.0:7391. |
--doctor-report <path> | no | Write a quickstart doctor report to this path after verification. |
--verify-only | no | Verify and exit; no listener is bound and --ui-dir is not required. |
Verify-only is the CI hook: it verifies a bundle and, with --doctor-report, records the verdict without opening a socket. A verification failure prints a proof-room.* error code to stderr and exits non-zero.
Bundle Manifest
The manifest is schema-locked to chio.proof-room.bundle.v1 with hash_algorithm fixed to sha256. Each reference is a bundle reference with a relative path, a 64-hex sha256, and the file's schema.
| Field | Meaning |
|---|---|
bundle_id, fixture_id | Bundle and source fixture identity, echoed back in the verifier report and doctor report. |
transaction_passport_ref | Root chio.transaction-passport.v1 passport the report is recomputed from. |
evidence_graph_ref | The chio.transaction.evidence-graph.v1 graph subsets are routed from. |
verifier_report_ref | Claimed chio.transaction.verifier-report.v1 report, compared with the recomputed report. |
proof_room_verifier_report_ref | UI-facing chio.proof-room.verifier-report.v1 report, with ui_verdict_source: verifier_report_ref. |
claims[] | Each has claim_id, required_artifacts, checker, and a result of verified, failed, or unsupported. |
receipt_coverage[] | The terminal-receipt matrix: one row per category, each covered (with artifact_path and terminal_status) or excluded (with exclusion_reason). |
negative_cases[] | Tamper fixtures, each pinning an expected_failure_code and its observed_failure_code. |
signature | kind: detached-dsse plus a signature_ref to the detached DSSE envelope. |
The three receipt-coverage categories are runtime_terminal_allow, runtime_terminal_denial, and runtime_terminal_failure. A covered row's terminal_status is one of the runtime terminal statuses, from allowed_executed and denied_pre_dispatch through failed_timeout_after_tool_entry.
Verification Pipeline
serve_proof_room validates the UI directory, runs the validation sequence against the bundle, then binds a listener. The sequence runs in order:
- Read
manifest.json, reject any non-regular file in the bundle tree, and validate the manifest againstbundle.schema.json. - Verify the detached DSSE bundle signature against the trust roots declared in the bundle's own
artifacts/authority/trust-roots.json, intersected with the env-pinnedCHIO_PROOF_ROOM_TRUSTED_BUNDLE_SIGNER_KEYS. - Verify the transaction passport and evidence graph refs, and, for first-run bundles, the capability-proof, guard-report, and trust-roots artifacts plus their evidence-graph node bindings.
- Recompute the source verifier report from the transaction passport and compare it to the manifest's claimed
verifier_report_ref. - Verify every claim is bundle-scoped or covered by the recomputed report, verify the receipt-coverage matrix (with kernel-signature checks per covered receipt), and replay every negative case against a temp copy of the bundle, checking its exact
expected_failure_code. - Verify the remaining artifacts hash correctly and cross-check the UI-facing report against the recomputed verdict.
Fail closed
proof-room.* error code, and the server refuses to bind. A negative case that fails to reproduce its expected code, or one that unexpectedly passes, fails the whole run. Bundle-relative paths are canonicalized and must stay under the bundle root, ruling out .., absolute paths, and symlink escapes.Served Endpoints
The axum router exposes the assets enumerated in the verified manifest, plus the dashboard SPA and fixture catalog. A bundle path outside the manifest allow-list returns 404.
| Route | Serves |
|---|---|
GET / | Temporary redirect to /proof-room?view=proof-room. |
GET /proof-room, /assets/* | The dashboard index.html and its built assets. |
GET /manifest.json | The verified bundle manifest. |
GET /artifacts/*, /negatives/*, /roots/*, /ui/*, /verifier/* | Allow-listed bundle assets under each namespace. |
GET /proof-room-fixture-catalog.json | The chio.proof-room.fixture-catalog.v1 catalog of fixtures and negative cases. |
GET /proof-room-fixtures/{id}/{asset} | Per-fixture assets; verifier-report.json is recomputed live, one domain verifier per fixture, with the HTTP status reflecting the verdict. |
GET /proof-room-trusted-bundle-signers.json | The pinned trusted signer set (chio.proof-room.trusted-bundle-signers.v1); 412 if none are configured. |
POST /proof-room/upload/verify | Verify an uploaded bundle. See below. |
The router is wrapped in chio-http-serve hygiene (connection caps and graceful drain). Because assets are read-only there is no receipt store to flush on shutdown.
Trust Configuration
Trust roots are read from CHIO_* environment variables at verification time, never inferred from the bundle. Keys are comma-separated hex public keys. Configuration a bundle's claims require but that is missing is a hard error, not a silent skip. The quickstart image pins the fixture's trust roots:
| Variable | Configures |
|---|---|
CHIO_PROOF_ROOM_UI_DIR | Default --ui-dir (the dashboard dist). |
CHIO_PROOF_FIXTURE_ROOT | Default --fixture-root (the fixture catalog root). |
CHIO_PROOF_ROOM_TRUSTED_BUNDLE_SIGNER_KEYS | Signers allowed to sign the bundle DSSE envelope, intersected with the bundle's own trust-roots artifact. |
CHIO_PROOF_ROOM_TRUSTED_RECEIPT_KERNEL_KEYS | Receipt kernel keys accepted for the receipt-coverage matrix. |
CHIO_TRANSACTION_TRUSTED_ROOT_KEYS | Trusted transaction passport root signers. |
CHIO_SWARM_TRUSTED_WITNESS_KEYS | Trusted swarm-authority witness keys. |
CHIO_DISCLOSURE_TRUSTED_LINEAGE_SIGNER_KEYS | Trusted disclosure-lineage signers. |
CHIO_DISCLOSURE_TRUSTED_CRYPTO_CONTEXT_REPORT_SIGNER_KEYS | Trusted signers for BBS crypto-context reports. |
Bundles whose claims reach the public-settlement verifier read further CHIO_PUBLIC_SETTLEMENT_* variables, including the allowed chain IDs and the reviewed runtime codehashes. The public-settlement independent-chain-head RPC fetch is the server's only outbound network call; it runs through chio-egress-contract's pinned-DNS resolver with redirects denied and a 1 MiB response ceiling.
The Doctor Report
With --doctor-report, the server writes a chio.proof-room.quickstart-doctor-report.v1 JSON file after a passing verification. The quickstart image writes it to /opt/chio/proof-doctor-report.json. It carries the verdict, the bundle and fixture identity, the verifier report ref, and the full receipt-coverage matrix and negative-case list from the manifest.
{
"schema": "chio.proof-room.quickstart-doctor-report.v1",
"verdict": "verified",
"bundle": ".../single-call-authority/proof-room-bundle",
"bundle_id": "proof-room-single-call-authority",
"fixture_id": "single-call-authority",
"verifier_report_ref": { "path": "...", "sha256": "...", "schema": "..." },
"receipt_coverage": [ /* ... */ ],
"negative_cases": [ /* ... */ ]
}The report is a compact, machine-readable receipt that the bundle verified in this image, at this commit, against these trust roots. It is the shipped bridge between the recompute-from-source verifier and the signed receipts it stands over.
Upload Verification
POST /proof-room/upload/verify accepts a multipart bundle upload, runs the same verification pipeline against it in an isolated temp directory, and returns the verdict. The route carries a 32 MiB body limit. Each part's filename is validated as a safe bundle-relative path before it is written; duplicate paths and unsafe segments are rejected.
curl -sS -X POST http://127.0.0.1:7391/proof-room/upload/verify \
-F "manifest.json=@manifest.json" \
-F "artifacts/transaction-passport.json=@artifacts/transaction-passport.json"
# ... one -F per bundle member ...The response is a chio.proof-room.upload-verification.v1 JSON body. A passing bundle returns 200 with verdict: verified and its bundle_id; a bundle that fails verification returns 422 with verdict: failed and the proof-room.* error; a malformed multipart body returns 400.
Next Steps
- Receipts: the signed, append-only evidence the Proof Room bundle is built over.
- Verify Receipts Offline: recompute receipt signatures without the server.
- Container Images: the multi-stage build pattern the quickstart image shares.
- Receipt Format: the terminal-receipt shapes the coverage matrix accounts for.
- Schemas & Errors: the canonical schema and error-code index.