- Nix 100%
|
Some checks failed
CI / check (push) Has been cancelled
basically, the tests sporadically fail to kill the `socat` process, reporting it to not exist. in the log, you could also see the `socat` existing with SIG15. so my guess is -- `socat` can get killed by the environment (nix build pipeline, for instance), and would no longer require a cleanup (won't be reparented to PID1). so the mental shift is -- as long as `socat` is gone, the clean was successful. the failure mode here would be incorrectly capturing `socat`'s PID, or missing the `kill` command (right now, it comes from `coreutils` package, so presumably it would always be available). |
||
|---|---|---|
| .github/workflows | ||
| flake.lock | ||
| flake.nix | ||
| README.md | ||
| tests.nix | ||
Brief
unsafe-cell is designed with following workloads in mind:
- share a cache/binary store with the host
- share a configuration with the host
- allow limited internet access (to a set list of domains)
- jailed program might misbehave -- host must be protected from accidental damage
So this cell aims to prevent malfunction, not malice; for example: current design shares a nix daemon with the host -- a malicious code could easily exploit the build pipeline to dos, mine crypto or circumvent the web proxy. However, this kind of malfunction is extremely unlikely happen accidentally, while benefits of sharing the nix store with host are self-explanatory.
Example use-cases:
- trusted CI job container
- agentic runtime (like
opencode, for instance)
Parameters
command(pkgs -> derivation): a function to build the cell entrypoint fromnixpkgsinstantiationworktreePath(string): host path to bind as/home/cell/worktreeinside the jail. Use this parameter to expose jailed processes primary worktree (like a repo you work on)extraCombinators(jail-nix -> list, default_: []): a function to produce additionaljail.nixcombinators you want the jail to have.tinyproxyFilter(string or null): Path to a tinyproxy filter file.nullmeans "allow all", non-nullshould contain a regex list of the allowed domains. Usestinyproxy(with your filter as a white-list!).logDir(string or null): directory to bind for log output.nullmeans using the jail tempdir (wherevermktempcreates it).nixDaemonSocket(string, default"/var/nix/daemon-socket"): host path to nix daemon socket directory (containssocket).
NOTE: if you want to pass some truly special arguments to bwrap, see unsafe-add-raw-args jail.nix combinator -- an escape hatch for adding bare os args for the bwrap process.
NOTE: for now, the host is expected to have a nix daemon socket. To make the cell work, at the bare minimum, you should make up a socket and point nixDaemonSocket to it -- cell will connect socat to it, but won't actually communicate with the other side, for as long as you don't use nix inside the jail.
Capabilities
- nix daemon access:
- read-only bind of host store (
/nix/store) - bind of the daemon socket (
/run/nix) - nix client config to silence experimental feature warnings (
nix-command,flakes) - nix client substitutions enabled to allow binary cache usage (client controls that, for some reason?)
- read-only bind of host store (
- network:
- http proxied through
tinyproxy, with optional filter - isolated network namespace with no interfaces
- http proxied through
- workdir bind-mounted at a configurable host path
- optional log directory bind
planned:
- spawning a personal dockerd (blocked by some annoying stuff inside
bwrap) - support for MITM docker image cache (could be implemented now, but is useless without a personal dockerd)
NOTE: unfortunately, outward communication with protocols other than HTTP(S) is not supported. Any celled app failing to interpret {HTTP{,S},NO}_PROXY envvars, is also likely to misbehave.
Usage example
See tests.nix.
Will probably add my opencode run script, once it's complete.