18 PonderCode Devlog 5
The experiment worked! And it has implications for Adamant.
Part A: Dependency Resolution
As part of the brainstorming, I created a simple Python script where I hardcoded a set of binaries as part of a list and then used ldd to resolve their dependency graph. This graph was then used to build a shell script that executed Bubblewrap. This is the heart of the script:
def generate_sand_script(apps):
"""Constructs the bwrap shell script string."""
bind_mounts = []
libraries = set()
# 1. Process the requested apps
for app in apps:
app_path = get_app_path(app)
if app_path:
bind_mounts.append(f" --ro-bind {app_path} {app_path}" )
# Get dependencies for this app
deps = get_dependencies(app_path)
for dep in deps:
libraries.add(dep)
else :
print(f"Warning: Command '{app}' not found in PATH." )
# 2. Sort libraries for a clean, deterministic output
sorted_libs = sorted(list(libraries))
# 3. Build the script template
script = [
"#!/bin/sh" ,
"set -euo pipefail" ,
'REAL_HOME="$HOME"' ,
'REAL_PROJECT_DIR="$(pwd)"' ,
'FAKE_HOME="/home/user"' ,
'FAKE_PATH="/usr/bin"' ,
"" ,
"" ,
]
exec = [
"exec bwrap --clearenv --unshare-all --die-with-parent" ,
" --tmpfs /" ,
" --tmpfs /tmp" ,
]
# Add app bind mounts
for bm in bind_mounts:
exec.append(bm)
# Add library bind mounts
for lib in sorted_libs:
exec.append(f" --ro-bind {lib} {lib}" )
# Add symlinks and environment setup
exec.extend(
[
" --proc /proc" ,
" --dev /dev" ,
" --symlink /usr/lib /lib" ,
" --symlink /usr/lib64 /lib64" ,
" --symlink /usr/bin /bin" ,
' --dir "$FAKE_HOME"' ,
' --setenv HOME "$FAKE_HOME"' ,
' --setenv PATH "$FAKE_PATH"' ,
' --chdir "$FAKE_HOME"' ,
' "$@"' ,
]
)
return "\n" .join(script) + " \\\n" .join(exec)
I took this and incorporated it into the app. Now, the user does not have to manually map paths into the sandbox. They can provide a list of binaries and the system will resolve them at runtime and prepare the sandbox accordingly.
Part B: Sockets + Proxy
The app initializes the sandbox with socat running a proxy on 127.0.0.1:8080 inside the sandbox. It also maps a socket path into the sandbox. socat intercepts the requests from curl and other applications and the app uses the whitelist in the <profile>.hosts key to decide if the connection can be permitted or not. An important limitation: client applications must support HTTP_PROXY + HTTPS_PROXY envars.
This exact mechanism, A + B, can be used for Adamant!
PonderCode is mostly done. I will continue this series in the future when I take a couple of days to iron out various bugs and streamline the codebase.