4c5bf95def
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.
213 lines
9.0 KiB
Bash
Executable File
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
|