21 Adamant Devlog 2
The experiments to get sandboxing working with PonderCode suggested a direction, and I borrowed it almost wholesale for Adamant.
The prepare command produces or updates a profile in ~/.config/adamant/profiles/. A profile can be extended by another profile. And run executes the command.
BASE ="sh ls cat head tail wc grep sed awk rg pwd whoami id uname find stat readlink ps kill mkdir rmdir rm cp mv env printenv which file du df mount findmnt man tee touch echo"
adamant --profile base prepare $BASE
adamant --profile net prepare --extend base -- curl
adamant --profile base run -- sh
adamant --profile base run -- ls -la /home
As Adamant presently uses readelf instead of ldd, it loses out on the discovery of all the dlopen stuff. And as it does not use strace, it cannot detect all the data dependencies of a program. So I must manually do stuff like this:
# ~/.config/adamant/profiles/base.toml
# AUTOMATIC: resolved_ro is written by `adamant prepare`; do not hand-edit.
# Hand-edited keys (extends, extra_ro, extra_rw, hosts, env) are preserved.
resolved_ro = [
"/usr/lib/ld-linux-x86-64.so.2" ,
"/usr/lib/libc.so.6" ,
...
"/usr/bin/clear" ,
]
extra_ro = [
"/usr/share/terminfo" , # ncurses/fish terminal db
"/etc/passwd" , # username/home lookup
"/etc/group" ,
"/etc/hostname" ,
"/etc/localtime" ,
"/usr/lib/kitty/terminfo" ,
]
env = [
{name = "TERM" , value = "xterm-kitty" },
{name = "COLORTERM" , value = "truecolor" },
{ name = "LANG" , value = "C.UTF-8" },
]
and this:
# ~/.config/adamant/profiles/net.toml
# AUTOMATIC: resolved_ro is written by `adamant prepare`; do not hand-edit.
# Hand-edited keys (extends, extra_ro, extra_rw, hosts, env) are preserved.
extends = "base"
resolved_ro = [
"/usr/lib/libcom_err.so.2" ,
...
"/usr/bin/curl" ,
]
extra_ro = [
"/etc/ssl" ,
"/etc/ca-certificates" ,
"/etc/nsswitch.conf" ,
"/usr/lib/libnss_files.so.2" , # dlopen'd, prepare can't see it
"/etc/hosts" ,
"/etc/resolv.conf" ,
]
and this:
# ~/.config/adamant/profiles/coding.toml
# AUTOMATIC: resolved_ro is written by `adamant prepare`; do not hand-edit.
# Hand-edited keys (extends, extra_ro, extra_rw, hosts, env) are preserved.
extends = "net"
resolved_ro = [
"/usr/bin/node" ,
...
"/usr/lib/libjemalloc.so.2" ,
"/usr/bin/jj" ,
]
hosts = ["npmjs.com" , "pypi.org" , "opencode.ai" , "github.com" , "*.astral.sh" , "pi.dev" , "127.0.0.1:5001" , "files.pythonhosted.org" ]
home = "~/my/homes/coding"
user = "<user>"
extra_ro = [
"/usr/lib/python3.14" ,
]
extra_rw = [
"~/.config/uv" ,
"~/.pi" ,
]
This is fine for most CLI tools, but is a massive PITA if you want to get headless Firefox working inside the sandbox.
The socat socket + proxy machinery was borrowed from PonderCode as-is. It has its pros and cons. The biggest con is that applications that do not respect HTTP_PROXY + HTTPS_PROXY envars do not work.
So, Adamant is mostly done. But I plan to explore veth as well as machinery to get something like Firefox working inside the sandbox.
I could perhaps get Adamant to use ldd + strace behind an --unsafe flag so that this becomes simpler. After all, my goal is to run known binaries and LLM harnesses inside the sandbox, not malware research. So executing the actual binary to figure out what it needs is not a dealbreaker.