apomesh-substrate-sandbox
apomesh-substrate-sandbox is a substrate implementation plane: it owns
confinement for both execution tiers, and owning both in one crate is the
point — it is what lets the two share primitives instead of each growing its own
half-correct copy. Sandbox-by-default is a non-negotiable substrate guarantee,
with no per-tool “trusted” escape hatch. This crate owns how isolation is
applied; the port traits, the policy vocabulary, and the contract itself live in
apomesh-substrate-types.
The tiers are distinguished by the unit of execution, never by the confinement technology — a new technology enters as an adapter within a tier:
| Tier | Unit | Contract | Boot-selected backends |
|---|---|---|---|
| 1 — tool sandbox | a declared tool | SandboxStrategy | Bubblewrap + seccomp (Linux), sandbox-exec (macOS), NoOp (test only) |
| 2 — workload runtime | an OCI image | RuntimeExecutor | EmbeddedOci (youki libcontainer) |
Tier 2 is what runs a programmable agent: a long-lived confined workload with a framed bidirectional channel and a resource envelope, rather than a short-lived request/response command. Keeping the two contracts distinct is deliberate — folding a long-lived channel into a wrap-a-command interface would be the wrong reuse.
Touch it for isolation mechanics: a new platform adapter, a new runtime backend, the runner wire framing, or the boot-time selection posture.
Position in the workspace
Section titled “Position in the workspace”- Layer: substrate implementation plane. See Workers — the sandbox isolation chain.
- Depends on:
apomesh-substrate-types (the
ToolSandboxport plus theSandboxPolicy/SandboxErrorvocabulary it implements), and the platform-gatedlibc/seccompilertrees the dependency-light vocabulary crate deliberately excludes. - Consumed by: apomesh-substrate
(which re-exports the plane as
apomesh_substrate::tool_sandbox),apomesh-substrate-tools(whose shell tools compose the shell-exec spawner), andapomesh-substrate-mcp(which spawns stdio MCP servers as long-lived sandboxed subprocesses).
What it owns
Section titled “What it owns”- The per-OS
ToolSandboxadapters —BubblewrapSandboxon Linux (bubblewrap namespaces plus a per-category seccomp-BPF program compiled in-process byseccompilerand handed tobwrapvia--seccomp) andSandboxExecSandboxon macOS (sandbox-execwith a generated SBPL profile). Each is compile-gated to its platform; the impl module cannot be referenced off-platform. - The runner-subprocess contract — a sandboxed dispatch spawns an
apomesh-tool-runnerchild and exchanges 4-byte length-prefixed JSON frames (ToolInputin on stdin,ToolOutputout on stdout).runner_ioowns the shared framing, the exit-code vocabulary, and the signal mapping both adapters reuse; per-OS signal classification stays in each adapter. - Boot-time selection, fail-closed —
select_sandbox_from_envresolvesAPOMESH_SANDBOX(defaulting per platform) into anArc<dyn ToolSandbox>. An unknown value, an unsupported platform, or a release-build no-op request each surface a typedSandboxSelectionErrorat startup rather than a mid-dispatch panic. - The shell-exec sandbox —
SandboxedCommandwraps arbitrary agent-supplied shell / CLI commands (a plane independent of the runner path) under the same per-OS engines. Secure-by-default: an unsetAPOMESH_SHELL_SANDBOXfails closed in a release build; an explicitnoneis honored and loudly warned only where the surrounding container is itself the isolation boundary. - Subprocess env hygiene — every spawn runs
env_clear()then re-adds only the narrowPASS_THROUGH_ENVallowlist before injecting operator-declared secrets, so ambient host provider keys never reach a sandboxed child; injected-secret cleartext is redacted from captured output at the spawn boundary.
It does not own the tool implementations (those live in
apomesh-substrate-tools), the runner binary (its own apomesh-tool-runner
crate), or the ToolSandbox port and its SandboxPolicy / SandboxError
vocabulary (defined in apomesh-substrate-types and re-exported flat here).
Public surface
Section titled “Public surface”select_sandbox_from_env— resolveAPOMESH_SANDBOX(or the per-platform default) into a workingArc<dyn ToolSandbox>; the worker’s boot entry point.SandboxSelection— the closed enum of supported impls (Bubblewrap/SandboxExec/NoOpTestOnly); a new variant forces an explicit selection arm.SandboxSelectionError— startup-time selection failures (unknown value, no platform default, build-configuration refusal, construction failure), kept distinct from the runtimeSandboxError.BubblewrapSandbox(Linux) — the bubblewrap + seccomp-BPF adapter.SandboxExecSandbox(macOS) — thesandbox-exec+ SBPL adapter.SandboxedCommand+SandboxStrategy— the shell-exec spawner and its per-OS strategy;SHELL_SANDBOX_ENVnames the selecting variable.locate_tool_runner— resolve theapomesh-tool-runnerbinary (env override → PATH → sibling of the current exe).NoOpSandbox/FirecrackerSandbox— test-only stubs behind thetest-utilfeature;NoOpSandbox::newpanics in a release build.
The port types (ToolSandbox, SandboxPolicy, policy_for,
LongLivedSpec, …) are re-exported from apomesh-substrate-types; see
its page for their contracts.
A deployment selects its sandbox by environment variable — the worker calls
select_sandbox_from_env at startup, and the shell tools call
SandboxedCommand::from_env:
# Runner-path sandbox for Tool::dispatch. Unset → per-platform default# (bubblewrap on Linux, sandbox-exec on macOS).export APOMESH_SANDBOX=sandbox-exec
# Shell-exec sandbox for agent-supplied shell / CLI commands. Unset fails# CLOSED in a release build; `none` is honored only where the surrounding# container is itself the isolation boundary (local dev).export APOMESH_SHELL_SANDBOX=noneBoth selectors are fail-closed: an unknown value or an unsupported platform
is a typed startup error, and the noop-test-only sandbox is compiled only
under the test-util feature and refuses to construct in a release build.
No runtime flag bypasses the sandbox.
Related
Section titled “Related”- Concepts: Workers
(the sandbox-by-default isolation chain in the execution plane),
The credential plane (the
env_clear+ allowlist boundary and how a resolved secret is injected at the sandbox edge). - Reference:
apomesh-substrate-types (the
ToolSandboxport this plane implements), apomesh-worker (the layer that selects and drives the sandbox at dispatch).