Commit Graph
2 Commits
Author SHA1 Message Date
ducoterra 8b70967907 Stop a trailing comment in an allow file killing every run
cfg_read_allowlist() ended on `[[ -n "$line" ]] && CFG_allow+=(...)`, so a file whose
last line is a comment or blank returned 1 from the loop. load_config() calls it twice
in a non-final position, so under `set -e` every run died with exit 1 and no output at
all -- --dry-run and --print-policy included, with nothing to explain it.

Reading a file now always succeeds. An allowlist with nothing in it stays
validate_opts()'s call to refuse, with the message that says why.

LLM-Generated: true
2026-10-30 22:50:04 -04:00
ducoterra 03ab9c0cb1 add ai-sandbox: rootless podman sandbox for agentic development
A single bash script that runs a coding harness (pi by default) inside a
rootless Ubuntu 24.04 container with only the current directory mounted at
/project, an explicit egress allowlist and an explicit environment: nothing
is passed in that was not named on the command line or in a config file.

Network enforcement here is empirical rather than assumed
(tests/spike_network.sh, docs/networking.md). The original design -- a sidecar
proxy on an internal network -- does not work rootless on this host, so allow
mode runs pasta with --map-host-loopback, installs an inet aisb ruleset inside
the container that drops every egress path except the gate's, and relays
through a squid gate bound to the host's loopback that resolves names itself
and refuses anything unlisted. The entrypoint checks that the default-drop rule
really exists before setpriv drops to uid 1000 with an empty capability set,
and exits 77/78 rather than run unenforced.

The Containerfile, the entrypoint, the squid config generator and the ruleset
renderer all live in bin/ai-sandbox, and the image is tagged by content hash,
so a policy change can never silently reuse a stale image. Tests are pure
bash: 161 assertions start no container and touch no network, 256 run real
ones, including proof that a raw socket, a stripped proxy env and DNS all stay
blocked while an allowlisted host works over both http and CONNECT.

LLM-Generated: true
2026-10-27 15:11:29 -04:00