Files
agents_and_robots/dev-scripts/agent/provision-agent-user_test.sh
T
egutierrez 4c5bf95def feat(0144b): provision-agent-user.sh script idempotente + templates
Bash script que provisiona Matrix user via Synapse admin API + login para
access_token + scaffold completo (config.yaml, agent.go, prompts/system.md).
6 templates (user/sudo x config/agent.go/prompt). 20 tests bash pasan.
Genera .env con AGENT_<ID>_TOKEN/PASSWORD/PICKLE/DEVICE_ID + URL mesh.
2026-05-24 14:07:13 +02:00

213 lines
9.0 KiB
Bash
Executable File

#!/usr/bin/env bash
# provision-agent-user_test.sh — tests bash para provision-agent-user.sh.
#
# Mockea la Synapse admin API + /v3/login con un mini servidor python.
#
# Casos:
# T1. Provision exitoso mode=user → exit 0, archivos generados
# T2. Provision exitoso mode=sudo → exit 0, plantilla sudo aplicada
# T3. Idempotencia: re-run sobre agente existente → exit 0 + "Already provisioned"
# T4. agent-id invalido (no match regex) → exit 1
# T5. mode invalido (no user/sudo) → exit 1
# T6. Falta MATRIX_ADMIN_TOKEN → exit 1
# T7. Permisos .env = 0600
# T8. config.yaml contiene tags correctos (user/sudo)
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
PROV="$SCRIPT_DIR/provision-agent-user.sh"
[[ -x "$PROV" ]] || { echo "FAIL: $PROV not executable"; exit 1; }
# ── isolated test workspace ────────────────────────────────────────────────
TEST_DIR="$(mktemp -d -t fn_prov_test_XXXXXX)"
trap 'rm -rf "$TEST_DIR"; kill_mock || true' EXIT
cd "$TEST_DIR"
# Lay out a minimal repo tree the script needs (REPO_ROOT cd'd by _common.sh).
mkdir -p dev-scripts/agent/templates/prompts agents
cp -r "$SCRIPT_DIR/templates/." dev-scripts/agent/templates/
cp "$SCRIPT_DIR/../_common.sh" dev-scripts/_common.sh
cp "$PROV" dev-scripts/agent/provision-agent-user.sh
chmod +x dev-scripts/agent/provision-agent-user.sh
PROV_LOCAL="$TEST_DIR/dev-scripts/agent/provision-agent-user.sh"
# Mock REPO_ROOT redirection: _common.sh uses BASH_SOURCE to find root; copying
# the layout above ensures REPO_ROOT === $TEST_DIR/.
# ── mock Synapse admin API + /v3/login ────────────────────────────────────
MOCK_PORT="${FN_PROV_TEST_PORT:-19981}"
MOCK_LOG="$TEST_DIR/mock.log"
start_mock() {
python3 -c "
import http.server, json, sys
class H(http.server.BaseHTTPRequestHandler):
def _read(self):
n = int(self.headers.get('Content-Length','0') or 0)
return self.rfile.read(n) if n else b''
def do_PUT(self):
body = self._read()
self.send_response(201)
self.send_header('Content-Type','application/json')
self.end_headers()
self.wfile.write(b'{}')
def do_POST(self):
body = self._read()
self.send_response(200)
self.send_header('Content-Type','application/json')
self.end_headers()
self.wfile.write(json.dumps({
'access_token':'syt_FAKETOKEN_'+self.path.replace('/','_'),
'device_id':'TESTDEVICE01',
'user_id':'@test:matrix.local'
}).encode())
def log_message(self, fmt, *args):
sys.stderr.write(fmt % args + '\n')
http.server.HTTPServer(('127.0.0.1', $MOCK_PORT), H).serve_forever()
" >"$MOCK_LOG" 2>&1 &
MOCK_PID=$!
echo "$MOCK_PID" > "$TEST_DIR/.mock.pid"
# wait for port
for _ in $(seq 1 50); do
if curl -sS -o /dev/null "http://127.0.0.1:$MOCK_PORT/" 2>/dev/null; then return 0; fi
sleep 0.1
done
echo "FAIL: mock did not come up" >&2
return 1
}
kill_mock() {
[[ -f "$TEST_DIR/.mock.pid" ]] || return 0
local pid; pid=$(cat "$TEST_DIR/.mock.pid")
kill "$pid" 2>/dev/null || true
}
start_mock
# Env shared by all tests (FN_PROV_TEST=1 skips load_env)
export FN_PROV_TEST=1
export MATRIX_HOMESERVER="http://127.0.0.1:$MOCK_PORT"
export MATRIX_SERVER_NAME="matrix.local"
export MATRIX_ADMIN_TOKEN="syt_FAKE_ADMIN"
export OPERATOR_MATRIX_ID="@operator:matrix.local"
PASS=0
FAIL=0
declare -a FAILED_TESTS
t_pass() { echo "$1"; PASS=$((PASS+1)); }
t_fail() { echo "$1"; FAIL=$((FAIL+1)); FAILED_TESTS+=("$1"); }
# ── T1: provision exitoso mode=user ────────────────────────────────────────
echo "T1: provision exitoso mode=user"
: > .env
chmod 0600 .env
"$PROV_LOCAL" agent-home-wsl home-wsl user >/tmp/t1.out 2>&1 \
&& t_pass "exit 0" \
|| { cat /tmp/t1.out; t_fail "T1 exit nonzero"; }
[[ -f agents/agent-home-wsl/config.yaml ]] && t_pass "T1 config.yaml exists" || t_fail "T1 config.yaml missing"
[[ -f agents/agent-home-wsl/agent.go ]] && t_pass "T1 agent.go exists" || t_fail "T1 agent.go missing"
[[ -f agents/agent-home-wsl/prompts/system.md ]] && t_pass "T1 system.md exists" || t_fail "T1 system.md missing"
[[ -d agents/agent-home-wsl/data ]] && t_pass "T1 data/ exists" || t_fail "T1 data/ missing"
# T8: mode=user tag present in config
grep -q "tags: \[agent, llm, devicemesh, home-wsl, user\]" agents/agent-home-wsl/config.yaml \
&& t_pass "T1 config tags include 'user'" \
|| t_fail "T1 config tags wrong: $(grep '^ tags:' agents/agent-home-wsl/config.yaml || echo MISSING)"
# T7: .env permission 0600
ENV_PERM=$(stat -c %a .env 2>/dev/null || stat -f %A .env 2>/dev/null)
[[ "$ENV_PERM" == "600" ]] && t_pass "T7 .env perm 0600" || t_fail "T7 .env perm = $ENV_PERM (expected 600)"
# Vars present in .env
grep -q "^MATRIX_TOKEN_AGENT_HOME_WSL=" .env && t_pass "T1 MATRIX_TOKEN_AGENT_HOME_WSL in .env" || t_fail "T1 token missing in .env"
grep -q "^PICKLE_KEY_AGENT_HOME_WSL=" .env && t_pass "T1 PICKLE_KEY_AGENT_HOME_WSL in .env" || t_fail "T1 pickle missing in .env"
grep -q "^MATRIX_DEVICE_ID_AGENT_HOME_WSL=" .env && t_pass "T1 MATRIX_DEVICE_ID in .env" || t_fail "T1 device id missing in .env"
grep -q "^AGENT_HOME_WSL_DEVICE_MESH_URL=" .env && t_pass "T1 DEVICE_MESH_URL in .env" || t_fail "T1 device mesh url missing in .env"
# ── T3: idempotencia (re-run sobre el mismo agente) ────────────────────────
echo "T3: idempotencia (re-run sobre agente existente)"
OUT2=$("$PROV_LOCAL" agent-home-wsl home-wsl user 2>&1)
RC=$?
if [[ $RC -eq 0 ]] && echo "$OUT2" | grep -q "Already provisioned"; then
t_pass "T3 idempotent re-run"
else
echo "$OUT2"
t_fail "T3 idempotent re-run (rc=$RC)"
fi
# ── T2: provision exitoso mode=sudo ────────────────────────────────────────
echo "T2: provision exitoso mode=sudo"
"$PROV_LOCAL" agent-home-wsl-sudo home-wsl sudo >/tmp/t2.out 2>&1 \
&& t_pass "T2 exit 0" \
|| { cat /tmp/t2.out; t_fail "T2 exit nonzero"; }
[[ -f agents/agent-home-wsl-sudo/config.yaml ]] && t_pass "T2 config.yaml exists" || t_fail "T2 config.yaml missing"
grep -q "tags: \[agent, llm, devicemesh, home-wsl, sudo\]" agents/agent-home-wsl-sudo/config.yaml \
&& t_pass "T2 config tags include 'sudo'" \
|| t_fail "T2 config tags wrong"
grep -q "requires_approval: true" agents/agent-home-wsl-sudo/config.yaml \
&& t_pass "T2 requires_approval: true" \
|| t_fail "T2 requires_approval not set"
# system prompt sudo has formal/strict copy
grep -q "🔒" agents/agent-home-wsl-sudo/prompts/system.md \
&& t_pass "T2 sudo prompt has 🔒 prefix" \
|| t_fail "T2 sudo prompt missing 🔒 marker"
# ── T4: agent-id invalido ──────────────────────────────────────────────────
echo "T4: agent-id invalido"
if "$PROV_LOCAL" "BadAgent" home-wsl user >/tmp/t4.out 2>&1; then
t_fail "T4 should have failed but didn't"
else
if grep -q "invalid" /tmp/t4.out; then
t_pass "T4 rejected invalid agent-id"
else
cat /tmp/t4.out
t_fail "T4 rejected without 'invalid' message"
fi
fi
# ── T5: mode invalido ──────────────────────────────────────────────────────
echo "T5: mode invalido"
if "$PROV_LOCAL" agent-test test bogus >/tmp/t5.out 2>&1; then
t_fail "T5 should have failed but didn't"
else
grep -q "mode" /tmp/t5.out && t_pass "T5 rejected invalid mode" || { cat /tmp/t5.out; t_fail "T5 wrong error"; }
fi
# ── T6: falta MATRIX_ADMIN_TOKEN ───────────────────────────────────────────
echo "T6: falta MATRIX_ADMIN_TOKEN"
(
unset MATRIX_ADMIN_TOKEN
if "$PROV_LOCAL" agent-test-2 test user >/tmp/t6.out 2>&1; then
exit 99
else
grep -q "MATRIX_ADMIN_TOKEN" /tmp/t6.out && exit 0 || exit 1
fi
)
RC=$?
case "$RC" in
0) t_pass "T6 rejected when MATRIX_ADMIN_TOKEN missing" ;;
99) t_fail "T6 should have failed but didn't" ;;
*) cat /tmp/t6.out; t_fail "T6 rejected without correct message" ;;
esac
# ── summary ────────────────────────────────────────────────────────────────
echo ""
echo "── results ─────────────────────────────────────────────────"
echo " pass: $PASS"
echo " fail: $FAIL"
if (( FAIL > 0 )); then
echo " failed tests:"
for t in "${FAILED_TESTS[@]}"; do echo " - $t"; done
exit 1
fi
echo " All tests passed."
exit 0