366 lines
11 KiB
Bash
366 lines
11 KiB
Bash
|
|
#!/usr/bin/env bash
|
|||
|
|
# =====================================================
|
|||
|
|
# Installer JSON API Test Script
|
|||
|
|
# =====================================================
|
|||
|
|
# Tests all API endpoints and verifies functionality
|
|||
|
|
|
|||
|
|
set -Eeuo pipefail
|
|||
|
|
|
|||
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|||
|
|
|
|||
|
|
# Source libraries
|
|||
|
|
source "${SCRIPT_DIR}/libsupabase.sh"
|
|||
|
|
source "${SCRIPT_DIR}/lib_installer_json_api.sh"
|
|||
|
|
|
|||
|
|
# Colors for output
|
|||
|
|
RED='\033[0;31m'
|
|||
|
|
GREEN='\033[0;32m'
|
|||
|
|
YELLOW='\033[1;33m'
|
|||
|
|
BLUE='\033[0;34m'
|
|||
|
|
NC='\033[0m' # No Color
|
|||
|
|
|
|||
|
|
# Test counters
|
|||
|
|
TESTS_PASSED=0
|
|||
|
|
TESTS_FAILED=0
|
|||
|
|
TESTS_TOTAL=0
|
|||
|
|
|
|||
|
|
# Test configuration
|
|||
|
|
TEST_CTID="${TEST_CTID:-769697636}"
|
|||
|
|
TEST_EMAIL="${TEST_EMAIL:-test@example.com}"
|
|||
|
|
TEST_POSTGREST_URL="${TEST_POSTGREST_URL:-http://192.168.45.104:3000}"
|
|||
|
|
TEST_SERVICE_ROLE_KEY="${TEST_SERVICE_ROLE_KEY:-}"
|
|||
|
|
|
|||
|
|
# Usage
|
|||
|
|
usage() {
|
|||
|
|
cat <<EOF
|
|||
|
|
Usage: bash test_installer_json_api.sh [options]
|
|||
|
|
|
|||
|
|
Options:
|
|||
|
|
--ctid <id> Test CTID (default: 769697636)
|
|||
|
|
--email <email> Test email (default: test@example.com)
|
|||
|
|
--postgrest-url <url> PostgREST URL (default: http://192.168.45.104:3000)
|
|||
|
|
--service-role-key <key> Service role key for authenticated tests
|
|||
|
|
--help Show this help
|
|||
|
|
|
|||
|
|
Examples:
|
|||
|
|
# Basic test (public endpoints only)
|
|||
|
|
bash test_installer_json_api.sh
|
|||
|
|
|
|||
|
|
# Full test with authentication
|
|||
|
|
bash test_installer_json_api.sh --service-role-key "eyJhbGc..."
|
|||
|
|
|
|||
|
|
# Test specific instance
|
|||
|
|
bash test_installer_json_api.sh --ctid 769697636 --email max@beispiel.de
|
|||
|
|
EOF
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
# Parse arguments
|
|||
|
|
while [[ $# -gt 0 ]]; do
|
|||
|
|
case "$1" in
|
|||
|
|
--ctid) TEST_CTID="${2:-}"; shift 2 ;;
|
|||
|
|
--email) TEST_EMAIL="${2:-}"; shift 2 ;;
|
|||
|
|
--postgrest-url) TEST_POSTGREST_URL="${2:-}"; shift 2 ;;
|
|||
|
|
--service-role-key) TEST_SERVICE_ROLE_KEY="${2:-}"; shift 2 ;;
|
|||
|
|
--help|-h) usage; exit 0 ;;
|
|||
|
|
*) echo "Unknown option: $1"; usage; exit 1 ;;
|
|||
|
|
esac
|
|||
|
|
done
|
|||
|
|
|
|||
|
|
# Print functions
|
|||
|
|
print_header() {
|
|||
|
|
echo -e "\n${BLUE}========================================${NC}"
|
|||
|
|
echo -e "${BLUE}$1${NC}"
|
|||
|
|
echo -e "${BLUE}========================================${NC}\n"
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
print_test() {
|
|||
|
|
echo -e "${YELLOW}TEST $((TESTS_TOTAL + 1)):${NC} $1"
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
print_pass() {
|
|||
|
|
echo -e "${GREEN}✓ PASS${NC}: $1"
|
|||
|
|
((TESTS_PASSED++))
|
|||
|
|
((TESTS_TOTAL++))
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
print_fail() {
|
|||
|
|
echo -e "${RED}✗ FAIL${NC}: $1"
|
|||
|
|
((TESTS_FAILED++))
|
|||
|
|
((TESTS_TOTAL++))
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
print_skip() {
|
|||
|
|
echo -e "${YELLOW}⊘ SKIP${NC}: $1"
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
print_info() {
|
|||
|
|
echo -e "${BLUE}ℹ INFO${NC}: $1"
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
# Test functions
|
|||
|
|
|
|||
|
|
test_api_connectivity() {
|
|||
|
|
print_test "API Connectivity"
|
|||
|
|
|
|||
|
|
local response
|
|||
|
|
local http_code
|
|||
|
|
|
|||
|
|
response=$(curl -sS -w "\n%{http_code}" -X POST "${TEST_POSTGREST_URL}/rpc/get_public_config" \
|
|||
|
|
-H "Content-Type: application/json" \
|
|||
|
|
-d '{}' 2>&1 || echo -e "\nFAILED")
|
|||
|
|
|
|||
|
|
http_code=$(echo "$response" | tail -n1)
|
|||
|
|
|
|||
|
|
if [[ "$http_code" == "200" ]]; then
|
|||
|
|
print_pass "API is reachable (HTTP 200)"
|
|||
|
|
else
|
|||
|
|
print_fail "API is not reachable (HTTP ${http_code})"
|
|||
|
|
fi
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
test_public_config() {
|
|||
|
|
print_test "Get Public Config"
|
|||
|
|
|
|||
|
|
local response
|
|||
|
|
response=$(get_public_config "${TEST_POSTGREST_URL}" 2>/dev/null || echo "")
|
|||
|
|
|
|||
|
|
if [[ -n "$response" ]]; then
|
|||
|
|
# Check if response contains expected fields
|
|||
|
|
if echo "$response" | grep -q "registration_webhook_url"; then
|
|||
|
|
print_pass "Public config retrieved successfully"
|
|||
|
|
print_info "Response: ${response}"
|
|||
|
|
else
|
|||
|
|
print_fail "Public config missing expected fields"
|
|||
|
|
fi
|
|||
|
|
else
|
|||
|
|
print_fail "Failed to retrieve public config"
|
|||
|
|
fi
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
test_get_instance_by_email() {
|
|||
|
|
print_test "Get Instance Config by Email"
|
|||
|
|
|
|||
|
|
local response
|
|||
|
|
response=$(get_installer_json_by_email "${TEST_EMAIL}" "${TEST_POSTGREST_URL}" 2>/dev/null || echo "")
|
|||
|
|
|
|||
|
|
if [[ -n "$response" && "$response" != "[]" ]]; then
|
|||
|
|
# Check if response contains expected fields
|
|||
|
|
if echo "$response" | grep -q "ctid"; then
|
|||
|
|
print_pass "Instance config retrieved by email"
|
|||
|
|
|
|||
|
|
# Verify no secrets are exposed
|
|||
|
|
if echo "$response" | grep -qE "password|service_role_key|jwt_secret|encryption_key"; then
|
|||
|
|
print_fail "Response contains secrets (SECURITY ISSUE!)"
|
|||
|
|
else
|
|||
|
|
print_pass "No secrets exposed in response"
|
|||
|
|
fi
|
|||
|
|
|
|||
|
|
# Print sample of response
|
|||
|
|
local ctid
|
|||
|
|
ctid=$(echo "$response" | python3 -c "import json,sys; d=json.load(sys.stdin); print(d[0]['ctid'] if d else 'N/A')" 2>/dev/null || echo "N/A")
|
|||
|
|
print_info "Found CTID: ${ctid}"
|
|||
|
|
else
|
|||
|
|
print_fail "Instance config missing expected fields"
|
|||
|
|
fi
|
|||
|
|
else
|
|||
|
|
print_skip "No instance found for email: ${TEST_EMAIL} (this is OK if instance doesn't exist)"
|
|||
|
|
fi
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
test_get_instance_by_ctid() {
|
|||
|
|
print_test "Get Instance Config by CTID (requires service role key)"
|
|||
|
|
|
|||
|
|
if [[ -z "$TEST_SERVICE_ROLE_KEY" ]]; then
|
|||
|
|
print_skip "Service role key not provided (use --service-role-key)"
|
|||
|
|
return
|
|||
|
|
fi
|
|||
|
|
|
|||
|
|
local response
|
|||
|
|
response=$(get_installer_json_by_ctid "${TEST_CTID}" "${TEST_POSTGREST_URL}" "${TEST_SERVICE_ROLE_KEY}" 2>/dev/null || echo "")
|
|||
|
|
|
|||
|
|
if [[ -n "$response" && "$response" != "[]" ]]; then
|
|||
|
|
# Check if response contains expected fields
|
|||
|
|
if echo "$response" | grep -q "ctid"; then
|
|||
|
|
print_pass "Instance config retrieved by CTID"
|
|||
|
|
|
|||
|
|
# Verify no secrets are exposed
|
|||
|
|
if echo "$response" | grep -qE "password|service_role_key|jwt_secret|encryption_key"; then
|
|||
|
|
print_fail "Response contains secrets (SECURITY ISSUE!)"
|
|||
|
|
else
|
|||
|
|
print_pass "No secrets exposed in response"
|
|||
|
|
fi
|
|||
|
|
else
|
|||
|
|
print_fail "Instance config missing expected fields"
|
|||
|
|
fi
|
|||
|
|
else
|
|||
|
|
print_skip "No instance found for CTID: ${TEST_CTID} (this is OK if instance doesn't exist)"
|
|||
|
|
fi
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
test_store_installer_json() {
|
|||
|
|
print_test "Store Installer JSON (requires service role key)"
|
|||
|
|
|
|||
|
|
if [[ -z "$TEST_SERVICE_ROLE_KEY" ]]; then
|
|||
|
|
print_skip "Service role key not provided (use --service-role-key)"
|
|||
|
|
return
|
|||
|
|
fi
|
|||
|
|
|
|||
|
|
# Create test JSON
|
|||
|
|
local test_json
|
|||
|
|
test_json=$(cat <<EOF
|
|||
|
|
{
|
|||
|
|
"ctid": ${TEST_CTID},
|
|||
|
|
"hostname": "sb-${TEST_CTID}",
|
|||
|
|
"fqdn": "sb-${TEST_CTID}.userman.de",
|
|||
|
|
"ip": "192.168.45.104",
|
|||
|
|
"vlan": 90,
|
|||
|
|
"urls": {
|
|||
|
|
"n8n_internal": "http://192.168.45.104:5678/",
|
|||
|
|
"n8n_external": "https://sb-${TEST_CTID}.userman.de",
|
|||
|
|
"postgrest": "http://192.168.45.104:3000",
|
|||
|
|
"chat_webhook": "https://sb-${TEST_CTID}.userman.de/webhook/rag-chat-webhook/chat",
|
|||
|
|
"chat_internal": "http://192.168.45.104:5678/webhook/rag-chat-webhook/chat",
|
|||
|
|
"upload_form": "https://sb-${TEST_CTID}.userman.de/form/rag-upload-form",
|
|||
|
|
"upload_form_internal": "http://192.168.45.104:5678/form/rag-upload-form"
|
|||
|
|
},
|
|||
|
|
"postgres": {
|
|||
|
|
"host": "postgres",
|
|||
|
|
"port": 5432,
|
|||
|
|
"db": "customer",
|
|||
|
|
"user": "customer",
|
|||
|
|
"password": "TEST_PASSWORD_SHOULD_NOT_BE_EXPOSED"
|
|||
|
|
},
|
|||
|
|
"supabase": {
|
|||
|
|
"url": "http://postgrest:3000",
|
|||
|
|
"url_external": "http://192.168.45.104:3000",
|
|||
|
|
"anon_key": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.TEST",
|
|||
|
|
"service_role_key": "TEST_SERVICE_ROLE_KEY_SHOULD_NOT_BE_EXPOSED",
|
|||
|
|
"jwt_secret": "TEST_JWT_SECRET_SHOULD_NOT_BE_EXPOSED"
|
|||
|
|
},
|
|||
|
|
"ollama": {
|
|||
|
|
"url": "http://192.168.45.3:11434",
|
|||
|
|
"model": "ministral-3:3b",
|
|||
|
|
"embedding_model": "nomic-embed-text:latest"
|
|||
|
|
},
|
|||
|
|
"n8n": {
|
|||
|
|
"encryption_key": "TEST_ENCRYPTION_KEY_SHOULD_NOT_BE_EXPOSED",
|
|||
|
|
"owner_email": "admin@userman.de",
|
|||
|
|
"owner_password": "TEST_PASSWORD_SHOULD_NOT_BE_EXPOSED",
|
|||
|
|
"secure_cookie": false
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
EOF
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
# Try to store
|
|||
|
|
if store_installer_json_in_db "${TEST_CTID}" "${TEST_EMAIL}" "${TEST_POSTGREST_URL}" "${TEST_SERVICE_ROLE_KEY}" "${test_json}"; then
|
|||
|
|
print_pass "Installer JSON stored successfully"
|
|||
|
|
|
|||
|
|
# Verify it was stored
|
|||
|
|
sleep 1
|
|||
|
|
local response
|
|||
|
|
response=$(get_installer_json_by_email "${TEST_EMAIL}" "${TEST_POSTGREST_URL}" 2>/dev/null || echo "")
|
|||
|
|
|
|||
|
|
if [[ -n "$response" && "$response" != "[]" ]]; then
|
|||
|
|
print_pass "Stored data can be retrieved"
|
|||
|
|
|
|||
|
|
# Verify secrets are NOT in the response
|
|||
|
|
if echo "$response" | grep -q "TEST_PASSWORD_SHOULD_NOT_BE_EXPOSED"; then
|
|||
|
|
print_fail "CRITICAL: Passwords are exposed in API response!"
|
|||
|
|
elif echo "$response" | grep -q "TEST_SERVICE_ROLE_KEY_SHOULD_NOT_BE_EXPOSED"; then
|
|||
|
|
print_fail "CRITICAL: Service role key is exposed in API response!"
|
|||
|
|
elif echo "$response" | grep -q "TEST_JWT_SECRET_SHOULD_NOT_BE_EXPOSED"; then
|
|||
|
|
print_fail "CRITICAL: JWT secret is exposed in API response!"
|
|||
|
|
elif echo "$response" | grep -q "TEST_ENCRYPTION_KEY_SHOULD_NOT_BE_EXPOSED"; then
|
|||
|
|
print_fail "CRITICAL: Encryption key is exposed in API response!"
|
|||
|
|
else
|
|||
|
|
print_pass "SECURITY: All secrets are properly filtered"
|
|||
|
|
fi
|
|||
|
|
else
|
|||
|
|
print_fail "Stored data could not be retrieved"
|
|||
|
|
fi
|
|||
|
|
else
|
|||
|
|
print_skip "Failed to store installer JSON (instance may not exist in database)"
|
|||
|
|
fi
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
test_cors_headers() {
|
|||
|
|
print_test "CORS Headers"
|
|||
|
|
|
|||
|
|
local response
|
|||
|
|
response=$(curl -sS -I -X OPTIONS "${TEST_POSTGREST_URL}/rpc/get_public_config" \
|
|||
|
|
-H "Origin: https://botkonzept.de" \
|
|||
|
|
-H "Access-Control-Request-Method: POST" 2>&1 || echo "")
|
|||
|
|
|
|||
|
|
if echo "$response" | grep -qi "access-control-allow-origin"; then
|
|||
|
|
print_pass "CORS headers are present"
|
|||
|
|
else
|
|||
|
|
print_skip "CORS headers not found (may need configuration)"
|
|||
|
|
fi
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
test_rate_limiting() {
|
|||
|
|
print_test "Rate Limiting (optional)"
|
|||
|
|
|
|||
|
|
print_skip "Rate limiting test not implemented (should be configured at nginx/gateway level)"
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
test_response_format() {
|
|||
|
|
print_test "Response Format Validation"
|
|||
|
|
|
|||
|
|
local response
|
|||
|
|
response=$(get_public_config "${TEST_POSTGREST_URL}" 2>/dev/null || echo "")
|
|||
|
|
|
|||
|
|
if [[ -n "$response" ]]; then
|
|||
|
|
# Validate JSON format
|
|||
|
|
if echo "$response" | python3 -m json.tool >/dev/null 2>&1; then
|
|||
|
|
print_pass "Response is valid JSON"
|
|||
|
|
else
|
|||
|
|
print_fail "Response is not valid JSON"
|
|||
|
|
fi
|
|||
|
|
else
|
|||
|
|
print_fail "No response received"
|
|||
|
|
fi
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
# Main test execution
|
|||
|
|
main() {
|
|||
|
|
print_header "BotKonzept Installer JSON API Tests"
|
|||
|
|
|
|||
|
|
echo "Test Configuration:"
|
|||
|
|
echo " CTID: ${TEST_CTID}"
|
|||
|
|
echo " Email: ${TEST_EMAIL}"
|
|||
|
|
echo " PostgREST URL: ${TEST_POSTGREST_URL}"
|
|||
|
|
echo " Service Role Key: ${TEST_SERVICE_ROLE_KEY:+***provided***}"
|
|||
|
|
echo ""
|
|||
|
|
|
|||
|
|
# Run tests
|
|||
|
|
test_api_connectivity
|
|||
|
|
test_public_config
|
|||
|
|
test_response_format
|
|||
|
|
test_cors_headers
|
|||
|
|
test_get_instance_by_email
|
|||
|
|
test_get_instance_by_ctid
|
|||
|
|
test_store_installer_json
|
|||
|
|
test_rate_limiting
|
|||
|
|
|
|||
|
|
# Print summary
|
|||
|
|
print_header "Test Summary"
|
|||
|
|
|
|||
|
|
echo "Total Tests: ${TESTS_TOTAL}"
|
|||
|
|
echo -e "${GREEN}Passed: ${TESTS_PASSED}${NC}"
|
|||
|
|
echo -e "${RED}Failed: ${TESTS_FAILED}${NC}"
|
|||
|
|
echo ""
|
|||
|
|
|
|||
|
|
if [[ $TESTS_FAILED -eq 0 ]]; then
|
|||
|
|
echo -e "${GREEN}✓ All tests passed!${NC}"
|
|||
|
|
exit 0
|
|||
|
|
else
|
|||
|
|
echo -e "${RED}✗ Some tests failed${NC}"
|
|||
|
|
exit 1
|
|||
|
|
fi
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
# Run main
|
|||
|
|
main
|