#!/usr/bin/env bash # INSTALL-01: First Install Verification Test # Tests that a freshly installed Archipelago node has all core services operational. # Usage: bash scripts/test-first-install.sh [host] [password] set -uo pipefail HOST="${1:-192.168.1.228}" PASS="${2:-password123}" PASS_COUNT=0 FAIL_COUNT=0 SSH_KEY="${ARCHIPELAGO_SSH_KEY:-$HOME/.ssh/archipelago-deploy}" green() { printf "\033[32m PASS \033[0m %s\n" "$1"; ((PASS_COUNT++)); } red() { printf "\033[31m FAIL \033[0m %s\n" "$1"; ((FAIL_COUNT++)); } header(){ printf "\n\033[1;36m--- %s ---\033[0m\n" "$1"; } rpc() { local method="$1" local params="${2:-{}}" ssh -i "$SSH_KEY" -o StrictHostKeyChecking=no "archipelago@${HOST}" \ "curl -s -c /tmp/test-cookies.txt -b /tmp/test-cookies.txt -X POST http://localhost/rpc/v1 \ -H 'Content-Type: application/json' \ -H \"X-CSRF-Token: \$(grep csrf_token /tmp/test-cookies.txt 2>/dev/null | awk '{print \$NF}')\" \ -d '{\"method\":\"$method\",\"params\":$params}'" 2>/dev/null } header "Authentication" LOGIN=$(ssh -i "$SSH_KEY" -o StrictHostKeyChecking=no "archipelago@${HOST}" \ "curl -s -c /tmp/test-cookies.txt -X POST http://localhost/rpc/v1 \ -H 'Content-Type: application/json' \ -d '{\"method\":\"auth.login\",\"params\":{\"password\":\"$PASS\"}}'" 2>/dev/null) if echo "$LOGIN" | grep -q '"error":null'; then green "Login successful" else red "Login failed: $LOGIN" echo "Cannot continue without authentication." exit 1 fi header "1. Node DID" DID_RESULT=$(rpc "node.did") DID=$(echo "$DID_RESULT" | python3 -c "import sys,json; print(json.load(sys.stdin).get('result',{}).get('did',''))" 2>/dev/null) if [[ "$DID" == did:key:z* ]]; then green "Node DID format valid: ${DID:0:32}..." else red "Invalid DID format: $DID" fi header "2. Nostr Pubkey" NOSTR_RESULT=$(rpc "node.nostr-pubkey") NPUB=$(echo "$NOSTR_RESULT" | python3 -c "import sys,json; r=json.load(sys.stdin).get('result',{}); print(r.get('nostr_npub',''))" 2>/dev/null) HEX=$(echo "$NOSTR_RESULT" | python3 -c "import sys,json; r=json.load(sys.stdin).get('result',{}); print(r.get('nostr_pubkey',''))" 2>/dev/null) if [[ "$NPUB" == npub1* ]] && [[ ${#HEX} -eq 64 ]]; then green "Nostr pubkey valid: npub=${NPUB:0:16}... hex=${HEX:0:16}..." else red "Invalid Nostr pubkey: npub=$NPUB hex=$HEX" fi header "3. Identity Create" ID_RESULT=$(rpc "identity.create" '{"name":"Test User"}') ID_DID=$(echo "$ID_RESULT" | python3 -c "import sys,json; r=json.load(sys.stdin).get('result',{}); print(r.get('did',''))" 2>/dev/null) if [[ "$ID_DID" == did:key:* ]]; then green "Identity created with DID: ${ID_DID:0:32}..." else # May already exist, try listing LIST_RESULT=$(rpc "identity.list") LIST_COUNT=$(echo "$LIST_RESULT" | python3 -c "import sys,json; r=json.load(sys.stdin).get('result',{}); ids=r.get('identities',[]); print(len(ids))" 2>/dev/null) if [[ "$LIST_COUNT" -gt 0 ]]; then green "Identity exists ($LIST_COUNT identities found)" else red "Identity create failed: $ID_RESULT" fi fi header "4. Identity List" LIST_RESULT=$(rpc "identity.list") LIST_COUNT=$(echo "$LIST_RESULT" | python3 -c "import sys,json; r=json.load(sys.stdin).get('result',{}); ids=r.get('identities',[]); print(len(ids))" 2>/dev/null) if [[ "$LIST_COUNT" -gt 0 ]]; then green "Identity list has $LIST_COUNT identit(ies)" else red "No identities found" fi header "5. Tor Address" TOR_RESULT=$(rpc "node.tor-address") TOR_ADDR=$(echo "$TOR_RESULT" | python3 -c "import sys,json; print(json.load(sys.stdin).get('result',{}).get('tor_address',''))" 2>/dev/null) if [[ "$TOR_ADDR" == *.onion ]]; then green "Tor address valid: ${TOR_ADDR:0:24}..." else red "No Tor address found" fi header "6. Webhook Config" WH_RESULT=$(rpc "webhook.get-config") WH_ERROR=$(echo "$WH_RESULT" | python3 -c "import sys,json; print(json.load(sys.stdin).get('error',{}) or 'none')" 2>/dev/null) if [[ "$WH_ERROR" != "none" ]] && [[ "$WH_ERROR" != "None" ]]; then # webhook.get-config may not exist, which is fine (disabled by default) green "Webhooks not configured (default/disabled)" else WH_ENABLED=$(echo "$WH_RESULT" | python3 -c "import sys,json; r=json.load(sys.stdin).get('result',{}); print(r.get('enabled', False))" 2>/dev/null) if [[ "$WH_ENABLED" == "False" ]]; then green "Webhooks disabled by default" else green "Webhook config accessible (enabled=$WH_ENABLED)" fi fi header "7. Health Monitor" STATS_RESULT=$(rpc "system.stats") CONTAINER_COUNT=$(echo "$STATS_RESULT" | python3 -c " import sys,json r=json.load(sys.stdin).get('result',{}) print(r.get('container_count', r.get('running_containers', -1))) " 2>/dev/null) if [[ "$CONTAINER_COUNT" -gt 0 ]]; then green "Health monitor reports $CONTAINER_COUNT containers" else # Try alternate endpoint HEALTH=$(ssh -i "$SSH_KEY" -o StrictHostKeyChecking=no "archipelago@${HOST}" \ "curl -s http://localhost/health" 2>/dev/null) if [[ "$HEALTH" == "OK" ]]; then green "Health endpoint returns OK" else red "Health monitor check failed (containers=$CONTAINER_COUNT)" fi fi header "8. DWN Status" DWN_RESULT=$(rpc "dwn.status") DWN_RUNNING=$(echo "$DWN_RESULT" | python3 -c "import sys,json; print(json.load(sys.stdin).get('result',{}).get('running', False))" 2>/dev/null) DWN_MSG=$(echo "$DWN_RESULT" | python3 -c "import sys,json; print(json.load(sys.stdin).get('result',{}).get('message_count', -1))" 2>/dev/null) if [[ "$DWN_RUNNING" == "True" ]]; then green "DWN operational (messages: $DWN_MSG)" else red "DWN not running" fi # Summary echo "" echo "===============================" printf "Results: \033[32m%d passed\033[0m, \033[31m%d failed\033[0m\n" "$PASS_COUNT" "$FAIL_COUNT" echo "===============================" [[ "$FAIL_COUNT" -eq 0 ]] && exit 0 || exit 1