Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
3e65878093
commit
e74fc29b82
4 changed files with 131 additions and 3 deletions
105
tools/edge-control/verify-chat-sandbox.sh
Executable file
105
tools/edge-control/verify-chat-sandbox.sh
Executable file
|
|
@ -0,0 +1,105 @@
|
|||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# verify-chat-sandbox.sh — One-shot sandbox verification for disinto-chat (#706)
|
||||
#
|
||||
# Runs against a live compose project and asserts hardening constraints.
|
||||
# Exit 0 if all pass, non-zero otherwise.
|
||||
|
||||
CONTAINER="disinto-chat"
|
||||
PASS=0
|
||||
FAIL=0
|
||||
|
||||
pass() { printf ' ✓ %s\n' "$1"; PASS=$((PASS + 1)); }
|
||||
fail() { printf ' ✗ %s\n' "$1"; FAIL=$((FAIL + 1)); }
|
||||
|
||||
echo "=== disinto-chat sandbox verification ==="
|
||||
echo
|
||||
|
||||
# --- docker inspect checks ---
|
||||
|
||||
inspect_json=$(docker inspect "$CONTAINER" 2>/dev/null) || {
|
||||
echo "ERROR: container '$CONTAINER' not found or not running"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# ReadonlyRootfs
|
||||
readonly_rootfs=$(echo "$inspect_json" | python3 -c "import sys,json; print(json.load(sys.stdin)[0]['HostConfig']['ReadonlyRootfs'])")
|
||||
if [ "$readonly_rootfs" = "True" ]; then
|
||||
pass "ReadonlyRootfs=true"
|
||||
else
|
||||
fail "ReadonlyRootfs expected true, got $readonly_rootfs"
|
||||
fi
|
||||
|
||||
# CapAdd — should be null or empty
|
||||
cap_add=$(echo "$inspect_json" | python3 -c "import sys,json; print(json.load(sys.stdin)[0]['HostConfig']['CapAdd'])")
|
||||
if [ "$cap_add" = "None" ] || [ "$cap_add" = "[]" ]; then
|
||||
pass "CapAdd=null (no extra capabilities)"
|
||||
else
|
||||
fail "CapAdd expected null, got $cap_add"
|
||||
fi
|
||||
|
||||
# PidsLimit
|
||||
pids_limit=$(echo "$inspect_json" | python3 -c "import sys,json; print(json.load(sys.stdin)[0]['HostConfig']['PidsLimit'])")
|
||||
if [ "$pids_limit" = "128" ]; then
|
||||
pass "PidsLimit=128"
|
||||
else
|
||||
fail "PidsLimit expected 128, got $pids_limit"
|
||||
fi
|
||||
|
||||
# Memory limit (512MB = 536870912 bytes)
|
||||
mem_limit=$(echo "$inspect_json" | python3 -c "import sys,json; print(json.load(sys.stdin)[0]['HostConfig']['Memory'])")
|
||||
if [ "$mem_limit" = "536870912" ]; then
|
||||
pass "Memory=512m"
|
||||
else
|
||||
fail "Memory expected 536870912, got $mem_limit"
|
||||
fi
|
||||
|
||||
# SecurityOpt — must contain no-new-privileges
|
||||
sec_opt=$(echo "$inspect_json" | python3 -c "import sys,json; opts=json.load(sys.stdin)[0]['HostConfig']['SecurityOpt'] or []; print(' '.join(opts))")
|
||||
if echo "$sec_opt" | grep -q "no-new-privileges"; then
|
||||
pass "SecurityOpt contains no-new-privileges"
|
||||
else
|
||||
fail "SecurityOpt missing no-new-privileges (got: $sec_opt)"
|
||||
fi
|
||||
|
||||
# No docker.sock bind mount
|
||||
binds=$(echo "$inspect_json" | python3 -c "import sys,json; binds=json.load(sys.stdin)[0]['HostConfig']['Binds'] or []; print(' '.join(binds))")
|
||||
if echo "$binds" | grep -q "docker.sock"; then
|
||||
fail "docker.sock is bind-mounted"
|
||||
else
|
||||
pass "No docker.sock mount"
|
||||
fi
|
||||
|
||||
echo
|
||||
|
||||
# --- runtime exec checks ---
|
||||
|
||||
# touch /root/x should fail (read-only rootfs + unprivileged user)
|
||||
if docker exec "$CONTAINER" touch /root/x 2>/dev/null; then
|
||||
fail "touch /root/x succeeded (should fail)"
|
||||
else
|
||||
pass "touch /root/x correctly denied"
|
||||
fi
|
||||
|
||||
# /var/run/docker.sock must not exist
|
||||
if docker exec "$CONTAINER" ls /var/run/docker.sock 2>/dev/null; then
|
||||
fail "/var/run/docker.sock is accessible"
|
||||
else
|
||||
pass "/var/run/docker.sock not accessible"
|
||||
fi
|
||||
|
||||
# /etc/shadow should not be readable
|
||||
if docker exec "$CONTAINER" cat /etc/shadow 2>/dev/null; then
|
||||
fail "cat /etc/shadow succeeded (should fail)"
|
||||
else
|
||||
pass "cat /etc/shadow correctly denied"
|
||||
fi
|
||||
|
||||
echo
|
||||
echo "=== Results: $PASS passed, $FAIL failed ==="
|
||||
|
||||
if [ "$FAIL" -gt 0 ]; then
|
||||
exit 1
|
||||
fi
|
||||
exit 0
|
||||
Loading…
Add table
Add a link
Reference in a new issue