#!/bin/bash # Multi-admin integration test for c-relay-pg # Validates: # 1) primary admin can add a secondary admin # 2) secondary admin can execute non-privileged admin command (system_status) # 3) secondary admin cannot mutate admin list (remove_admin) # 4) primary admin can remove secondary admin set -euo pipefail RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' log_info() { echo -e "${BLUE}[INFO]${NC} $1" } log_success() { echo -e "${GREEN}[PASS]${NC} $1" } log_error() { echo -e "${RED}[FAIL]${NC} $1" } log_warn() { echo -e "${YELLOW}[WARN]${NC} $1" } RELAY_URL="ws://127.0.0.1:8888" # test key set used by ./make_and_restart_relay.sh -t PRIMARY_ADMIN_PRIVKEY="aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" PRIMARY_ADMIN_PUBKEY="6a04ab98d9e4774ad806e302dddeb63bea16b5cb5f223ee77478e861bb583eb3" RELAY_PUBKEY="4f355bdcb7cc0af728ef3cceb9615d90684bb5b2ca5f859ab0f0b704075871aa" # secondary admin keypair generated per test run SECONDARY_ADMIN_PRIVKEY="" SECONDARY_ADMIN_PUBKEY="" # postgres defaults from make_and_restart_relay.sh PGHOST="localhost" PGPORT="5432" PGDATABASE="crelay" PGUSER="crelay" PGPASSWORD="crelay" require_bin() { if ! command -v "$1" >/dev/null 2>&1; then log_error "Required command not found: $1" exit 1 fi } get_admin_list_from_db() { PGPASSWORD="$PGPASSWORD" psql \ -h "$PGHOST" -p "$PGPORT" -U "$PGUSER" -d "$PGDATABASE" \ -tAc "SELECT value FROM config WHERE key='admin_pubkey';" 2>/dev/null | tr -d '[:space:]' } send_admin_command() { local signer_privkey="$1" local command_json="$2" local encrypted encrypted=$(nak encrypt "$command_json" --sec "$signer_privkey" --recipient-pubkey "$RELAY_PUBKEY" 2>/dev/null) if [[ -z "${encrypted:-}" ]]; then log_error "Failed to encrypt command: $command_json" return 1 fi local event_json event_json=$(nak event --kind 23456 --content "$encrypted" --sec "$signer_privkey" --tag "p=$RELAY_PUBKEY" 2>/dev/null) if [[ -z "${event_json:-}" ]]; then log_error "Failed to build admin event for command: $command_json" return 1 fi local result result=$(echo "$event_json" | nak event "$RELAY_URL" 2>&1 || true) if echo "$result" | grep -Eiq "error|failed|denied|invalid|unauthorized"; then log_warn "Relay returned non-success for command '$command_json': $result" return 1 fi return 0 } contains_pubkey() { local csv="$1" local key="$2" IFS=',' read -r -a arr <<< "$csv" for k in "${arr[@]}"; do [[ "$k" == "$key" ]] && return 0 done return 1 } main() { log_info "Starting multi-admin integration test" require_bin nak require_bin psql require_bin grep require_bin tr SECONDARY_ADMIN_PRIVKEY=$(nak key generate 2>/dev/null || true) if [[ -z "$SECONDARY_ADMIN_PRIVKEY" ]]; then log_error "Could not generate secondary admin private key" exit 1 fi SECONDARY_ADMIN_PUBKEY=$(nak key public "$SECONDARY_ADMIN_PRIVKEY" 2>/dev/null || true) if [[ -z "$SECONDARY_ADMIN_PUBKEY" ]]; then log_error "Could not derive secondary admin pubkey from generated private key" exit 1 fi log_info "Primary admin pubkey: ${PRIMARY_ADMIN_PUBKEY:0:16}..." log_info "Secondary admin pubkey: ${SECONDARY_ADMIN_PUBKEY:0:16}..." local current_admins current_admins=$(get_admin_list_from_db) if [[ -z "$current_admins" ]]; then log_error "Could not read admin_pubkey from database" exit 1 fi if ! contains_pubkey "$current_admins" "$PRIMARY_ADMIN_PUBKEY"; then log_error "Primary admin missing from DB admin list: $current_admins" exit 1 fi log_success "Primary admin exists in config table" # Clean slate: if secondary already present from prior run, remove via primary if contains_pubkey "$current_admins" "$SECONDARY_ADMIN_PUBKEY"; then log_info "Secondary admin already present; removing for clean start" send_admin_command "$PRIMARY_ADMIN_PRIVKEY" "[\"system_command\",\"remove_admin\",\"$SECONDARY_ADMIN_PUBKEY\"]" || true sleep 2 fi log_info "Adding secondary admin via primary admin command" send_admin_command "$PRIMARY_ADMIN_PRIVKEY" "[\"system_command\",\"add_admin\",\"$SECONDARY_ADMIN_PUBKEY\"]" sleep 2 current_admins=$(get_admin_list_from_db) if ! contains_pubkey "$current_admins" "$SECONDARY_ADMIN_PUBKEY"; then log_error "Secondary admin was not added. admin_pubkey='$current_admins'" exit 1 fi log_success "Secondary admin was added" # Verify secondary can execute a standard admin command with measurable side effect # Use whitelist insertion and verify via DB. local test_whitelist_pubkey test_whitelist_pubkey=$(nak key public "$(nak key generate 2>/dev/null)" 2>/dev/null || true) if [[ -z "$test_whitelist_pubkey" ]]; then log_error "Failed to generate test pubkey for secondary-admin whitelist command" exit 1 fi log_info "Sending whitelist command as secondary admin" send_admin_command "$SECONDARY_ADMIN_PRIVKEY" "[\"whitelist\",\"pubkey\",\"$test_whitelist_pubkey\"]" sleep 2 local whitelist_count whitelist_count=$(PGPASSWORD="$PGPASSWORD" psql \ -h "$PGHOST" -p "$PGPORT" -U "$PGUSER" -d "$PGDATABASE" \ -tAc "SELECT COUNT(*) FROM auth_rules WHERE rule_type='whitelist' AND pattern_type='pubkey' AND pattern_value='$test_whitelist_pubkey' AND active=1;" 2>/dev/null | tr -d '[:space:]') if [[ "${whitelist_count:-0}" -lt 1 ]]; then log_error "Secondary admin did not create whitelist rule as expected" exit 1 fi log_success "Secondary admin executed whitelist admin command" # Verify secondary cannot mutate admin list (remove_admin restricted to primary) log_info "Attempting remove_admin as secondary (should be rejected)" send_admin_command "$SECONDARY_ADMIN_PRIVKEY" "[\"system_command\",\"remove_admin\",\"$SECONDARY_ADMIN_PUBKEY\"]" || true sleep 2 current_admins=$(get_admin_list_from_db) if ! contains_pubkey "$current_admins" "$SECONDARY_ADMIN_PUBKEY"; then log_error "Secondary admin was able to remove admin (unexpected). admin_pubkey='$current_admins'" exit 1 fi log_success "Secondary admin could not remove admin list entry" # Cleanup: primary removes secondary log_info "Removing secondary admin via primary admin" send_admin_command "$PRIMARY_ADMIN_PRIVKEY" "[\"system_command\",\"remove_admin\",\"$SECONDARY_ADMIN_PUBKEY\"]" sleep 2 current_admins=$(get_admin_list_from_db) if contains_pubkey "$current_admins" "$SECONDARY_ADMIN_PUBKEY"; then log_error "Secondary admin still present after primary remove_admin. admin_pubkey='$current_admins'" exit 1 fi log_success "Primary admin removed secondary admin" log_success "Multi-admin integration test passed" } main "$@"