- 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
169 lines
4.9 KiB
Bash
Executable File
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
|