The agent host's vault and SilverBullet (M5.4)
CI / checks (push) Skipped
CI / checks (pull_request) Successful in 1m50s
CI / e2e (pull_request) Successful in 4m45s

deploy/agent-host sets up the vault on nisse-host (infra/tofu#77) and
SilverBullet over it: the operator writes the vault, the agents' memory/
is read-only to it, and only the operator's Caddy reaches it, which
serves vault.dongar.net to the LAN. scripts/agent-host.sh installs and
checks it from here.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01J5Utyfzw7gF7UhjRDEtjTk
This commit is contained in:
dongarandClaude Opus 5.5 committed 2026-10-18 20:55:21 +00:00
1 parent da9097a4dd
commit eafe1b9f4a
8 files changed
+342 -7

No files matched your search

+58
View File
@@ -0,0 +1,58 @@
#!/usr/bin/env bash
# The agent host's vault and SilverBullet (deploy/agent-host), from this box.
# scripts/agent-host.sh install copy deploy/agent-host over and run setup.sh
# scripts/agent-host.sh check check SilverBullet runs and the mounts and
# firewall hold
# scripts/agent-host.sh ssh ... run a command on the host
# Trusts only the host keys bot-ansible posted (~/bin/tofu-wait.sh saved them).
set -euo pipefail
host=${AGENT_HOST:-nisse-host.garrett-hall.com}
key=${AGENT_HOST_KEY:-/root/nisse-e2e/ssh/id_ed25519}
known=${AGENT_HOST_KNOWN:-/root/nisse-e2e/nisse-host.known_hosts}
repo=$(cd "$(dirname "$0")/.." && pwd)
on_host() {
ssh -i "$key" -o UserKnownHostsFile="$known" -o StrictHostKeyChecking=yes \
-o BatchMode=yes -o ConnectTimeout=10 "ubuntu@$host" "$@"
}
case ${1:-} in
install)
tar -C "$repo/deploy" -cf - agent-host |
on_host 'rm -rf /tmp/agent-host && tar -C /tmp -xf - && sudo bash /tmp/agent-host/setup.sh'
;;
check)
on_host 'bash -s' <<'EOF'
set -u
fail=0
ok() { echo "ok: $1"; }
bad() { echo "FAIL: $1"; fail=1; }
cd /opt/stacks/silverbullet
[ "$(sudo docker compose ps --status running -q | wc -l)" -ge 1 ] \
&& ok "SilverBullet is running" || bad "SilverBullet isn't running"
code=$(curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:3000/)
case $code in 2??|3??) ok "it answers locally ($code)" ;; *) bad "it answers $code" ;; esac
probe=.nisse-probe-$$
sudo docker compose exec -T -u 1000 silverbullet sh -c "touch /vault/infrastructure/$probe && rm /vault/infrastructure/$probe" \
&& ok "the operator's folders are writable" || bad "the operator's folders aren't writable"
if sudo docker compose exec -T silverbullet sh -c "touch /vault/memory/$probe" 2>/dev/null; then
sudo docker compose exec -T silverbullet rm -f "/vault/memory/$probe"
bad "memory/ is writable from SilverBullet, even as root in it"
else
ok "memory/ is read-only to SilverBullet"
fi
sudo iptables -S DOCKER-USER | grep -q -- '--comment nisse-firewall' \
&& ok "the firewall rule is in place" || bad "no firewall rule"
exit $fail
EOF
;;
ssh)
shift
on_host "$@"
;;
*)
sed -n '2,7p' "$0"
exit 2
;;
esac