go/scripts/agent-setup.sh
Claude d92762ecdc
feat(agentci): Clotho orchestrator and security hardening
Adds the Clotho dual-run verification system and hardens the entire
agent dispatch pipeline against command injection, token exposure,
and SSH MitM attacks. Breaks the agentci→handlers circular dependency.

Security:
- SanitizePath (regex whitelist + filepath.Base) for all dispatch inputs
- EscapeShellArg for shell argument safety
- SecureSSHCommand (StrictHostKeyChecking=yes, BatchMode=yes)
- ForgeToken removed from ticket JSON, transferred via .env with 0600
- ssh-keyscan on agent add populates known_hosts before first connection

Clotho:
- Spinner orchestrator determines Standard vs Dual execution mode
- Config-driven via ClothoConfig (strategy, validation_threshold)
- Agent runner supports claude/codex/gemini backends with dual-run
- Divergence detection compares thread outputs via git diff

API:
- LoadActiveAgents() returns map[string]AgentConfig (no handlers import)
- LoadClothoConfig() reads clotho section from config
- Forge helpers: AssignIssue, EnsureLabel, AddIssueLabels

32 tests pass (19 agentci + 13 dispatch).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-10 03:08:16 +00:00

86 lines
2.4 KiB
Bash
Executable file

#!/bin/bash
# agent-setup.sh — Bootstrap an AgentCI agent machine via SSH.
#
# Usage: agent-setup.sh <user@host>
#
# Creates work directories, copies agent-runner.sh, installs cron,
# and verifies prerequisites.
set -euo pipefail
HOST="${1:?Usage: agent-setup.sh <user@host>}"
SSH_OPTS="-o StrictHostKeyChecking=yes -o BatchMode=yes -o ConnectTimeout=10"
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
RUNNER_SCRIPT="${SCRIPT_DIR}/agent-runner.sh"
if [ ! -f "$RUNNER_SCRIPT" ]; then
echo "ERROR: agent-runner.sh not found at $RUNNER_SCRIPT"
exit 1
fi
echo "=== AgentCI Setup: $HOST ==="
# --- 1. Test SSH ---
echo -n "Testing SSH... "
if ! ssh $SSH_OPTS "$HOST" "echo ok" >/dev/null 2>&1; then
echo "FAILED — cannot reach $HOST"
exit 1
fi
echo "OK"
# --- 2. Create directories ---
echo -n "Creating directories... "
ssh $SSH_OPTS "$HOST" "mkdir -p ~/ai-work/{queue,active,done,logs,jobs}"
echo "OK"
# --- 3. Copy runner script ---
echo -n "Copying agent-runner.sh... "
scp $SSH_OPTS "$RUNNER_SCRIPT" "${HOST}:~/ai-work/agent-runner.sh"
ssh $SSH_OPTS "$HOST" "chmod +x ~/ai-work/agent-runner.sh"
echo "OK"
# --- 4. Install cron (idempotent) ---
echo -n "Installing cron... "
CRON_LINE="*/5 * * * * ~/ai-work/agent-runner.sh >> ~/ai-work/logs/runner.log 2>&1"
ssh $SSH_OPTS "$HOST" "
if crontab -l 2>/dev/null | grep -qF 'agent-runner.sh'; then
echo 'already installed'
else
(crontab -l 2>/dev/null; echo '$CRON_LINE') | crontab -
echo 'installed'
fi
"
# --- 5. Verify prerequisites ---
echo "Checking prerequisites..."
MISSING=""
for tool in jq git claude; do
if ssh $SSH_OPTS "$HOST" "command -v $tool" >/dev/null 2>&1; then
echo " $tool: OK"
else
echo " $tool: MISSING"
MISSING="$MISSING $tool"
fi
done
if [ -n "$MISSING" ]; then
echo ""
echo "WARNING: Missing tools:$MISSING"
echo "Install them before the agent can process tickets."
fi
# --- 6. Round-trip test ---
echo -n "Round-trip test... "
TEST_FILE="queue/test-setup-$(date +%s).json"
ssh $SSH_OPTS "$HOST" "echo '{\"test\":true}' > ~/ai-work/$TEST_FILE"
RESULT=$(ssh $SSH_OPTS "$HOST" "cat ~/ai-work/$TEST_FILE && rm ~/ai-work/$TEST_FILE")
if [ "$RESULT" = '{"test":true}' ]; then
echo "OK"
else
echo "FAILED"
exit 1
fi
echo ""
echo "=== Setup complete ==="
echo "Agent queue: $HOST:~/ai-work/queue/"
echo "Runner log: $HOST:~/ai-work/logs/runner.log"