The gateway reads its sandbox rules and loads new dependencies only when it starts, and hermes update restarts it only for new code. Restart it at the end of the sandbox update step instead of before hermes update runs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
78 lines
3.1 KiB
Bash
78 lines
3.1 KiB
Bash
#!/bin/bash
|
|
#
|
|
# Purpose : Set up sandboxed AI agents (see sandbox/agent): install or update
|
|
# Anthropic's sandbox runtime (srt) and Hermes Agent, and turn on
|
|
# Claude Code's built-in sandbox. Run by install.sh and on every
|
|
# update (updates.d/72-sandbox.sh).
|
|
|
|
COREDESKTOP="$HOME/.local/share/coredesktop"
|
|
STATUS=0
|
|
|
|
# npm's global prefix is under /usr, so install to ~/.local; srt lands in ~/.local/bin
|
|
echo "Installing the sandbox runtime (srt)..."
|
|
npm install --global --prefix "$HOME/.local" --no-fund --no-audit @anthropic-ai/sandbox-runtime || STATUS=1
|
|
|
|
# --non-interactive skips Hermes' setup questions and its background gateway
|
|
# service; `configure hermes` chooses a model provider afterwards
|
|
if [ ! -x "$HOME/.local/bin/hermes" ]; then
|
|
echo "Installing Hermes Agent..."
|
|
curl -fsSL https://hermes-agent.nousresearch.com/install.sh | bash -s -- --non-interactive || STATUS=1
|
|
fi
|
|
|
|
# Claude Code runs every command it starts in its own sandbox, also built on
|
|
# bubblewrap and socat; it can't run inside srt because bubblewrap can't be
|
|
# nested. Anything already in the sandbox section of your settings wins over
|
|
# these defaults.
|
|
CLAUDE_SETTINGS="$HOME/.claude/settings.json"
|
|
if [ -f "$CLAUDE_SETTINGS" ]; then
|
|
domains="$(jq '.network.allowedDomains' "$COREDESKTOP/sandbox/config/base.json")"
|
|
tmp="$(mktemp "$CLAUDE_SETTINGS.XXXXXX")"
|
|
if jq --argjson domains "$domains" \
|
|
'.sandbox = ({enabled: true, network: {allowedDomains: $domains}} * (.sandbox // {}))' \
|
|
"$CLAUDE_SETTINGS" > "$tmp"; then
|
|
if cmp -s "$tmp" "$CLAUDE_SETTINGS"; then
|
|
rm -f "$tmp"
|
|
else
|
|
echo "Turning on Claude Code's sandbox..."
|
|
mv -f "$tmp" "$CLAUDE_SETTINGS"
|
|
fi
|
|
else
|
|
echo "Couldn't read $CLAUDE_SETTINGS; Claude Code's sandbox was not turned on."
|
|
rm -f "$tmp"
|
|
STATUS=1
|
|
fi
|
|
fi
|
|
|
|
# Hermes' gateway acts on messages from outside this machine, so it runs in
|
|
# the sandbox too: a systemd drop-in starts it through sandbox/bin/hermes. It
|
|
# also needs to reach the Matrix server in Hermes' settings, which differs on
|
|
# each machine; for other messaging services, add their domains to
|
|
# ~/.config/coredesktop/sandbox/hermes.json.
|
|
GATEWAY_UNIT="$HOME/.config/systemd/user/hermes-gateway.service"
|
|
if [ -f "$GATEWAY_UNIT" ]; then
|
|
if [ -x "$HOME/.local/bin/srt" ]; then
|
|
homeserver="$(sed -nE "s#^MATRIX_HOMESERVER=[\"']?https?://([^/:\"']+).*#\1#p" "$HOME/.hermes/.env" 2> /dev/null | head -n 1)"
|
|
dropin="$GATEWAY_UNIT.d/coredesktop-sandbox.conf"
|
|
tmp="$(mktemp)"
|
|
cat > "$tmp" << EOF
|
|
# Written by CoreDesktop (sandbox/setup.sh): run Hermes' gateway in the sandbox
|
|
[Service]
|
|
Environment="COREDESKTOP_SANDBOX_DOMAINS=$homeserver"
|
|
ExecStart=
|
|
ExecStart=%h/.local/share/coredesktop/sandbox/bin/hermes gateway run
|
|
EOF
|
|
if cmp -s "$tmp" "$dropin"; then
|
|
rm -f "$tmp"
|
|
else
|
|
echo "Running Hermes' gateway in the sandbox..."
|
|
mkdir -p "$(dirname "$dropin")" && mv -f "$tmp" "$dropin" && chmod 644 "$dropin" \
|
|
&& systemctl --user daemon-reload || STATUS=1
|
|
fi
|
|
else
|
|
echo "Hermes' gateway isn't sandboxed yet: the sandbox (srt) isn't installed."
|
|
STATUS=1
|
|
fi
|
|
fi
|
|
|
|
exit $STATUS
|