From d1675a1f2b6058cbeefa534a659180a23c1893ce Mon Sep 17 00:00:00 2001 From: Pulse Monitor Date: Tue, 9 Sep 2025 07:07:10 +0000 Subject: [PATCH] chore: remove remaining test files and scripts from repository --- frontend-modern/public/debug.html | 56 ------ frontend-modern/public/test.html | 39 ---- scripts/test-all.sh | 119 ------------ scripts/test-edge-cases.sh | 138 ------------- scripts/test-installation-methods.sh | 200 ------------------- scripts/test-proxy-scenarios.sh | 176 ----------------- scripts/test-release.sh | 281 --------------------------- scripts/test-security.sh | 268 ------------------------- 8 files changed, 1277 deletions(-) delete mode 100644 frontend-modern/public/debug.html delete mode 100644 frontend-modern/public/test.html delete mode 100755 scripts/test-all.sh delete mode 100755 scripts/test-edge-cases.sh delete mode 100755 scripts/test-installation-methods.sh delete mode 100755 scripts/test-proxy-scenarios.sh delete mode 100755 scripts/test-release.sh delete mode 100755 scripts/test-security.sh diff --git a/frontend-modern/public/debug.html b/frontend-modern/public/debug.html deleted file mode 100644 index a67a15f97..000000000 --- a/frontend-modern/public/debug.html +++ /dev/null @@ -1,56 +0,0 @@ - - - - - Debug Pulse - - -

Debug Page

-
Initial content - if you see this, JavaScript didn't run
- -
-

Log:

-
- - - - \ No newline at end of file diff --git a/frontend-modern/public/test.html b/frontend-modern/public/test.html deleted file mode 100644 index b2bdf5487..000000000 --- a/frontend-modern/public/test.html +++ /dev/null @@ -1,39 +0,0 @@ - - - - Test App Loading - - -

Testing App Loading

-
- - - \ No newline at end of file diff --git a/scripts/test-all.sh b/scripts/test-all.sh deleted file mode 100755 index 9e6c967d1..000000000 --- a/scripts/test-all.sh +++ /dev/null @@ -1,119 +0,0 @@ -#!/bin/bash - -# Master test script that runs all test suites -# Run this before any release! - -set -e - -VERSION=${1:-$(cat VERSION)} -API_TOKEN=${2:-""} -PULSE_URL=${3:-"http://localhost:7655"} - -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -BLUE='\033[0;34m' -NC='\033[0m' - -echo "================================================" -echo -e "${BLUE}PULSE COMPREHENSIVE TEST SUITE v${VERSION}${NC}" -echo "================================================" -echo "" - -TOTAL_PASSED=0 -TOTAL_FAILED=0 -FAILED_SUITES=() - -run_test_suite() { - local suite_name="$1" - local script_path="$2" - shift 2 - local args="$@" - - echo -e "${YELLOW}Running: $suite_name${NC}" - echo "----------------------------------------" - - if [ -f "$script_path" ]; then - if timeout 60 $script_path $args 2>&1 | tee /tmp/test_output.txt | grep -E "✓|✗|passed|failed|PASS|FAIL"; then - # Extract pass/fail counts if possible - if grep -q "All tests passed" /tmp/test_output.txt; then - echo -e "${GREEN}✅ $suite_name: PASSED${NC}" - ((TOTAL_PASSED++)) - elif grep -q "FAILED\|Failed" /tmp/test_output.txt; then - echo -e "${RED}❌ $suite_name: FAILED${NC}" - ((TOTAL_FAILED++)) - FAILED_SUITES+=("$suite_name") - else - echo -e "${YELLOW}⚠️ $suite_name: COMPLETED (check output)${NC}" - fi - else - echo -e "${RED}❌ $suite_name: ERROR or TIMEOUT${NC}" - ((TOTAL_FAILED++)) - FAILED_SUITES+=("$suite_name") - fi - else - echo -e "${YELLOW}⚠️ $suite_name: Script not found${NC}" - fi - echo "" -} - -# Change to Pulse directory -cd /opt/pulse - -echo -e "${BLUE}Starting comprehensive test suite...${NC}" -echo "" - -# 1. Main release tests -if [ -n "$API_TOKEN" ]; then - export API_TOKEN -fi -run_test_suite "Release Tests" "./scripts/test-release.sh" - -# 2. Edge case tests -run_test_suite "Edge Case Tests" "./scripts/test-edge-cases.sh" "$PULSE_URL" - -# 3. Proxy scenario tests -run_test_suite "Proxy Scenarios" "./scripts/test-proxy-scenarios.sh" "$PULSE_URL" "$API_TOKEN" - -# 4. Security tests -run_test_suite "Security Tests" "./scripts/test-security.sh" "$PULSE_URL" "$API_TOKEN" - -# 5. Installation method tests (non-destructive) -run_test_suite "Installation Tests" "./scripts/test-installation-methods.sh" "$VERSION" - -echo "================================================" -echo -e "${BLUE}TEST SUITE SUMMARY${NC}" -echo "================================================" -echo "" -echo -e "Test Suites Passed: ${GREEN}$TOTAL_PASSED${NC}" -echo -e "Test Suites Failed: ${RED}$TOTAL_FAILED${NC}" - -if [ ${#FAILED_SUITES[@]} -gt 0 ]; then - echo "" - echo -e "${RED}Failed test suites:${NC}" - for suite in "${FAILED_SUITES[@]}"; do - echo " - $suite" - done - echo "" - echo -e "${RED}⚠️ DO NOT RELEASE - Tests failed!${NC}" - echo "" - echo "Run individual test suites for details:" - echo " ./scripts/test-release.sh" - echo " ./scripts/test-edge-cases.sh" - echo " ./scripts/test-proxy-scenarios.sh" - echo " ./scripts/test-security.sh" - echo " ./scripts/test-installation-methods.sh" - exit 1 -else - echo "" - echo -e "${GREEN}✅ ALL TEST SUITES PASSED!${NC}" - echo -e "${GREEN}Safe to proceed with release v${VERSION}${NC}" -fi - -echo "" -echo "Additional manual testing recommended:" -echo " 1. Test actual ProxmoxVE LXC installation" -echo " 2. Test Docker deployment on different architectures" -echo " 3. Test behind real nginx/Cloudflare" -echo " 4. Test upgrade from previous version" -echo " 5. Load test with many concurrent users" \ No newline at end of file diff --git a/scripts/test-edge-cases.sh b/scripts/test-edge-cases.sh deleted file mode 100755 index 8830dbae8..000000000 --- a/scripts/test-edge-cases.sh +++ /dev/null @@ -1,138 +0,0 @@ -#!/bin/bash - -# Edge case testing for Pulse -# Tests the weird stuff that breaks in production - -set -e - -PULSE_URL=${1:-http://localhost:7655} - -echo "================================================" -echo "EDGE CASE TESTING" -echo "================================================" - -echo "" -echo "Testing URL variations that break reverse proxies..." -echo "----------------------------------------------------" - -# Test all the ways users might access Pulse -URLS=( - "$PULSE_URL" # No trailing slash - "$PULSE_URL/" # With trailing slash - "$PULSE_URL//" # Double slash (happens with bad proxy configs) - "$PULSE_URL/./" # Relative path (should not happen!) - "$PULSE_URL/index.html" # Direct file access -) - -for url in "${URLS[@]}"; do - echo -n "Testing: $url ... " - STATUS=$(curl -s -o /dev/null -w "%{http_code}" -I "$url" 2>/dev/null || echo "FAIL") - LOCATION=$(curl -s -I "$url" 2>/dev/null | grep -i "^location:" | cut -d' ' -f2 | tr -d '\r\n' || echo "none") - - if [[ "$STATUS" == "200" ]]; then - echo "✓ 200 OK" - elif [[ "$STATUS" == "301" ]] || [[ "$STATUS" == "302" ]]; then - echo "⚠️ Redirect to: $LOCATION" - if [[ "$LOCATION" == "./" ]] || [[ "$LOCATION" == "../" ]]; then - echo " ❌ RELATIVE REDIRECT DETECTED - THIS BREAKS PROXIES!" - fi - else - echo "❌ Status: $STATUS" - fi -done - -echo "" -echo "Testing problematic header combinations..." -echo "----------------------------------------------------" - -# Headers that various proxies send -HEADER_TESTS=( - "-H 'Host: example.com'" # Different host - "-H 'X-Forwarded-Host: proxy.local' -H 'X-Forwarded-Proto: https'" # Proxy headers - "-H 'X-Real-IP: 10.0.0.1' -H 'X-Forwarded-For: 10.0.0.1'" # Multiple IPs - "-H 'CF-Connecting-IP: 1.2.3.4'" # Cloudflare - "-H 'X-Forwarded-Prefix: /pulse'" # Subpath proxy -) - -for headers in "${HEADER_TESTS[@]}"; do - echo -n "Testing with: $headers ... " - if eval "curl -s $headers '$PULSE_URL' | grep -q 'Pulse'" 2>/dev/null; then - echo "✓" - else - echo "❌ Failed" - fi -done - -echo "" -echo "Testing authentication edge cases..." -echo "----------------------------------------------------" - -# Test various auth header formats -echo -n "Empty API token header: " -curl -s -H "X-API-Token: " "$PULSE_URL/api/health" | grep -q "healthy" && echo "✓" || echo "❌" - -echo -n "Malformed API token: " -RESPONSE=$(curl -s -o /dev/null -w "%{http_code}" -H "X-API-Token: notavalidtoken" "$PULSE_URL/api/state") -[[ "$RESPONSE" == "401" ]] && echo "✓ Properly rejected" || echo "❌ Status: $RESPONSE" - -echo -n "SQL injection in API token: " -RESPONSE=$(curl -s -o /dev/null -w "%{http_code}" -H "X-API-Token: ' OR '1'='1" "$PULSE_URL/api/state") -[[ "$RESPONSE" == "401" ]] && echo "✓ Properly rejected" || echo "❌ Status: $RESPONSE" - -echo "" -echo "Testing concurrent connections..." -echo "----------------------------------------------------" - -echo "Sending 50 concurrent requests..." -for i in {1..50}; do - curl -s "$PULSE_URL/api/health" > /dev/null & -done -wait -echo "✓ Handled concurrent load" - -echo "" -echo "Testing large request handling..." -echo "----------------------------------------------------" - -# Test with large headers -echo -n "Large header (10KB): " -LARGE_HEADER=$(head -c 10000 /dev/zero | tr '\0' 'A') -RESPONSE=$(curl -s -o /dev/null -w "%{http_code}" -H "X-Large: $LARGE_HEADER" "$PULSE_URL/api/health" 2>/dev/null || echo "FAIL") -[[ "$RESPONSE" == "200" ]] && echo "✓" || echo "❌ Status: $RESPONSE" - -echo "" -echo "Testing special characters in URLs..." -echo "----------------------------------------------------" - -SPECIAL_PATHS=( - "/api/health?test=" # XSS attempt - "/api/health?test=';DROP TABLE--" # SQL injection - "/api/../../../etc/passwd" # Path traversal - "/api/health%00.json" # Null byte - "/api/health?test=%" # Invalid encoding -) - -for path in "${SPECIAL_PATHS[@]}"; do - echo -n "Testing: $path ... " - RESPONSE=$(curl -s -o /dev/null -w "%{http_code}" "$PULSE_URL$path" 2>/dev/null || echo "FAIL") - if [[ "$RESPONSE" == "200" ]] || [[ "$RESPONSE" == "400" ]] || [[ "$RESPONSE" == "404" ]]; then - echo "✓ Handled safely ($RESPONSE)" - else - echo "❌ Unexpected: $RESPONSE" - fi -done - -echo "" -echo "Testing WebSocket edge cases..." -echo "----------------------------------------------------" - -echo -n "WebSocket with wrong protocol: " -curl -s -I -H "Upgrade: wrong" "$PULSE_URL/ws" | grep -q "HTTP/1.1" && echo "✓" || echo "❌" - -echo -n "WebSocket with auth token: " -curl -s -I -H "Upgrade: websocket" -H "X-API-Token: test" "$PULSE_URL/ws" | grep -q "HTTP/1.1" && echo "✓" || echo "❌" - -echo "" -echo "================================================" -echo "EDGE CASE TESTING COMPLETE" -echo "================================================" \ No newline at end of file diff --git a/scripts/test-installation-methods.sh b/scripts/test-installation-methods.sh deleted file mode 100755 index dfe43fd53..000000000 --- a/scripts/test-installation-methods.sh +++ /dev/null @@ -1,200 +0,0 @@ -#!/bin/bash - -# Test different installation methods -# Catches issues with install script, Docker, systemd, etc. - -set -e - -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -NC='\033[0m' - -echo "================================================" -echo "INSTALLATION METHOD TESTING" -echo "================================================" - -VERSION=${1:-$(cat VERSION)} - -echo "" -echo "1. INSTALL SCRIPT VALIDATION" -echo "============================" - -echo -n "Install script exists on GitHub: " -if curl -s -f https://raw.githubusercontent.com/rcourtman/Pulse/main/install.sh > /dev/null; then - echo -e "${GREEN}✓${NC}" -else - echo -e "${RED}✗${NC}" -fi - -echo -n "Install script is executable: " -SCRIPT=$(curl -s https://raw.githubusercontent.com/rcourtman/Pulse/main/install.sh) -if echo "$SCRIPT" | head -1 | grep -q "^#!/bin/bash"; then - echo -e "${GREEN}✓${NC}" -else - echo -e "${RED}✗${NC}" -fi - -echo -n "Install script has version detection: " -if echo "$SCRIPT" | grep -q "VERSION="; then - echo -e "${GREEN}✓${NC}" -else - echo -e "${RED}✗${NC}" -fi - -echo "" -echo "2. GITHUB RELEASE ARTIFACTS" -echo "===========================" - -ARTIFACTS=( - "pulse-v${VERSION}-linux-amd64.tar.gz" - "pulse-v${VERSION}-linux-arm64.tar.gz" - "pulse-v${VERSION}-linux-armv7.tar.gz" - "pulse-v${VERSION}.tar.gz" - "checksums.txt" -) - -for artifact in "${ARTIFACTS[@]}"; do - echo -n "Checking $artifact: " - URL="https://github.com/rcourtman/Pulse/releases/download/v${VERSION}/${artifact}" - if curl -s -f -I "$URL" > /dev/null 2>&1; then - echo -e "${GREEN}✓${NC}" - else - echo -e "${YELLOW}Not yet uploaded${NC}" - fi -done - -echo "" -echo "3. DOCKER IMAGE AVAILABILITY" -echo "============================" - -echo -n "Docker Hub image exists: " -if curl -s "https://hub.docker.com/v2/repositories/rcourtman/pulse/tags/v${VERSION}" | grep -q "v${VERSION}"; then - echo -e "${GREEN}✓${NC}" -else - echo -e "${YELLOW}Not yet pushed${NC}" -fi - -echo "" -echo "4. SYSTEMD SERVICE FILE" -echo "=======================" - -echo -n "Service file exists locally: " -if [ -f /etc/systemd/system/pulse.service ] || [ -f /etc/systemd/system/pulse-backend.service ]; then - echo -e "${GREEN}✓${NC}" - - # Check service file contents - SERVICE_FILE=$(ls /etc/systemd/system/pulse*.service 2>/dev/null | head -1) - - echo -n "Service has Restart=always: " - if grep -q "Restart=always" "$SERVICE_FILE"; then - echo -e "${GREEN}✓${NC}" - else - echo -e "${RED}✗${NC}" - fi - - echo -n "Service runs as pulse user: " - if grep -q "User=pulse" "$SERVICE_FILE"; then - echo -e "${GREEN}✓${NC}" - else - echo -e "${YELLOW}⚠️ Running as different user${NC}" - fi -else - echo -e "${YELLOW}Not installed via systemd${NC}" -fi - -echo "" -echo "5. BINARY COMPATIBILITY TESTS" -echo "=============================" - -echo -n "Current binary runs: " -if /opt/pulse/pulse help > /dev/null 2>&1; then - echo -e "${GREEN}✓${NC}" -else - echo -e "${RED}✗${NC}" -fi - -echo -n "Binary has embedded frontend: " -if strings /opt/pulse/pulse 2>/dev/null | grep -q ""; then - echo -e "${GREEN}✓${NC}" -else - echo -e "${RED}✗ Frontend not embedded!${NC}" -fi - -echo "" -echo "6. CONFIGURATION VALIDATION" -echo "===========================" - -echo -n "Config directory exists: " -if [ -d /etc/pulse ]; then - echo -e "${GREEN}✓${NC}" - - echo -n ".env file exists: " - if [ -f /etc/pulse/.env ]; then - echo -e "${GREEN}✓${NC}" - else - echo -e "${YELLOW}Using defaults${NC}" - fi - - echo -n "nodes.json exists: " - if [ -f /etc/pulse/nodes.json ]; then - echo -e "${GREEN}✓${NC}" - else - echo -e "${YELLOW}No nodes configured${NC}" - fi -else - echo -e "${RED}✗${NC}" -fi - -echo "" -echo "7. PERMISSION CHECKS" -echo "===================" - -echo -n "Pulse user exists: " -if id pulse > /dev/null 2>&1; then - echo -e "${GREEN}✓${NC}" - - echo -n "Config owned by pulse user: " - if [ -d /etc/pulse ] && [ "$(stat -c %U /etc/pulse)" = "pulse" ]; then - echo -e "${GREEN}✓${NC}" - else - echo -e "${YELLOW}⚠️ Ownership issue${NC}" - fi -else - echo -e "${YELLOW}Running as different user${NC}" -fi - -echo "" -echo "8. PORT AVAILABILITY" -echo "===================" - -echo -n "Port 7655 is listening: " -if netstat -tln 2>/dev/null | grep -q :7655 || ss -tln 2>/dev/null | grep -q :7655; then - echo -e "${GREEN}✓${NC}" -else - echo -e "${RED}✗ Not listening${NC}" -fi - -echo "" -echo "9. UPDATE MECHANISM" -echo "==================" - -echo -n "Can detect current version: " -CURRENT=$(curl -s http://localhost:7655/api/version 2>/dev/null | jq -r .version 2>/dev/null) -if [ -n "$CURRENT" ]; then - echo -e "${GREEN}✓ ($CURRENT)${NC}" -else - echo -e "${RED}✗${NC}" -fi - -echo -n "Can check for updates: " -if curl -s http://localhost:7655/api/updates/check 2>/dev/null | grep -q "currentVersion"; then - echo -e "${GREEN}✓${NC}" -else - echo -e "${YELLOW}Requires auth${NC}" -fi - -echo "" -echo "================================================" -echo "Installation tests complete" -echo "================================================" \ No newline at end of file diff --git a/scripts/test-proxy-scenarios.sh b/scripts/test-proxy-scenarios.sh deleted file mode 100755 index 9907e62ea..000000000 --- a/scripts/test-proxy-scenarios.sh +++ /dev/null @@ -1,176 +0,0 @@ -#!/bin/bash - -# Test script for reverse proxy scenarios -# These are the cases that often break in production - -set -e - -PULSE_URL=${1:-http://localhost:7655} -API_TOKEN=${2:-""} - -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -NC='\033[0m' - -echo "================================================" -echo "REVERSE PROXY SCENARIO TESTING" -echo "================================================" - -FAILED=0 -PASSED=0 - -test_scenario() { - local test_name="$1" - local command="$2" - - echo -n "$test_name: " - if eval "$command" > /dev/null 2>&1; then - echo -e "${GREEN}✓${NC}" - ((PASSED++)) || true - else - echo -e "${RED}✗${NC}" - ((FAILED++)) || true - fi -} - -echo "" -echo "1. NGINX-STYLE PROXY HEADERS" -echo "============================" - -test_scenario "X-Real-IP header" \ - "curl -s -H 'X-Real-IP: 192.168.1.100' $PULSE_URL/api/health | grep -q healthy" - -test_scenario "X-Forwarded-For with multiple IPs" \ - "curl -s -H 'X-Forwarded-For: 203.0.113.0, 198.51.100.0, 172.16.0.1' $PULSE_URL/api/health | grep -q healthy" - -test_scenario "X-Forwarded-Proto https" \ - "curl -s -H 'X-Forwarded-Proto: https' $PULSE_URL/api/health | grep -q healthy" - -test_scenario "X-Forwarded-Host" \ - "curl -s -H 'X-Forwarded-Host: pulse.example.com' $PULSE_URL/api/health | grep -q healthy" - -test_scenario "X-Forwarded-Port" \ - "curl -s -H 'X-Forwarded-Port: 443' $PULSE_URL/api/health | grep -q healthy" - -echo "" -echo "2. CLOUDFLARE TUNNEL HEADERS" -echo "=============================" - -test_scenario "CF-Connecting-IP" \ - "curl -s -H 'CF-Connecting-IP: 198.51.100.42' $PULSE_URL/api/health | grep -q healthy" - -test_scenario "CF-IPCountry" \ - "curl -s -H 'CF-IPCountry: US' $PULSE_URL/api/health | grep -q healthy" - -test_scenario "CF-Ray (request ID)" \ - "curl -s -H 'CF-Ray: 8a9b7c6d5e4f3a2b1' $PULSE_URL/api/health | grep -q healthy" - -test_scenario "CF-Visitor (scheme)" \ - "curl -s -H 'CF-Visitor: {\"scheme\":\"https\"}' $PULSE_URL/api/health | grep -q healthy" - -echo "" -echo "3. TRAEFIK HEADERS" -echo "==================" - -test_scenario "X-Forwarded-Prefix (subpath)" \ - "curl -s -H 'X-Forwarded-Prefix: /apps/pulse' $PULSE_URL/api/health | grep -q healthy" - -test_scenario "X-Forwarded-Method override" \ - "curl -s -H 'X-Forwarded-Method: POST' $PULSE_URL/api/health | grep -q healthy" - -echo "" -echo "4. PATH VARIATIONS (CRITICAL FOR #334)" -echo "=======================================" - -# These are the exact scenarios that broke with issue #334 -test_scenario "Root without slash - no redirect" \ - "! curl -s -I $PULSE_URL | grep -q 'Location: ./'" - -test_scenario "Root with slash - no redirect" \ - "! curl -s -I $PULSE_URL/ | grep -q 'Location: ./'" - -test_scenario "Root without slash - 200 OK" \ - "curl -s -o /dev/null -w '%{http_code}' $PULSE_URL | grep -q 200" - -test_scenario "Root with slash - 200 OK" \ - "curl -s -o /dev/null -w '%{http_code}' $PULSE_URL/ | grep -q 200" - -# Test that we don't get relative redirects for any common paths -PATHS=("" "/" "/api" "/api/" "/settings" "/login" "/dashboard") -for path in "${PATHS[@]}"; do - test_scenario "No relative redirect for '$path'" \ - "! curl -s -I '$PULSE_URL$path' 2>/dev/null | grep -i 'location:' | grep -q '^\\.'" -done - -echo "" -echo "5. WEBSOCKET THROUGH PROXY" -echo "===========================" - -test_scenario "WebSocket with proxy headers" \ - "curl -s -I -H 'Upgrade: websocket' -H 'X-Forwarded-For: 10.0.0.1' $PULSE_URL/ws | grep -q 'HTTP/1.1'" - -test_scenario "WebSocket with wrong origin" \ - "curl -s -I -H 'Upgrade: websocket' -H 'Origin: http://evil.com' $PULSE_URL/ws | grep -q 'HTTP/1.1'" - -echo "" -echo "6. AUTHENTICATION WITH PROXY" -echo "=============================" - -if [ -n "$API_TOKEN" ]; then - test_scenario "API token through proxy headers" \ - "curl -s -H 'X-API-Token: $API_TOKEN' -H 'X-Forwarded-For: 10.0.0.1' $PULSE_URL/api/state | grep -q nodes" - - test_scenario "API token with Cloudflare headers" \ - "curl -s -H 'X-API-Token: $API_TOKEN' -H 'CF-Connecting-IP: 1.2.3.4' $PULSE_URL/api/state | grep -q nodes" -else - echo -e "${YELLOW}Skipping auth tests (no API_TOKEN)${NC}" -fi - -echo "" -echo "7. COOKIE HANDLING THROUGH PROXY" -echo "=================================" - -# Test that cookies work correctly with proxy headers (important for auth) -test_scenario "Set-Cookie with secure flag for https proxy" \ - "curl -s -I -H 'X-Forwarded-Proto: https' $PULSE_URL | grep -i 'set-cookie' || true" - -echo "" -echo "8. CONTENT-TYPE PRESERVATION" -echo "=============================" - -test_scenario "JSON content-type preserved" \ - "curl -s -I $PULSE_URL/api/version | grep -q 'Content-Type: application/json'" - -test_scenario "HTML content-type for UI" \ - "curl -s -I $PULSE_URL/ | grep -q 'Content-Type: text/html'" - -echo "" -echo "9. SUBPATH DEPLOYMENT" -echo "=====================" - -# Test if Pulse could work behind a subpath (like /monitoring/pulse/) -test_scenario "API works with referer containing subpath" \ - "curl -s -H 'Referer: https://example.com/monitoring/pulse/' $PULSE_URL/api/health | grep -q healthy" - -echo "" -echo "10. COMPRESSION HANDLING" -echo "========================" - -test_scenario "Accepts gzip encoding" \ - "curl -s -H 'Accept-Encoding: gzip' -I $PULSE_URL/ | grep -i 'content-encoding' || true" - -test_scenario "Handles deflate encoding request" \ - "curl -s -H 'Accept-Encoding: deflate' $PULSE_URL/api/health | grep -q healthy" - -echo "" -echo "================================================" -echo "RESULTS: Passed: $PASSED | Failed: $FAILED" -echo "================================================" - -if [ $FAILED -gt 0 ]; then - echo -e "${RED}⚠️ Some proxy scenarios failed!${NC}" - exit 1 -else - echo -e "${GREEN}✅ All proxy scenarios handled correctly${NC}" -fi \ No newline at end of file diff --git a/scripts/test-release.sh b/scripts/test-release.sh deleted file mode 100755 index e65103052..000000000 --- a/scripts/test-release.sh +++ /dev/null @@ -1,281 +0,0 @@ -#!/bin/bash - -# Comprehensive release testing script for Pulse -# Tests actual deployments, not just unit tests - -set -e - -VERSION=${1:-$(cat VERSION)} -PULSE_URL=${PULSE_URL:-http://localhost:7655} -API_TOKEN=${API_TOKEN:-""} - -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -NC='\033[0m' - -echo "================================================" -echo "Pulse Release Test Suite v${VERSION}" -echo "================================================" - -# Detect if auth is disabled -AUTH_DISABLED=false -security_status=$(curl -s "$PULSE_URL/api/security/status" 2>/dev/null || echo "{}") -if echo "$security_status" | grep -q '"disabled":true'; then - AUTH_DISABLED=true - echo "" - echo -e "${YELLOW}Note: Authentication is DISABLED (DISABLE_AUTH mode)${NC}" -fi - -# Track test results -FAILED_TESTS=() -PASSED_TESTS=() - -# Test function -run_test() { - local test_name="$1" - local test_command="$2" - - echo -n "Testing: $test_name... " - if eval "$test_command" > /dev/null 2>&1; then - echo -e "${GREEN}✓${NC}" - PASSED_TESTS+=("$test_name") - else - echo -e "${RED}✗${NC}" - FAILED_TESTS+=("$test_name") - fi -} - -# Test function with output -run_test_verbose() { - local test_name="$1" - local test_command="$2" - - echo "Testing: $test_name..." - if eval "$test_command"; then - echo -e "${GREEN}✓ $test_name passed${NC}" - PASSED_TESTS+=("$test_name") - else - echo -e "${RED}✗ $test_name failed${NC}" - FAILED_TESTS+=("$test_name") - fi -} - -echo "" -echo "1. HTTP/ROUTING TESTS" -echo "====================" - -# Critical: Test root without trailing slash (catches issue #334) -run_test "Root path without trailing slash (no redirect)" \ - "curl -s -I ${PULSE_URL} | grep -q 'HTTP/1.1 200'" - -run_test "Root path with trailing slash" \ - "curl -s -I ${PULSE_URL}/ | grep -q 'HTTP/1.1 200'" - -# Check for unwanted redirects -run_test "No relative path redirects" \ - "! curl -s -I ${PULSE_URL} | grep -q 'Location: ./'" - -# Test static assets (get actual filenames from index.html) -JS_FILE=$(curl -s ${PULSE_URL}/ | grep -o '/assets/index-[^"]*\.js' | head -1) -CSS_FILE=$(curl -s ${PULSE_URL}/ | grep -o '/assets/index-[^"]*\.css' | head -1) - -if [ -n "$JS_FILE" ]; then - run_test "JavaScript assets load" \ - "curl -s -I ${PULSE_URL}${JS_FILE} | grep -q 'Content-Type: application/javascript'" -else - echo -e "${RED}✗ Could not find JS file${NC}" - FAILED_TESTS+=("JavaScript assets load") -fi - -if [ -n "$CSS_FILE" ]; then - run_test "CSS assets load" \ - "curl -s -I ${PULSE_URL}${CSS_FILE} | grep -q 'Content-Type: text/css'" -else - echo -e "${RED}✗ Could not find CSS file${NC}" - FAILED_TESTS+=("CSS assets load") -fi - -# Test various access patterns -run_test "Empty path handling" \ - "curl -s -o /dev/null -w '%{http_code}' ${PULSE_URL} | grep -q '200'" - -if [ "$AUTH_DISABLED" != true ]; then - run_test "SPA routes require authentication" \ - "curl -s ${PULSE_URL}/settings | grep -q 'Authentication required'" -else - run_test "SPA routes accessible (auth disabled)" \ - "curl -s ${PULSE_URL}/settings | grep -q '
'" -fi - -echo "" -echo "2. API ENDPOINT TESTS" -echo "====================" - -# Public endpoints (should work without auth) -run_test "API health endpoint" \ - "curl -s ${PULSE_URL}/api/health | grep -q 'healthy'" - -run_test "API version endpoint" \ - "curl -s ${PULSE_URL}/api/version | grep -q 'version'" - -# If API token provided, test protected endpoints -if [ -n "$API_TOKEN" ]; then - echo "Testing with API token..." - - run_test "API state with token" \ - "curl -s -H 'X-API-Token: $API_TOKEN' ${PULSE_URL}/api/state | grep -q 'nodes'" - - run_test "API config/nodes with token" \ - "curl -s -H 'X-API-Token: $API_TOKEN' ${PULSE_URL}/api/config/nodes | jq -e '. | type == \"array\"'" - - run_test "API export requires passphrase" \ - "curl -s -X POST -H 'X-API-Token: $API_TOKEN' ${PULSE_URL}/api/config/export -d '{}' | grep -q 'Passphrase is required'" -else - echo -e "${YELLOW}Skipping auth tests (no API_TOKEN provided)${NC}" -fi - -echo "" -echo "3. WEBSOCKET TESTS" -echo "==================" - -# Test WebSocket endpoint availability -run_test "WebSocket endpoint responds" \ - "curl -s -I -H 'Upgrade: websocket' ${PULSE_URL}/ws | grep -q 'HTTP/1.1'" - -echo "" -echo "4. REVERSE PROXY SIMULATION" -echo "===========================" - -# Simulate reverse proxy headers -run_test "Handles X-Forwarded headers" \ - "curl -s -H 'X-Forwarded-For: 10.0.0.1' -H 'X-Forwarded-Proto: https' ${PULSE_URL}/api/health | grep -q 'healthy'" - -run_test "Handles proxy without trailing slash" \ - "curl -s -H 'X-Forwarded-Host: proxy.example.com' ${PULSE_URL} | grep -q ''" - -echo "" -echo "5. DOCKER DEPLOYMENT TEST (if Docker available)" -echo "==============================================" - -if false && command -v docker &> /dev/null; then # Temporarily disabled - hanging - echo "Testing Docker deployment..." - - # Stop any existing test container - docker stop pulse-test 2>/dev/null || true - docker rm pulse-test 2>/dev/null || true - - # Run test container - echo "Starting Docker container..." - docker run -d --name pulse-test \ - -p 7656:7655 \ - -e API_TOKEN=test123 \ - rcourtman/pulse:v${VERSION} > /dev/null 2>&1 - - # Wait for container to start - sleep 5 - - run_test "Docker container running" \ - "docker ps | grep -q pulse-test" - - run_test "Docker health endpoint" \ - "curl -s http://localhost:7656/api/health | grep -q 'healthy'" - - run_test "Docker UI loads" \ - "curl -s http://localhost:7656 | grep -q '<title>Pulse'" - - # Cleanup - docker stop pulse-test > /dev/null 2>&1 - docker rm pulse-test > /dev/null 2>&1 -else - echo -e "${YELLOW}Docker not available, skipping Docker tests${NC}" -fi - -echo "" -echo "6. LXC DEPLOYMENT TEST (if on Proxmox)" -echo "=====================================" - -if command -v pct &> /dev/null; then - echo "Would test LXC deployment (implement based on environment)" - # This would create a test container, install Pulse, and verify -else - echo -e "${YELLOW}Not on Proxmox, skipping LXC tests${NC}" -fi - -echo "" -echo "7. UPDATE MECHANISM TEST" -echo "=======================" - -# Update check -if [ "$AUTH_DISABLED" = true ]; then - run_test "Update check endpoint (auth disabled)" \ - "curl -s ${PULSE_URL}/api/updates/check | jq -e '.currentVersion'" -elif [ -n "$API_TOKEN" ]; then - run_test "Update check endpoint with auth" \ - "curl -s -H 'X-API-Token: $API_TOKEN' ${PULSE_URL}/api/updates/check | jq -e '.currentVersion'" -else - run_test "Update check requires auth" \ - "curl -s ${PULSE_URL}/api/updates/check | grep -q 'Authentication required'" -fi - -echo "" -echo "8. PERFORMANCE TESTS" -echo "===================" - -# Test response times -RESPONSE_TIME=$(curl -s -o /dev/null -w '%{time_total}' ${PULSE_URL}/api/health) -if (( $(echo "$RESPONSE_TIME < 1" | bc -l) )); then - echo -e "${GREEN}✓ API response time: ${RESPONSE_TIME}s${NC}" - PASSED_TESTS+=("API response time") -else - echo -e "${RED}✗ API slow: ${RESPONSE_TIME}s${NC}" - FAILED_TESTS+=("API response time") -fi - -echo "" -echo "9. ERROR HANDLING TESTS" -echo "======================" - -# 401 is returned before 404 when not authenticated (auth checked first) -if [ "$AUTH_DISABLED" = true ]; then - run_test "404 for non-existent endpoint" \ - "curl -s -o /dev/null -w '%{http_code}' ${PULSE_URL}/api/nonexistent | grep -q '404'" -elif [ -n "$API_TOKEN" ]; then - run_test "404 for non-existent API endpoint" \ - "curl -s -o /dev/null -w '%{http_code}' -H 'X-API-Token: $API_TOKEN' ${PULSE_URL}/api/nonexistent | grep -q '404'" -else - run_test "401 for non-existent endpoint (auth first)" \ - "curl -s -o /dev/null -w '%{http_code}' ${PULSE_URL}/api/nonexistent | grep -q '401'" -fi - -run_test "405 for wrong method" \ - "curl -s -X DELETE -o /dev/null -w '%{http_code}' ${PULSE_URL}/api/health | grep -q '405'" - -echo "" -echo "================================================" -echo "TEST RESULTS SUMMARY" -echo "================================================" -echo -e "${GREEN}Passed: ${#PASSED_TESTS[@]} tests${NC}" -echo -e "${RED}Failed: ${#FAILED_TESTS[@]} tests${NC}" - -if [ ${#FAILED_TESTS[@]} -gt 0 ]; then - echo "" - echo "Failed tests:" - for test in "${FAILED_TESTS[@]}"; do - echo " - $test" - done - echo "" - echo -e "${RED}⚠️ RELEASE TESTS FAILED - DO NOT RELEASE!${NC}" - exit 1 -else - echo "" - echo -e "${GREEN}✅ All tests passed! Safe to release.${NC}" -fi - -echo "" -echo "Additional manual tests recommended:" -echo " 1. Test behind actual reverse proxy (nginx/traefik)" -echo " 2. Test with Cloudflare tunnel" -echo " 3. Test ProxmoxVE 'update' command" -echo " 4. Test on different architectures (ARM)" -echo " 5. Test upgrade from previous version" \ No newline at end of file diff --git a/scripts/test-security.sh b/scripts/test-security.sh deleted file mode 100755 index 8a268bb50..000000000 --- a/scripts/test-security.sh +++ /dev/null @@ -1,268 +0,0 @@ -#!/bin/bash - -# Security testing for Pulse -# Tests authentication, authorization, input validation, etc. -# Detects auth state and adjusts expectations - -set -e - -PULSE_URL=${1:-http://localhost:7655} -API_TOKEN=${2:-""} - -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -NC='\033[0m' - -echo "================================================" -echo "SECURITY TESTING" -echo "================================================" - -VULNERABILITIES=0 - -# Detect if auth is disabled -AUTH_DISABLED=false -security_status=$(curl -s "$PULSE_URL/api/security/status" 2>/dev/null || echo "{}") -if echo "$security_status" | grep -q '"disabled":true'; then - AUTH_DISABLED=true - echo "" - echo -e "${YELLOW}Note: Authentication is DISABLED (DISABLE_AUTH mode)${NC}" - echo -e "${YELLOW}Skipping auth bypass tests${NC}" -fi - -test_security() { - local test_name="$1" - local command="$2" - local expected="$3" - - echo -n "$test_name: " - RESULT=$(eval "$command" 2>/dev/null || echo "ERROR") - if [[ "$RESULT" == *"$expected"* ]]; then - echo -e "${GREEN}✓ Secure${NC}" - else - echo -e "${RED}✗ VULNERABLE${NC}" - ((VULNERABILITIES++)) - fi -} - -echo "" -echo "1. AUTHENTICATION BYPASS ATTEMPTS" -echo "=================================" - -if [ "$AUTH_DISABLED" != true ]; then - test_security "Empty auth header" \ - "curl -s -H 'X-API-Token: ' $PULSE_URL/api/state | head -1" \ - "Authentication required" - - test_security "Null token" \ - "curl -s -H 'X-API-Token: null' $PULSE_URL/api/state | head -1" \ - "Authentication required" - - test_security "SQL injection in token" \ - "curl -s -H \"X-API-Token: ' OR '1'='1\" $PULSE_URL/api/state | head -1" \ - "Authentication required" - - test_security "Command injection in token" \ - "curl -s -H 'X-API-Token: \$(whoami)' $PULSE_URL/api/state | head -1" \ - "Authentication required" - - test_security "Path traversal in token" \ - "curl -s -H 'X-API-Token: ../../etc/passwd' $PULSE_URL/api/state | head -1" \ - "Authentication required" -else - echo -e "${YELLOW}Skipped - auth is disabled${NC}" -fi - -echo "" -echo "2. PATH TRAVERSAL ATTEMPTS" -echo "==========================" - -if [ "$AUTH_DISABLED" != true ]; then - test_security "Path traversal in URL" \ - "curl -s -o /dev/null -w '%{http_code}' $PULSE_URL/../../../etc/passwd" \ - "401" # 401 is fine - auth blocks before path processing - - test_security "Double URL encoding" \ - "curl -s -o /dev/null -w '%{http_code}' $PULSE_URL/%252e%252e%252f%252e%252e%252fetc%252fpasswd" \ - "401" # 401 is secure - auth blocks first - - test_security "Null byte injection" \ - "curl -s -o /dev/null -w '%{http_code}' '$PULSE_URL/api/health%00.json'" \ - "401" # Expected - auth required -else - # When auth is disabled, server returns 200 (index page) for invalid paths - test_security "Path traversal in URL" \ - "curl -s -o /dev/null -w '%{http_code}' $PULSE_URL/../../../etc/passwd" \ - "200" # Returns index page, not actual file - - test_security "Double URL encoding" \ - "curl -s -o /dev/null -w '%{http_code}' $PULSE_URL/%252e%252e%252f%252e%252e%252fetc%252fpasswd" \ - "200" # Returns index page - - test_security "Null byte injection" \ - "curl -s -o /dev/null -w '%{http_code}' '$PULSE_URL/api/health%00.json'" \ - "404" # API endpoint with null byte returns 404 -fi - -echo "" -echo "3. XSS ATTEMPTS" -echo "===============" - -test_security "XSS in query parameter" \ - "curl -s '$PULSE_URL/api/health?test=' | grep -c '' $PULSE_URL | grep -c '' | grep -c '