Files
timmy-config/infra/matrix/scripts/verify-hermes-integration.sh
Ezra (Archivist) dbcdc5aea7 feat(matrix): add Hermes integration verification runbook and probe script
- HERMES_INTEGRATION_VERIFICATION.md maps #166 acceptance criteria
to the existing hermes-agent Matrix platform adapter.
- verify-hermes-integration.sh performs live probe against any
Matrix homeserver to confirm E2EE readiness.

Refs #166, #183
2026-04-05 20:18:50 +00:00

169 lines
4.9 KiB
Bash
Executable File

#!/usr/bin/env bash
# verify-hermes-integration.sh — Verify Hermes Matrix adapter integration
# Usage: ./verify-hermes-integration.sh
# Issue: #166
set -uo pipefail
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
PASS=0
FAIL=0
pass() { echo -e "${GREEN}[PASS]${NC} $*"; ((PASS++)); }
fail() { echo -e "${RED}[FAIL]${NC} $*"; ((FAIL++)); }
warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
log() { echo -e "\n==> $*"; }
log "Hermes Matrix Integration Verification"
log "======================================"
# === Check matrix-nio ===
log "Checking Python dependencies..."
if python3 -c "import nio" 2>/dev/null; then
pass "matrix-nio is installed"
else
fail "matrix-nio not installed. Run: pip install 'matrix-nio[e2e]'"
exit 1
fi
# === Check env vars ===
log "Checking environment variables..."
MISSING=0
for var in MATRIX_HOMESERVER MATRIX_USER_ID; do
if [[ -z "${!var:-}" ]]; then
fail "$var is not set"
MISSING=1
else
pass "$var is set"
fi
done
if [[ -z "${MATRIX_ACCESS_TOKEN:-}" && -z "${MATRIX_PASSWORD:-}" ]]; then
fail "Either MATRIX_ACCESS_TOKEN or MATRIX_PASSWORD must be set"
MISSING=1
fi
if [[ $MISSING -gt 0 ]]; then
exit 1
else
pass "Authentication credentials present"
fi
# === Run Python probe ===
log "Running live probe against $MATRIX_HOMESERVER..."
python3 <<'PYEOF'
import asyncio
import os
import sys
from datetime import datetime, timezone
from nio import AsyncClient, LoginResponse, SyncResponse, RoomSendResponse
HOMESERVER = os.getenv("MATRIX_HOMESERVER", "").rstrip("/")
USER_ID = os.getenv("MATRIX_USER_ID", "")
ACCESS_TOKEN = os.getenv("MATRIX_ACCESS_TOKEN", "")
PASSWORD = os.getenv("MATRIX_PASSWORD", "")
ENCRYPTION = os.getenv("MATRIX_ENCRYPTION", "").lower() in ("true", "1", "yes")
ROOM_ALIAS = os.getenv("MATRIX_TEST_ROOM", "#operator-room:matrix.timmy.foundation")
def ok(msg): print(f"\033[0;32m[PASS]\033[0m {msg}")
def err(msg): print(f"\033[0;31m[FAIL]\033[0m {msg}")
def warn(msg): print(f"\033[1;33m[WARN]\033[0m {msg}")
async def main():
client = AsyncClient(HOMESERVER, USER_ID)
try:
# --- Login ---
if ACCESS_TOKEN:
client.access_token = ACCESS_TOKEN
client.user_id = USER_ID
resp = await client.whoami()
if hasattr(resp, "user_id"):
ok(f"Access token valid for {resp.user_id}")
else:
err(f"Access token invalid: {resp}")
return 1
elif PASSWORD:
resp = await client.login(PASSWORD, device_name="HermesVerify")
if isinstance(resp, LoginResponse):
ok(f"Password login succeeded for {resp.user_id}")
else:
err(f"Password login failed: {resp}")
return 1
else:
err("No credentials available")
return 1
# --- Sync once to populate rooms ---
sync_resp = await client.sync(timeout=10000)
if isinstance(sync_resp, SyncResponse):
ok(f"Initial sync complete ({len(sync_resp.rooms.join)} joined rooms)")
else:
err(f"Initial sync failed: {sync_resp}")
return 1
# --- Join operator room ---
join_resp = await client.join_room(ROOM_ALIAS)
if hasattr(join_resp, "room_id"):
room_id = join_resp.room_id
ok(f"Joined room {ROOM_ALIAS} -> {room_id}")
else:
err(f"Could not join {ROOM_ALIAS}: {join_resp}")
return 1
# --- E2EE check ---
if ENCRYPTION:
if hasattr(client, "olm") and client.olm:
ok("E2EE crypto store is active")
else:
warn("E2EE requested but crypto store not loaded (install matrix-nio[e2e])")
else:
warn("E2EE is disabled")
# --- Send test message ---
test_body = f"🔥 Hermes Matrix probe | {datetime.now(timezone.utc).isoformat()}"
send_resp = await client.room_send(
room_id,
"m.room.message",
{"msgtype": "m.text", "body": test_body},
)
if isinstance(send_resp, RoomSendResponse):
ok(f"Test message sent (event_id: {send_resp.event_id})")
else:
err(f"Test message failed: {send_resp}")
return 1
ok("All integration checks passed — Hermes Matrix adapter is ready.")
return 0
finally:
await client.close()
sys.exit(asyncio.run(main()))
PYEOF
PROBE_EXIT=$?
if [[ $PROBE_EXIT -ne 0 ]]; then
((FAIL++))
fi
# === Summary ===
log "======================================"
echo -e "Results: ${GREEN}$PASS passed${NC}, ${RED}$FAIL failures${NC}"
if [[ $FAIL -gt 0 ]]; then
echo ""
echo "Integration verification FAILED. Fix errors above and re-run."
exit 1
else
echo ""
echo "Integration verification PASSED. Hermes Matrix adapter is ready for production."
exit 0
fi