Zygo: a rootless Linux sandbox in Rust that forks a warm Python interpreter per request
Zygo runs short pieces of code other people wrote (customer plugins, workflow steps, an agent's tools) and gives every call its own process, cgroup, deadline and secrets, thrown away afterwards. For Python, `zygo serve handler.py` starts the interpreter inside a sandbox, lets it do its imports and parks it; each request is a `fork()` of that warm process.
Repo: https://github.com/mhmtskrc2/zygo · Book: https://mhmtskrc2.github.io/zygo/
The parts I think r/rust might find interesting:
\- **The launcher is `clone3` with `CLONE_INTO_CGROUP`**, so a sandbox is born inside its cgroup rather than moved into it. Everything the child needs (the mount plan as C strings, the seccomp program) is built before `clone3`, and the child side is async-signal-safe only: no allocation, no `format!`, `_exit` on every path. See [`prepare.rs`\](https://github.com/mhmtskrc2/zygo/blob/main/crates/zygo-core/src/backend/ns/prepare.rs) and [`child.rs`\](https://github.com/mhmtskrc2/zygo/blob/main/crates/zygo-core/src/backend/ns/child.rs).
\- **Seccomp and Landlock without a crate for either.** The seccomp allowlist is generated as BPF in Rust, and the unit tests run the generated program through a small BPF interpreter for each syscall, so a wrong jump offset fails `cargo test` on any OS. [`seccomp.rs`\](https://github.com/mhmtskrc2/zygo/blob/main/crates/zygo-core/src/backend/ns/seccomp.rs)
\- **`unsafe` is documented or CI fails**: clippy's `undocumented_unsafe_blocks` is on and CI denies warnings, so every unsafe block carries a `SAFETY:` comment.
\- **The supervisor is plain threads and a unix socket, no tokio.** Only the HTTP API in front of it (hyper) is async.
\- **One static musl binary**, edition 2024, MSRV 1.88. `cargo install zygo-cli` works too.
Numbers, on a 2 vCPU Linux VM (aarch64): a warm Python request is 1.4 ms through the API and 2.8 ms from the CLI, where `docker run --rm` takes 542 ms for the same import-heavy script. Node can't be forked safely, so it gets a pre-loaded worker per call instead, at about 25 ms of CPU. `zygo bench all` repeats these on your machine.
What it is not: the wall is the host kernel, so it's for semi-trusted code, not anonymous attackers. The escape suite attempts 21 vectors with 0 escapes, but there has been no external audit. The [threat model\](https://github.com/mhmtskrc2/zygo/blob/main/docs/book/23-security.md) says what is weak.
It's v0.1.4, Apache-2.0, one maintainer. I'd especially like eyes on the fork path and the `unsafe` in it.
I built it with heavy use of Claude Code.
https://redd.it/1x1yd6k
@r_linux
Post #43221
19