fix: tools/edge-control/verify-chat-sandbox.sh targets deleted disinto-chat container (#1087)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
d1867bd877
commit
750981529b
2 changed files with 1 additions and 114 deletions
|
|
@ -43,7 +43,7 @@ disinto/ (code repo)
|
||||||
├── projects/ *.toml.example — templates; *.toml — local per-box config (gitignored)
|
├── projects/ *.toml.example — templates; *.toml — local per-box config (gitignored)
|
||||||
├── formulas/ Issue templates (TOML specs for multi-step agent tasks)
|
├── formulas/ Issue templates (TOML specs for multi-step agent tasks)
|
||||||
├── docker/ Dockerfiles and entrypoints: reproduce, triage, edge (Caddy + chat server subprocess + dispatcher), chat (server.py, ui/ — copied into edge image at build time)
|
├── docker/ Dockerfiles and entrypoints: reproduce, triage, edge (Caddy + chat server subprocess + dispatcher), chat (server.py, ui/ — copied into edge image at build time)
|
||||||
├── tools/ Operational tools: edge-control/ (register.sh, install.sh, verify-chat-sandbox.sh)
|
├── tools/ Operational tools: edge-control/ (register.sh, install.sh)
|
||||||
│ vault-apply-policies.sh, vault-apply-roles.sh, vault-import.sh — Vault provisioning (S2.1/S2.2)
|
│ vault-apply-policies.sh, vault-apply-roles.sh, vault-import.sh — Vault provisioning (S2.1/S2.2)
|
||||||
│ vault-seed-<svc>.sh — per-service Vault secret seeders; auto-invoked by `bin/disinto --with <svc>` (add a new file to support a new service)
|
│ vault-seed-<svc>.sh — per-service Vault secret seeders; auto-invoked by `bin/disinto --with <svc>` (add a new file to support a new service)
|
||||||
├── docs/ Protocol docs (PHASE-PROTOCOL.md, EVIDENCE-ARCHITECTURE.md)
|
├── docs/ Protocol docs (PHASE-PROTOCOL.md, EVIDENCE-ARCHITECTURE.md)
|
||||||
|
|
|
||||||
|
|
@ -1,113 +0,0 @@
|
||||||
#!/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
|
|
||||||
|
|
||||||
# CapDrop — should contain ALL
|
|
||||||
cap_drop=$(echo "$inspect_json" | python3 -c "import sys,json; caps=json.load(sys.stdin)[0]['HostConfig']['CapDrop'] or []; print(' '.join(caps))")
|
|
||||||
if echo "$cap_drop" | grep -q "ALL"; then
|
|
||||||
pass "CapDrop contains ALL"
|
|
||||||
else
|
|
||||||
fail "CapDrop expected ALL, got: $cap_drop"
|
|
||||||
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