Skip to repository content118 lines · 5.0 KB · shellscript
tenant.openagents/omega
No repository description is available.
OpenAgents Git authority 2026-07-28T04:06:02.916Z Public web read
NIP-34 coordinate
30617:7649603503856e5148d571eac2766b288a8ff1e9e35d380337a1d2b0015b4f92:omegaMaintainersHidden in public view
References2 branches · 1 tag
Read-only clone
git clone https://openagents.com/git/tenant.openagents/omega.gitBrowse files
bwrap_smoke_test.sh
1#!/usr/bin/env bash
2# Ad-hoc smoke test for the static `bwrap` binary. Exercises filesystem
3# read/write isolation and network isolation by trying to "break out" of the
4# sandbox in ways that must fail, alongside controls that must succeed.
5#
6# Usage: bwrap_smoke_test.sh /path/to/bwrap
7set -u
8
9BWRAP=${1:?usage: bwrap_smoke_test.sh /path/to/bwrap}
10
11# Resolve real binaries (works on NixOS, where /bin is mostly empty).
12CAT=$(command -v cat)
13TOUCH=$(command -v touch)
14SH=$(command -v sh)
15PY=$(command -v python3)
16
17# Bind enough of the host (read-only) for dynamically-linked helpers to run.
18# On NixOS that means the closure under /nix/store; /usr/bin elsewhere.
19BASE=(--ro-bind /nix /nix --ro-bind /run /run --proc /proc --dev /dev --unshare-user)
20[ -d /usr ] && BASE+=(--ro-bind /usr /usr)
21[ -e /bin ] && BASE+=(--ro-bind /bin /bin)
22[ -e /lib ] && BASE+=(--ro-bind /lib /lib)
23[ -e /lib64 ] && BASE+=(--ro-bind /lib64 /lib64)
24[ -e /etc ] && BASE+=(--ro-bind /etc /etc)
25
26PASS=0
27FAIL=0
28ok() { echo "PASS: $1"; PASS=$((PASS + 1)); }
29bad() { echo "FAIL: $1"; FAIL=$((FAIL + 1)); }
30
31# expect_ok <desc> <cmd...> -> command must exit 0
32expect_ok() {
33 desc=$1; shift
34 if "$@"; then ok "$desc"; else bad "$desc (expected success, got exit $?)"; fi
35}
36# expect_fail <desc> <cmd...> -> command must exit non-zero
37expect_fail() {
38 desc=$1; shift
39 if "$@"; then bad "$desc (expected failure, but it succeeded)"; else ok "$desc"; fi
40}
41
42# ---------------------------------------------------------------------------
43# Set up a host scratch tree:
44# $ROOT/secret/secret.txt -> must NOT be visible unless explicitly bound
45# $ROOT/allowed/note.txt -> bound read-only into the sandbox
46# $ROOT/writable/ -> bound read-write into the sandbox
47# ---------------------------------------------------------------------------
48ROOT=$(mktemp -d /tmp/bwrap-smoke.XXXXXX)
49trap 'rm -rf "$ROOT"' EXIT
50mkdir -p "$ROOT/secret" "$ROOT/allowed" "$ROOT/writable"
51echo "TOP SECRET" > "$ROOT/secret/secret.txt"
52echo "you may read me" > "$ROOT/allowed/note.txt"
53
54echo "=================================================================="
55echo "bwrap: $BWRAP"
56"$BWRAP" --version
57echo "=================================================================="
58echo "## Filesystem isolation"
59
60# The host secret must be invisible: sandbox sees a fresh tmpfs at $ROOT,
61# so the secret path simply doesn't exist.
62expect_fail "host secret file is NOT readable from sandbox" \
63 "$BWRAP" "${BASE[@]}" --tmpfs "$ROOT" "$CAT" "$ROOT/secret/secret.txt"
64
65# Likewise nothing under /tmp leaks in by default (no bind for it).
66expect_fail "host /tmp is NOT visible from sandbox" \
67 "$BWRAP" "${BASE[@]}" --tmpfs /tmp "$CAT" "$ROOT/allowed/note.txt"
68
69# An explicitly read-only bind IS readable...
70expect_ok "explicitly ro-bound file IS readable" \
71 "$BWRAP" "${BASE[@]}" --ro-bind "$ROOT/allowed" /data "$CAT" /data/note.txt
72
73# ...but writing to a read-only bind must fail.
74expect_fail "writing to a ro-bound dir is denied" \
75 "$BWRAP" "${BASE[@]}" --ro-bind "$ROOT/allowed" /data "$TOUCH" /data/evil
76
77# Confirm the host file was not modified/created behind the sandbox's back.
78expect_fail "ro-bind write did not leak to host" test -e "$ROOT/allowed/evil"
79
80# A read-write bind allows writes...
81expect_ok "writing to a rw-bound dir succeeds" \
82 "$BWRAP" "${BASE[@]}" --bind "$ROOT/writable" /data "$TOUCH" /data/hello
83
84# ...and the write really lands on the host file (proves the bind, not a tmpfs).
85expect_ok "rw-bind write is visible on host" test -e "$ROOT/writable/hello"
86
87# Writing to a tmpfs overlay succeeds inside, but must NOT touch the host dir.
88expect_ok "writing into a tmpfs works inside sandbox" \
89 "$BWRAP" "${BASE[@]}" --tmpfs "$ROOT/writable" "$TOUCH" "$ROOT/writable/ephemeral"
90expect_fail "tmpfs write did not leak to host" test -e "$ROOT/writable/ephemeral"
91
92echo "------------------------------------------------------------------"
93echo "## Network isolation"
94
95NETCHECK='import socket; s=socket.socket(socket.AF_INET,socket.SOCK_STREAM); s.settimeout(5); s.connect(("1.1.1.1",53)); print("connected")'
96
97# With --unshare-net the sandbox has only loopback: outbound TCP must fail.
98expect_fail "outbound TCP is blocked with --unshare-net" \
99 "$BWRAP" "${BASE[@]}" --unshare-net "$PY" -c "$NETCHECK"
100
101# Loopback still exists inside the isolated netns.
102expect_ok "loopback is up inside --unshare-net" \
103 "$BWRAP" "${BASE[@]}" --unshare-net "$PY" -c \
104 'import socket; socket.socket().bind(("127.0.0.1",0)); print("lo ok")'
105
106# Without --unshare-net the host network is shared, so the same connect works
107# (skipped automatically if the host itself has no outbound connectivity).
108if timeout 6 "$PY" -c "$NETCHECK" >/dev/null 2>&1; then
109 expect_ok "outbound TCP works when network is shared" \
110 "$BWRAP" "${BASE[@]}" "$PY" -c "$NETCHECK"
111else
112 echo "SKIP: host has no outbound TCP; cannot test shared-network case"
113fi
114
115echo "=================================================================="
116echo "Summary: $PASS passed, $FAIL failed"
117[ "$FAIL" -eq 0 ]
118