open-standards/sandbox/spec/capabilities.md
Transaction Science ba1212361f Add aac, map, sandbox standards; catalog the standards family
Commit the previously-untracked standard directories and catalog them in the
root README alongside proof:

- aac/    — communication cargo class: portable boards + a ten-level
            offline-first cascade (Apache-2.0 code / CC-BY-4.0 spec).
- map/    — geospatial cargo class: range-requestable signed tilesets +
            an F0–F4 fidelity cascade (Apache-2.0 code / CC-BY-4.0 spec).
- sandbox/— isolated, metered, attested execution across the heterogeneous
            compute fabric (Apache-2.0 code / CC-BY-4.0 spec).
- jouleclaw-otel-authz, jouleclaw-trust — new jouleclaw reference crates.

Root README now lists aac, map, sandbox, and proof in the catalog, the tree,
and the contribution guide.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-07 17:04:36 -04:00

8.2 KiB
Raw Permalink Blame History

The capability-grant model

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

A grant set is the complete, explicit description of what a unit may touch. The model is deny-by-default: any access to a resource not named by a grant MUST be denied. The grant set is content-addressed before the run (its grants_id, SPEC §3) and MUST NOT widen during the run (SPEC §1.2).

Grants {
  compute : ComputeGrant,
  storage : StorageGrant,
  network : NetworkGrant,
  kv      : KvGrant,
  host    : HostGrant,
}

The default grant set is empty: no devices beyond Cpu, no storage, no network, no kv, no host services. Every capability is opt-in.

ComputeGrant — the heterogeneity clause

ComputeGrant {
  devices          : Set<DeviceClass>,   // Cpu | Simd | Gpu | Npu | Tpu | Lpu | Photonic | Quantum
  energy_budget_uj : u64,
  cpu_time_ms      : u64,
  memory_bytes     : u64,
}

Rules:

  1. Dispatch is gated by class. A unit MUST NOT dispatch work to a device class absent from devices; the host MUST deny it. Cpu is implicitly present.
  2. The host must isolate AND meter every granted class. A host MUST refuse the grant (decline the run) if devices names a class it cannot both confine at the tier in force and attribute energy to in the receipt (SPEC §6.2). A class the host can run but cannot meter is not grantable — metering is not optional.
  3. Class minimums bind the tier. Any class beyond Cpu/Simd requires ≥ S2; direct device assignment requires ≥ S5; confidential compute requires ≥ S6 (see tiers.md).
  4. Budgets are hard. On exceeding energy_budget_uj, cpu_time_ms, or memory_bytes, the host MUST terminate the unit and record the breached bound as outcome = Terminated{ breach } in the attestation (SPEC §7.1).

The energy budget is denominated in the same unit as the receipt — integer microjoules — so a unit's grant and its account are directly comparable.

StorageGrant

StorageGrant {
  read : [Glob], write : [Glob], delete : [Glob],
  max_iops      : u64?,   // optional sustained-I/O ceiling: ops/sec
  max_read_bps  : u64?,   // optional sustained-I/O ceiling: bytes/sec
}

A path operation MUST match at least one allow-glob for its mode (read/write/delete) or be denied. Globs use * (single segment) and **//* (prefix) matching; the matching algorithm is fixed in the reference sandbox-capability crate and vectored. Write and delete do not imply read. The empty lists deny all storage.

I/O ceilings — the contention lever

A grant MAY carry sustained-I/O ceilings. A request to sustain a rate is permitted iff it stays within every ceiling that is set; an unset ceiling (null) does not bound that dimension. This is a deny-by-default rate control, and it is the standard's lever against storage-contention side channels (see SECURITY.md): a unit whose I/O is capped cannot drive the high-rate, page-cache-busting random-read pattern such a channel needs to read co-tenant activity off shared-device latency. A deployment that colocates a contention-sensitive workload at S0–S2 (shared physical I/O) MUST set a ceiling on untrusted neighbors, or raise the floor to S3, where device I/O is partitioned rather than shared.

The ceilings serialize only when set (skip_serializing_if): a grant that omits them is byte-identical to one written before they existed, so its content id and the published conformance vectors are unchanged. The reference enforces them in sandbox-capability (Enforcer::may_sustain_io, io_ceilings); a ceiling is a property of the grant, so it is bound into grants_content_id and attested.

NetworkGrant

NetworkGrant { outbound : [Endpoint], inbound : bool }

outbound is an allowlist of host:port strings; an egress to any endpoint not on the list MUST be denied. inbound = false denies all inbound connections. The empty grant denies all network. Per SPEC §1.4, the host's own operation never depends on network; a denied egress is a unit-level denial, not a host failure.

KvGrant

KvGrant { read : bool, write : bool, prefixes : [Bytes] }

Key-value access is gated by direction (read/write) and by key prefixes: a key operation MUST match a granted prefix and direction or be denied. Empty prefixes with read/write true grants the whole keyspace; the conservative default is all-false.

HostGrant

HostGrant { logging : bool, clock : bool, random : bool, inference : bool }
  • logging — the unit may emit log lines to the host sink.
  • clock — the unit may read wall-clock time. When false, time calls return a normalized constant (anti-evasion, SPEC §7.5).
  • random — the unit may draw host randomness. When a replay journal is recorded (SPEC §8), draws are journaled.
  • inference — the unit may call an on-host model endpoint. When granted, the energy of each inference MUST be metered to the device class that served it (SPEC §6.2) and MUST NOT be hidden inside an opaque host-call cost.

ProcessGrant — shell and code-interpreter

ProcessGrant { exec : bool, programs : [String], max_processes : u32 }

The substrate for shell access and code-interpreter capabilities. A unit MUST NOT spawn a subprocess unless exec is true and the program is on the programs allowlist — deny-by-default, so an empty allowlist permits nothing even with exec true. max_processes bounds concurrency. Granting exec lifts the required tier to at least S2 (tiers.md): subprocess execution crosses a brokered host boundary. The reference WASM executor brokers this as a sandbox::exec host call that consults the Enforcer before spawning and journals the subprocess output (a nondeterministic input, SPEC §8).

BrowserGrant — browser and GUI agents

BrowserGrant { enabled : bool, origins : [Origin], headless : bool }

The substrate for browser-automation and GUI-agent capabilities. A navigation MUST be denied unless enabled is true and the target origin (scheme://host[:port]) is on the origins allowlist. headless forbids on-screen rendering. Granting enabled lifts the required tier to at least S2.

DisplayGrant — desktop and VNC

DisplayGrant { enabled : bool, vnc : bool, max_width : u32, max_height : u32 }

The substrate for desktop capabilities. Framebuffer access MUST be denied unless enabled is true; a VNC export MUST additionally require vnc; the surface is bounded by max_width × max_height. Granting enabled lifts the required tier to at least S2.

The filesystem capability is storage; a code-interpreter is process + storage; an editor/IDE is display + process + storage. The standard models the underlying resources, never the composed product — so a new agent surface is expressed as a combination of grants, not a new primitive.

Enforcement contract

The reference sandbox-capability crate exposes an Enforcer that, given a Grants set, answers each access query (may_dispatch(class), may_path(mode, path), may_egress(endpoint), may_kv(dir, key), may_host(service), may_exec(program), may_navigate(origin), may_display(), may_vnc()) with allow/deny. The enforcer is pure and deterministic: the same grant set and query always yield the same decision, with no float and no ambient state. Conformance vector class C2 (SPEC §10, conformance.md) fixes the decisions for a canonical grant set, including the deny-by-default negatives.

At tier S2 the enforcement is live, not advisory: the reference WASM executor (sandbox-exec-wasm) brokers every capability the guest exercises through a host-call boundary — kv_get/kv_put, storage_read/storage_write, egress, clock_now, random_u64, log — and each call consults the Enforcer before acting. A denied call returns an error code to the guest (denial is not a crash), so capability enforcement is exercised through real execution. Each nondeterministic input the guest receives (a kv or storage read, the clock, a random draw, an outbound call) is recorded in the run's replay journal (SPEC §8), so the attestation carries a journal_root.