open-standards/sandbox/spec/conformance.md
David Charlot 41dcdb9484
All checks were successful
no-vanity-metrics / Scan committed Markdown for vanity metrics (pull_request) Successful in 3s
sandbox: let an S1-S5 attestation say how it confined the run (SPEC §7.9)
The previous commit made the sealed tier true. It did not make it checkable.
Below S6 the standard requires no evidence at all — §7.5 says so outright, and
`validate_structure` enforces evidence only at S6 (TEE) and S7 (locality) — so
`tier = "S2"` is the host's word with a signature around it, and the honest
`S0` the last commit produced is equally just the host's word.

§7.9 adds an optional `mechanism`: the enforcement runtime (name AND version)
plus a commitment to the policy profile applied and the egress allowlist
installed. An attestation carrying one is `sandbox.attestation/2`; without one
it stays `/1` and canonicalizes to byte-identical JSON, so every attestation
sealed before this section — and every published vector — verifies unchanged.
That is the same add-field/bump-profile/dispatch shape used for `payload_hash`.

What this is careful not to claim: a mechanism is NOT proof of isolation, and
both the SPEC text and the type docs say so. A host willing to misstate its
tier can misstate its profile; a commitment made by the party under scrutiny
cannot bootstrap its own trustworthiness. What changes is the shape of the
claim — an unadorned tier label is unfalsifiable, while a profile_id is
checkable against a known-good profile a relying party already trusts, and a
false one is a specific, attributable lie about a named artifact. A party that
needs proof rather than assertion still requires S6+.

Design notes:

- The commitment length-prefixes each field rather than concatenating them.
  Bare concatenation is not injective: "seatbelt/14" + "5;deny-net" and
  "seatbelt/145" + ";deny-net" would collide. C11 asserts they no longer do.
- Requiring a mechanism is a *relying-party* check, not a producer obligation.
  Making it mandatory would retroactively invalidate every honest attestation
  sealed before §7.9, and a standard does not get to make historical records
  non-conformant. It lives in `require_mechanism_evidence()`, the same posture
  §7.5 already takes for isolation proof.
- A mechanism at S0 is rejected, not ignored. S0 is unconfined; describing a
  boundary that does not exist is incoherent rather than merely redundant.
- `Executor::mechanism()` defaults to `None` — as with `attained_tier()`, the
  component that did the work is the one that gets to describe it, and silence
  beats invention. `run_and_seal` takes it from the executor; the bare
  `seal_run` primitive keeps its old signature and passes `None`.
- `WasmExecutor` is a real producer, so the field is not decorative: it commits
  to fuel metering, the fuel budget and the memory cap — deliberately NOT
  `uj_per_million_fuel`, an accounting coefficient that confines nothing and
  would make two identically-confined runs disagree when someone retunes it.
- wasmtime exposes no version constant and Cargo gives no compile-time access
  to a dependency's resolved version, so `WASMTIME_VERSION` is hand-maintained
  and a test fails the build if it drifts from Cargo.lock. A stale value would
  attest confinement to a runtime that did not run.

Verified: 194 workspace tests pass, conformance passes with no skips across all
11 classes. C4 attestation.json — a published vector — still passes untouched,
which is the backward-compatibility claim holding in practice rather than in
argument.
2026-08-24 23:58:46 -04:00

6.3 KiB
Raw Permalink Blame History

Conformance

Normative companion to SPEC.md §10. RFC 2119 keywords apply.

A host is conformant if, for every isolation tier it advertises, it satisfies every REQUIRED clause of SPEC.md §1–§7 and round-trips the conformance vectors in ../conformance/. A conforming host MUST pass the full pack with no skips for its advertised tiers. The vectors — not any brand — define what is correct.

Vector classes

C1 — Canonicality

The content addressing (b3: + base64url over BLAKE3-256) and the canonical forms (det-CBOR for the receipt core, JCS for the attestation core) are reproduced byte-for-byte. A unit descriptor, a grant set, a receipt core, and an attestation core each address to the fixed ContentId in the vector. No float appears in any canonical form.

C2 — Capability enforcement (deny-by-default)

Given the canonical grant set, the Enforcer returns the fixed allow/deny decision for each query in the vector, including the negatives: a dispatch to an ungranted device class is denied; a write to a read-only path is denied; an egress to an unlisted endpoint is denied; a kv access outside granted prefixes is denied; a host service that was not granted is denied. The empty grant set denies everything.

C3 — Receipt integrity and per-device provenance

A receipt round-trips through its JCR-1 envelope to byte-identical bytes and verifies under the steward key. The per-device records sum to total (field-wise), total.measured_uj is present iff every used class carries one, and the (provenance, measured_uj) coupling holds for every record (HwShunt ⇒ present, Estimator ⇒ absent). The pack includes adversarial negatives: an accelerator run that folds GPU energy into the CPU record (rejected), a HwShunt record with no measured_uj (rejected), an Estimator record carrying a measured_uj (rejected), a total that does not equal the device sum (rejected).

C4 — Attestation signing and verification

An attestation core canonicalizes to the fixed JCS bytes and produces the fixed Ed25519 signature under the known signing key; verification accepts it and rejects a single-bit mutation of any field. The attestation's devices classes match the bound receipt's devices classes. A journal_root present in the attestation replays Consistent against the vector's journal; a tampered journal replays Diverged.

C5 — Tier minimization

Given a grant set, the host selects the lowest tier whose guarantees satisfy it (the maximum of the per-grant minimums in tiers.md). The pack fixes the required tier for a set of grant sets: CPU-only trusted → S0/S1; untrusted code → S2; accelerator via brokered interface → S2; multi-tenant → S3; accelerator via direct assignment → S5; confidential → S6. A host that runs above or below the required tier fails C5.

C6 — Durable run records (§13)

A run record chains execute → suspend → resume segments; the head advances and recomputes from genesis. Resuming a snapshot that differs from the one recorded at suspension is refused, as is an execution while parked or an append after close. Idle energy accumulates across parks; a tampered segment (via the wire form) fails verification.

C7 — Environment manifest (§14)

A devcontainer.json ingests to a canonical, content-addressed manifest whose address is invariant to key order and whitespace. Fields that execute commands or widen the sandbox are refused, and unknown fields are refused rather than silently dropped. A resume offering a drifted manifest address is refused.

C8 — Content-addressed process control (§5.5)

Process control decides on the BLAKE3 of the executable's bytes. A denylisted hash is refused regardless of the binary's name (survives rename / move / wrapper) and overrides every allow rule; when a hash allowlist is set it is authoritative over names; exec is still required.

C9 — Warm pools (§15)

A claim attributes the slot's accrued idle energy to the run and is refused unless the slot's environment address matches. An evicted unclaimed slot records its idle energy as overhead, never zero. The pool's total idle energy equals claimed + overhead + pending — nothing hidden.

C10 — Fleet records (§16)

Every item in a fleet proves against the merkle aggregate root with a logarithmic proof, across odd and even leaf counts. A foreign item on a real proof path fails to verify, and any change to a leaf changes the root.

C11 — Enforcement mechanism (§7.9)

An attestation without a mechanism canonicalizes to byte-identical JSON under the /1 profile, so historical signatures and published vectors still verify; one carrying a mechanism is /2, and the commitment is inside the signed bytes. The commitment is injective across field boundaries — moving bytes between the runtime name and the profile changes the digest. A mechanism at S0 is refused, and the relying-party requirement rejects a bare S1–S5 tier label while an evidenced one satisfies it.

Adversarial obligation

The most valuable vectors are negatives — runs a conformant host must reject. A standard whose vectors only assert the happy path certifies nothing. The committed pack (../conformance/v1/negative.json) carries a C-neg class the harness asserts is rejected:

  • a HwShunt reading with no measured figure, an Estimator carrying one, a total that does not equal the device sum, and a measured-coverage mismatch (SPEC §6);
  • an attestation that omits an accelerator the receipt metered (SPEC §7.2), and an S6 attestation without TEE evidence (SPEC §7.6);
  • a replay journal that diverges and one that is truncated — neither may compare Consistent (SPEC §8);
  • a mid-run grant-set mutation, whose before/after content addresses MUST differ so a host can detect it (SPEC §1.2).

Growing this set (tier-minimization violations, anti-evasion probing) is the highest-value contribution to this directory (see ../CONTRIBUTING.md).

Running the pack

The reference harness (sandbox-conformance) loads the vectors and checks each class; the sandbox CLI exposes it as sandbox conformance. A run that skips a class for an advertised tier is a fail, not a pass: silent truncation reads as "covered" when it is not.