No description
Find a file
Dzuchun 539a4bb6a7
Some checks are pending
CI / check (push) Waiting to run
add: initial version
well, the first version I am willing to record
2026-05-20 01:49:14 +01:00
.github/workflows add: initial version 2026-05-20 01:49:14 +01:00
flake.nix add: initial version 2026-05-20 01:49:14 +01:00
README.md add: initial version 2026-05-20 01:49:14 +01:00
tests.nix add: initial version 2026-05-20 01:49:14 +01:00

unsafe-cell

A jail-nix container that shares user namespace and grants all capabilities (the "unsafe" part), packaging a command into a self-contained executable ("cell"). It provides nix daemon passthrough, configurable networking, and filesystem isolation — enough to run agentic workloads without the friction of full containerization.

Capabilities

Shares user/id mappings 1:1 with the host. All kernel capabilities granted. No PID namespace isolation — host PID 1 visible inside. New mount namespace with only explicitly bound paths.

Nix daemon access via read-only bind of host store (/nix/store) and daemon socket (/run/nix). Nix config and experimental features (nix-command, flakes) set inside the jail. Binary substitution enabled.

Network access is always proxied through tinyproxy with an isolated network namespace (no network routes inside the jail). A socat pair forwards TCP through a Unix socket onto tinyproxy. An optional tinyproxy filter file controls allowed domains; defaults to allow-all (.*).

Working directory bind-mounted at a configurable host path. Optional log directory bind.

Entrypoint runs the command derivation supplied via the command parameter. PATH includes nix, coreutils.

Parameters

command (pkgs -> derivation): Builds the jailed entrypoint. Receives nixpkgs.

worktreePath (string): Host path to bind as /home/cell/worktree inside the jail. Required, no default.

extraCombinators (jail-nix -> list, default _: []): jail-nix combinators appended to the default set.

tinyproxyFilter (string or null): Path to a tinyproxy filter file. null = default allow-all filter (.*); non-null = use the specified filter file.

logDir (string or null): Directory to bind for log output. null = use jail tempdir ($JD).

nixDaemonSocket (string, default "/var/nix/daemon-socket"): Host path to nix daemon socket directory (contains socket).

Implicit assumptions

mkCell builds its output for every system in systems.flakeExposed. Requires nixpkgs and jail-nix as flake inputs.

The nix daemon socket path is assumed to be a directory containing a socket entry — the NIX_REMOTE env var always resolves /run/nix/socket regardless of nixDaemonSocket.

/nix/store is assumed present and readable on the host. NIX_PATH hardcoded to /home/cell/.nix-defexpr/channels.

NIX_CONFIG unconditionally overrides host nix config — forces nix-command, flakes, and substitute = true.

Host-side packages required at nixpkgs evaluation time: socat, coreutils, nix, iproute2, gawk, tinyproxy.

worktreePath is resolved relative to the host-script's CWD at runtime (shell expansion applies).

The default combinator set does not include SSL certificates, app config/state directories, nix registry mapping, nix config files, or secret tokens — these must be supplied by the consumer via extraCombinators.

The host script always creates $JD (temp dir) with tinyproxy config, SSL overlay dirs, and Unix socket — all cleaned up on exit. The SSL overlay dirs are created but unused (dead code from original hardcoded version).

No IPC namespace isolation — inherits from host.