Skip to content

feat(sandbox): add the in-sandbox agent and the image bundle it ships in - #390

Open
ItamarZand88 wants to merge 1 commit into
itamar/alien-75-sandbox-1-corefrom
itamar/alien-75-sandbox-2-agent
Open

feat(sandbox): add the in-sandbox agent and the image bundle it ships in#390
ItamarZand88 wants to merge 1 commit into
itamar/alien-75-sandbox-1-corefrom
itamar/alien-75-sandbox-2-agent

Conversation

@ItamarZand88

@ItamarZand88 ItamarZand88 commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds the agent that runs inside a sandbox and executes a caller's code, plus the image bundle it ships in. Layer 1 added the Sandbox resource type; this adds the process that actually runs something inside one.

When a caller asks a sandbox to run a command:

  1. The agent authorises the request — a signed capability, or the transport itself where the cloud already scopes the caller to one sandbox.
  2. It resolves any path the request names through the kernel, so a path that would leave the session root is refused rather than checked and then opened. This is the heart of the change.
  3. It spawns the command with a fresh environment, as an unprivileged user, in its own process group, and streams stdout and stderr back as they are produced.
  4. The deadline kills that whole group, so what the command forked goes with it.

This turns the sandbox from a resource you can declare into one you can run code in.

What I did

The agent is a small HTTP server that ships inside the image. It runs as root so it can drop to an unprivileged user before every spawn; inside a MicroVM that drop sits behind hardware virtualisation, which is the tenant boundary.

Two decisions are worth pointing at:

  • Paths go through openat2, not a resolver. Resolving a path and then opening it by name leaves every check in a race window, and the code being confined runs in the same guest and can drive both sides of it. RESOLVE_BENEATH | RESOLVE_NO_SYMLINKS makes resolution and open one operation. This removed the hand-written component walk, the canonicalisation, and the containment check rather than adding a fourth guard next to them.
  • spawn and spawn_sandboxed are two functions, not a flag. One inherits the environment for our own helper processes; the other clears it. The agent's environment names its own port and session, so handing it to a caller's code hands over a map to the API running it.

Files touched

  • crates/alien-sandbox-agent/ — the agent: HTTP surface, exec, file transfer, path confinement, privilege drop, PID-namespace support for runtimes that grant it.
  • crates/alien-core/src/sandbox_process.rs — process framing, shared with the GCP launcher path.
  • crates/alien-build/src/sandbox_bundle.rs — the image bundle and its Dockerfile.
  • crates/alien-bindings/src/error.rs — the error variants the agent's callers see.

How I tested

  • 27 unit + 14 protocol tests, run on Linux in a container as well as on macOS. The Linux run is the one that counts: it exercises the real openat2 path, and it caught a traversal on write returning 500 instead of 400 that macOS could not have surfaced.
  • A standalone probe against a real kernel: a legitimate file opens; a symlink to an outside file, a symlinked parent directory, a dangling symlink on write, .. traversal and an absolute path are all refused. The control arm reads the same symlink successfully without confinement, so the refusals are the code working rather than a broken fixture.
  • Each security-relevant test was mutation-tested — the fix reverted, the test observed to fail, the fix restored. That covers the dangling-symlink escape, environment inheritance, the process-group kill, the refusal of the agent's own supervised code, and Dockerfile directive injection.
  • A standalone probe confirming a connecting socket can be attributed to its owning user before that was relied on: a connection from the sandbox user is identified as such, and one from another user is not mistaken for it.
  • protected_hardlinks checked on the actual MicroVM base image, as the sandbox uid, with a control arm.
  • cargo check for alien-build and alien-bindings under their individual feature combinations, not just the workspace build.

Security review of this diff, since it runs untrusted code:

  • A caller planting a symlink — refused by the kernel at open, verified against a real kernel.
  • A caller racing a rename between check and open — no window; resolution and open are one call.
  • A caller reaching the agent's own API from inside the guest — refused. The agent does not serve a request whose connecting socket belongs to the identity it runs commands as, so the command it started cannot ask it for more work. Verified against a real kernel, with a control arm showing a caller on loopback under a different user is unaffected — a proxy terminating inside the guest still works.
  • An image reference carrying a newline — refused before it renders, since a reference reaching a generated Dockerfile would otherwise write its own directives. The check sits inside the renderer, so neither entry point can skip it.
  • A command outliving its deadline — the process group is killed; a setsid child still escapes, which needs a cgroup and is called out in the module docs.
  • A setuid binary in a caller-supplied base image — no_new_privs is set after the drop.
  • Supplementary groups surviving the drop — shed before the uid changes.
  • Hard links — deliberately not addressed here and documented; a link is the inode, so no resolver can tell it apart, and protected_hardlinks bounds it to files the caller could already write.

Nothing turned up.

@greptile-apps

greptile-apps Bot commented Aug 10, 2026

Copy link
Copy Markdown

Greptile Summary

The PR adds the in-sandbox execution agent, shared process-output framing, and the image bundle used to ship the agent.

  • Adds capability- and transport-based request authorization with local socket-owner attribution.
  • Confines file access through kernel-backed path resolution and runs commands under a reduced identity with isolated environment and process-group deadlines.
  • Adds sandbox image rendering and archive assembly with centralized base-image validation.
  • Exposes shared sandbox process framing and caller-facing error variants.

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains.

Important Files Changed

Filename Overview
crates/alien-sandbox-agent/src/server.rs Defines the agent HTTP protocol and consistently authorizes protected exec and file operations before performing work.
crates/alien-sandbox-agent/src/peer.rs Attributes local transport connections to socket owners and fails closed when a local connection cannot be attributed.
crates/alien-sandbox-agent/src/confine.rs Implements Linux kernel-backed path confinement for sandbox file operations.
crates/alien-core/src/sandbox_process.rs Centralizes bounded process-output streaming, terminal framing, deadline enforcement, and process-group cleanup.
crates/alien-build/src/sandbox_bundle.rs Renders and archives the sandbox image bundle while validating base-image references at the rendering boundary.

Sequence Diagram

sequenceDiagram
  participant Caller
  participant Agent
  participant Auth as Authorization
  participant Kernel as Kernel confinement
  participant Child as Sandboxed process
  Caller->>Agent: exec or file request
  Agent->>Auth: Verify capability or transport peer
  Auth-->>Agent: Authorized
  Agent->>Kernel: Resolve path beneath session root
  Kernel-->>Agent: Confined descriptor/path
  Agent->>Child: Spawn as unprivileged identity
  Child-->>Agent: Sequenced stdout/stderr frames
  Agent-->>Caller: NDJSON stream and terminal frame
Loading

Reviews (21): Last reviewed commit: "feat(sandbox): add the in-sandbox agent ..." | Re-trigger Greptile

Comment thread crates/alien-build/src/sandbox_bundle.rs
Comment thread crates/alien-build/src/sandbox_bundle.rs Outdated
@ItamarZand88
ItamarZand88 force-pushed the itamar/alien-75-sandbox-2-agent branch from 8f2beff to 7f2f487 Compare August 11, 2026 06:55
Comment thread crates/alien-sandbox-agent/src/server.rs Outdated
@ItamarZand88
ItamarZand88 force-pushed the itamar/alien-75-sandbox-2-agent branch from 7f2f487 to 6510139 Compare August 11, 2026 07:37
@ItamarZand88
ItamarZand88 force-pushed the itamar/alien-75-sandbox-2-agent branch from 6510139 to 39a3fd4 Compare August 11, 2026 07:50
@ItamarZand88
ItamarZand88 force-pushed the itamar/alien-75-sandbox-2-agent branch from 39a3fd4 to 7d0e0a4 Compare August 11, 2026 08:59
@ItamarZand88
ItamarZand88 force-pushed the itamar/alien-75-sandbox-2-agent branch from 7d0e0a4 to 33e13f4 Compare August 11, 2026 09:10
@ItamarZand88
ItamarZand88 force-pushed the itamar/alien-75-sandbox-2-agent branch from 33e13f4 to 6c36ed2 Compare August 11, 2026 12:11
@ItamarZand88
ItamarZand88 force-pushed the itamar/alien-75-sandbox-2-agent branch from 6c36ed2 to f8a4255 Compare August 11, 2026 13:19
Comment thread crates/alien-sandbox-agent/src/peer.rs Fixed
Comment thread crates/alien-sandbox-agent/src/peer.rs Outdated
@ItamarZand88
ItamarZand88 force-pushed the itamar/alien-75-sandbox-2-agent branch 2 times, most recently from 853d4f1 to 182f60b Compare August 11, 2026 16:53
@ItamarZand88
ItamarZand88 force-pushed the itamar/alien-75-sandbox-2-agent branch 2 times, most recently from 25bba81 to af8945f Compare August 11, 2026 17:28
@ItamarZand88
ItamarZand88 force-pushed the itamar/alien-75-sandbox-2-agent branch from af8945f to 9d6a588 Compare August 11, 2026 18:40
@ItamarZand88
ItamarZand88 force-pushed the itamar/alien-75-sandbox-2-agent branch from 9d6a588 to eab73e0 Compare August 11, 2026 18:49
@ItamarZand88
ItamarZand88 force-pushed the itamar/alien-75-sandbox-2-agent branch from eab73e0 to a15e370 Compare August 11, 2026 19:16
@ItamarZand88
ItamarZand88 force-pushed the itamar/alien-75-sandbox-2-agent branch 2 times, most recently from c2771f2 to 945be88 Compare August 11, 2026 19:49
@ItamarZand88
ItamarZand88 force-pushed the itamar/alien-75-sandbox-2-agent branch from 945be88 to 0b154ba Compare August 11, 2026 20:08
@ItamarZand88
ItamarZand88 force-pushed the itamar/alien-75-sandbox-2-agent branch 2 times, most recently from b59c8b0 to a3397cd Compare August 11, 2026 21:26
@ItamarZand88
ItamarZand88 force-pushed the itamar/alien-75-sandbox-2-agent branch from a3397cd to e89f04e Compare August 11, 2026 22:16
@ItamarZand88
ItamarZand88 force-pushed the itamar/alien-75-sandbox-2-agent branch from e89f04e to 76a1e5f Compare August 11, 2026 22:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants