All checks were successful
no-vanity-metrics / Scan committed Markdown for vanity metrics (pull_request) Successful in 3s
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.
55 lines
6.3 KiB
Markdown
55 lines
6.3 KiB
Markdown
# Conformance
|
||
|
||
Normative companion to [`SPEC.md`](../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/`](../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`](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`](../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`](../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.
|