Chio/Docs

ProductsProductsnew

Proof Room

Run the standalone server and CLI that recompute a bundle's verifier report from source inputs before serving a dashboard.

Source

Verified against 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

The dashboard displays the server's verdict derived from source inputs. A tampered 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:

bash
# 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-room

Or bring it up alongside the other demo services with Compose. The chio-proof-room service builds the same target and publishes 7391:

examples/docker/compose.yaml
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:

deploy/docker/Dockerfile
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.

bash
# 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>]
FlagRequiredPurpose
--bundle <dir>alwaysBundle directory containing manifest.json.
--ui-dir <dir>serve modeBuilt dashboard SPA directory; must contain index.html. Defaults to CHIO_PROOF_ROOM_UI_DIR.
--fixture-root <dir>noRoot of the fixture catalog. Defaults to CHIO_PROOF_FIXTURE_ROOT.
--listen <addr>noBind address. Defaults to 0.0.0.0:7391.
--doctor-report <path>noWrite a quickstart doctor report to this path after verification.
--verify-onlynoVerify 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.

FieldMeaning
bundle_id, fixture_idBundle and source fixture identity, echoed back in the verifier report and doctor report.
transaction_passport_refRoot chio.transaction-passport.v1 passport the report is recomputed from.
evidence_graph_refThe chio.transaction.evidence-graph.v1 graph subsets are routed from.
verifier_report_refClaimed chio.transaction.verifier-report.v1 report, compared with the recomputed report.
proof_room_verifier_report_refUI-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.
signaturekind: 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:

  1. Read manifest.json, reject any non-regular file in the bundle tree, and validate the manifest against bundle.schema.json.
  2. 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-pinned CHIO_PROOF_ROOM_TRUSTED_BUNDLE_SIGNER_KEYS.
  3. 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.
  4. Recompute the source verifier report from the transaction passport and compare it to the manifest's claimed verifier_report_ref.
  5. 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.
  6. Verify the remaining artifacts hash correctly and cross-check the UI-facing report against the recomputed verdict.

Fail closed

Any schema, hash, signature, or claim mismatch rejects the bundle with a 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.

RouteServes
GET /Temporary redirect to /proof-room?view=proof-room.
GET /proof-room, /assets/*The dashboard index.html and its built assets.
GET /manifest.jsonThe verified bundle manifest.
GET /artifacts/*, /negatives/*, /roots/*, /ui/*, /verifier/*Allow-listed bundle assets under each namespace.
GET /proof-room-fixture-catalog.jsonThe 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.jsonThe pinned trusted signer set (chio.proof-room.trusted-bundle-signers.v1); 412 if none are configured.
POST /proof-room/upload/verifyVerify 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:

VariableConfigures
CHIO_PROOF_ROOM_UI_DIRDefault --ui-dir (the dashboard dist).
CHIO_PROOF_FIXTURE_ROOTDefault --fixture-root (the fixture catalog root).
CHIO_PROOF_ROOM_TRUSTED_BUNDLE_SIGNER_KEYSSigners allowed to sign the bundle DSSE envelope, intersected with the bundle's own trust-roots artifact.
CHIO_PROOF_ROOM_TRUSTED_RECEIPT_KERNEL_KEYSReceipt kernel keys accepted for the receipt-coverage matrix.
CHIO_TRANSACTION_TRUSTED_ROOT_KEYSTrusted transaction passport root signers.
CHIO_SWARM_TRUSTED_WITNESS_KEYSTrusted swarm-authority witness keys.
CHIO_DISCLOSURE_TRUSTED_LINEAGE_SIGNER_KEYSTrusted disclosure-lineage signers.
CHIO_DISCLOSURE_TRUSTED_CRYPTO_CONTEXT_REPORT_SIGNER_KEYSTrusted 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.

proof-doctor-report.json
{
  "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.

bash
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