wai-quantum-service: sandboxed workers, IPv6 clients counted by /64, a per-client memory cap #464

Merged
dcharlot merged 1 commit from wai/quantum-service-client-identity into main 2026-10-25 06:35:04 -04:00
Owner

The fleet audit of the public job service found three ways past its limits. This closes them.

  • Workers run sandboxed (macOS). Each job's worker runs under sandbox-exec: no network, no file writes, no program but itself (jobs::worker_profile). It reads its job on stdin and writes its result on stdout, so it needs none of them. A flaw in parsing a submitted circuit then reaches neither the host's files nor the network nor a shell. The exec chain stays one process (taskpolicy → nice → sandbox-exec → worker), so memory polling, the energy read and the kill all work by PID as before. WAI_QSVC_SANDBOX=0 turns it off for debugging.
  • An IPv6 client is its /64 (http::identity). Limits were counted per address, and a subscriber usually holds a whole /64, so rotating through it reset every per-client limit. An IPv4 address carried in IPv6 counts as itself.
  • One client holds at most one job's worth of memory (WAI_QSVC_CLIENT_GB, by default the per-job size). Three jobs from one client could hold the whole 96 GiB budget. Any client can still run its largest job.

GET /v1 and the MCP server publish the new limit. GET /v1 also publishes how a client is counted and whether workers are sandboxed. The README and changelog document all three.

Checked on the build host:

  • cargo test: 23 tests pass. New ones:
    • a_client_holds_at_most_one_jobs_worth_of_memory_at_once;
    • the_worker_sandbox_denies_files_network_and_processes (macOS): a file write, an outbound connection and a nested exec are each refused, while writing to the given pipe works;
    • an_ipv6_client_is_its_64_and_ipv4_is_itself.
  • cargo clippy --all-targets -- -D warnings is clean.
  • A release build served on a spare port with a throwaway key. smoke.sh: every check held.
  • On that instance, the worker was seen running as sandbox-exec -p (version 1)(allow default)(deny network*)(deny file-write*)…. A 22-qubit job completed with its energy read (3.3 J, on-chip counter).

🤖 Generated with Claude Code

The fleet audit of the public job service found three ways past its limits. This closes them. - **Workers run sandboxed (macOS).** Each job's worker runs under `sandbox-exec`: no network, no file writes, no program but itself (`jobs::worker_profile`). It reads its job on stdin and writes its result on stdout, so it needs none of them. A flaw in parsing a submitted circuit then reaches neither the host's files nor the network nor a shell. The exec chain stays one process (`taskpolicy` → `nice` → `sandbox-exec` → worker), so memory polling, the energy read and the kill all work by PID as before. `WAI_QSVC_SANDBOX=0` turns it off for debugging. - **An IPv6 client is its /64** (`http::identity`). Limits were counted per address, and a subscriber usually holds a whole /64, so rotating through it reset every per-client limit. An IPv4 address carried in IPv6 counts as itself. - **One client holds at most one job's worth of memory** (`WAI_QSVC_CLIENT_GB`, by default the per-job size). Three jobs from one client could hold the whole 96 GiB budget. Any client can still run its largest job. `GET /v1` and the MCP server publish the new limit. `GET /v1` also publishes how a client is counted and whether workers are sandboxed. The README and changelog document all three. Checked on the build host: - `cargo test`: 23 tests pass. New ones: - `a_client_holds_at_most_one_jobs_worth_of_memory_at_once`; - `the_worker_sandbox_denies_files_network_and_processes` (macOS): a file write, an outbound connection and a nested exec are each refused, while writing to the given pipe works; - `an_ipv6_client_is_its_64_and_ipv4_is_itself`. - `cargo clippy --all-targets -- -D warnings` is clean. - A release build served on a spare port with a throwaway key. `smoke.sh`: every check held. - On that instance, the worker was seen running as `sandbox-exec -p (version 1)(allow default)(deny network*)(deny file-write*)…`. A 22-qubit job completed with its energy read (3.3 J, on-chip counter). 🤖 Generated with [Claude Code](https://claude.com/claude-code)
wai-quantum-service: sandboxed workers, IPv6 clients counted by /64, a per-client memory cap
All checks were successful
standards workspaces build + test / which workspaces this change touches (pull_request) Successful in 8s
WAI energy receipts / does this change touch it (pull_request) Successful in 7s
wai-quantum service / does this change touch it (pull_request) Successful in 6s
repository checks / lockfiles, advisories, tests in CI, workflow hygiene, spec and section references, public text (pull_request) Successful in 2m38s
wai-quantum service / service · linux (pull_request) Successful in 50s
WAI energy receipts / energy receipts · linux (pull_request) Successful in 9m45s
standards workspaces build + test / joule-code-rs (joule-code/joule-code-rs, joule-code-rs, linux-arm64, true) (pull_request) Successful in 3m52s
WAI energy receipts / energy receipts · linux-arm64 (pull_request) Successful in 7m25s
standards workspaces build + test / macOS energy backends (pull_request) Successful in 9m4s
WAI energy receipts / energy receipts · macos (pull_request) Successful in 4m37s
wai-quantum service / service · macos (pull_request) Successful in 42s
ce76e029b1
The audit of the public job service found three ways past its limits:

- Each IPv6 address counted as its own client. A subscriber is usually
  given a /64 whole, so rotating through it handed out fresh per-client
  limits with every request. A client is now an IPv4 address or an IPv6
  /64; an IPv4 address carried in IPv6 counts as itself.
- Three active jobs from one client could hold the whole 96 GiB budget.
  One client's queued and running jobs may now hold at most one job's
  worth together (WAI_QSVC_CLIENT_GB, default the job size), so any client
  can still run its largest job, and no client holds the rest.
- A worker ran as the service's user with everything that user can reach,
  so a flaw in parsing a submitted circuit would have been code running as
  the account that owns the build host. On macOS each worker now runs under
  sandbox-exec: no network, no file writes, no program but itself. It needs
  none of them, since it reads its job on stdin and writes its result on
  stdout. WAI_QSVC_SANDBOX=0 turns it off for debugging.

GET /v1 and the MCP server publish the new limit, and the README documents
all three.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
Transaction-Science/open-standards!464
No description provided.