#!/bin/bash set -e set -o pipefail # ⚠️ DEPRECATED: This script is deprecated and will be removed in v2.0.0 # Please use: .github/skills/scripts/skill-runner.sh integration-test-all # For more info: docs/AGENT_SKILLS_MIGRATION.md echo "⚠️ WARNING: This script is deprecated and will be removed in v2.0.0" >&2 echo " Please use: .github/skills/scripts/skill-runner.sh integration-test-all" >&2 echo " For more info: docs/AGENT_SKILLS_MIGRATION.md" >&2 echo "" >&2 sleep 1 # Fail entire script if it runs longer than 4 minutes (240 seconds) # This prevents CI hangs from indefinite waits TIMEOUT=${INTEGRATION_TEST_TIMEOUT:-240} if command -v timeout >/dev/null 2>&1; then if [ "${INTEGRATION_TEST_WRAPPED:-}" != "1" ]; then export INTEGRATION_TEST_WRAPPED=1 exec timeout $TIMEOUT "$0" "$@" fi fi # Configuration API_URL="http://localhost:8080/api/v1" ADMIN_EMAIL="admin@example.com" ADMIN_PASSWORD="changeme" echo "Waiting for Charon to be ready..." for i in $(seq 1 30); do code=$(curl -s -o /dev/null -w "%{http_code}" $API_URL/health || echo "000") if [ "$code" = "200" ]; then echo "✅ Charon is ready!" break fi echo "Attempt $i/30: health not ready (code=$code); waiting..." sleep 2 done if [ "$code" != "200" ]; then echo "❌ Charon failed to start" exit 1 fi echo "Checking setup status..." SETUP_RESPONSE=$(curl -s $API_URL/setup) echo "Setup response: $SETUP_RESPONSE" # Validate response is JSON before parsing if ! echo "$SETUP_RESPONSE" | jq -e . >/dev/null 2>&1; then echo "❌ Setup endpoint did not return valid JSON" echo "Raw response: $SETUP_RESPONSE" exit 1 fi SETUP_REQUIRED=$(echo "$SETUP_RESPONSE" | jq -r .setupRequired) if [ "$SETUP_REQUIRED" = "true" ]; then echo "Setup is required; attempting to create initial admin..." SETUP_RESPONSE=$(curl -s -X POST $API_URL/setup \ -H "Content-Type: application/json" \ -d "{\"name\":\"Administrator\",\"email\":\"$ADMIN_EMAIL\",\"password\":\"$ADMIN_PASSWORD\"}") echo "Setup response: $SETUP_RESPONSE" if echo "$SETUP_RESPONSE" | jq -e .user >/dev/null 2>&1; then echo "✅ Setup completed" else echo "⚠️ Setup request returned unexpected response; continuing to login attempt" fi fi echo "Logging in..." TOKEN=$(curl -s -X POST $API_URL/auth/login \ -H "Content-Type: application/json" \ -d "{\"email\":\"$ADMIN_EMAIL\",\"password\":\"$ADMIN_PASSWORD\"}" | jq -r .token) if [ -z "$TOKEN" ] || [ "$TOKEN" = "null" ]; then echo "❌ Login failed" exit 1 fi echo "✅ Login successful" echo "Creating Proxy Host..." # Remove existing proxy host for the domain to make the test idempotent EXISTING_ID=$(curl -s -H "Authorization: Bearer $TOKEN" $API_URL/proxy-hosts | jq -r --arg domain "test.localhost" '.[] | select(.domain_names == $domain) | .uuid' | head -n1) if [ -n "$EXISTING_ID" ]; then echo "Found existing proxy host (ID: $EXISTING_ID), deleting..." curl -s -X DELETE $API_URL/proxy-hosts/$EXISTING_ID -H "Authorization: Bearer $TOKEN" # Wait until the host is removed and Caddy has reloaded for i in $(seq 1 10); do sleep 1 STILL_EXISTS=$(curl -s -H "Authorization: Bearer $TOKEN" $API_URL/proxy-hosts | jq -r --arg domain "test.localhost" '.[] | select(.domain_names == $domain) | .uuid' | head -n1) if [ -z "$STILL_EXISTS" ]; then break fi echo "Waiting for API to delete existing proxy host..." done fi # Start a lightweight test upstream server to ensure proxy has a target (local-only). If a # whoami container is already running on the Docker network, prefer using that. USE_HOST_WHOAMI=false if command -v docker >/dev/null 2>&1; then if docker ps --format '{{.Names}}' | grep -q '^whoami$'; then USE_HOST_WHOAMI=true fi fi if [ "$USE_HOST_WHOAMI" = "false" ]; then python3 -c "import http.server, socketserver class Handler(http.server.BaseHTTPRequestHandler): def do_GET(self): self.send_response(200) self.end_headers() self.wfile.write(b'Hostname: local-test') def log_message(self, format, *args): pass httpd=socketserver.TCPServer(('0.0.0.0', 8081), Handler) import threading threading.Thread(target=httpd.serve_forever, daemon=True).start() " & else echo "Using existing whoami container for upstream tests" fi # Prefer "whoami" when running inside CI/docker (it resolves on the docker network). # For local runs, default to 127.0.0.1 since we start the test upstream on the host — # but if charon runs inside Docker and the upstream is bound to the host, we must # use host.docker.internal so Caddy inside the container can reach the host service. FORWARD_HOST="127.0.0.1" FORWARD_PORT="8081" if [ "$USE_HOST_WHOAMI" = "true" ]; then FORWARD_HOST="whoami" FORWARD_PORT="80" fi if [ -n "$CI" ] || [ -n "$GITHUB_ACTIONS" ]; then FORWARD_HOST="whoami" # whoami image listens on port 80 inside its container FORWARD_PORT="80" fi # If we're running charon in Docker locally and we didn't choose whoami, prefer # host.docker.internal so that the containerized Caddy can reach a host-bound upstream. if command -v docker >/dev/null 2>&1; then if docker ps --format '{{.Names}}' | grep -q '^charon-debug$' || docker ps --format '{{.Image}}' | grep -q 'charon:local'; then if [ "$FORWARD_HOST" = "127.0.0.1" ]; then FORWARD_HOST="host.docker.internal" fi fi fi echo "Using forward host: $FORWARD_HOST:$FORWARD_PORT" # Adjust the Caddy/Caddy proxy test port for local runs to avoid conflicts with # host services on port 80. if [ -z "$CADDY_PORT" ]; then CADDY_PORT="80" if [ -z "$CI" ] && [ -z "$GITHUB_ACTIONS" ]; then # Use a non-privileged port locally when binding to host: 8082 CADDY_PORT="8082" fi fi echo "Using Caddy host port: $CADDY_PORT" # Retry creation up to 5 times if the apply config call fails due to Caddy reloads RESPONSE="" for attempt in 1 2 3 4 5; do RESPONSE=$(curl -s -X POST $API_URL/proxy-hosts \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{ "domain_names": "test.localhost", "forward_scheme": "http", "forward_host": "'"$FORWARD_HOST"'", "forward_port": '"$FORWARD_PORT"', "access_list_id": null, "certificate_id": null, "ssl_forced": false, "caching_enabled": false, "block_exploits": false, "allow_websocket_upgrade": true, "http2_support": true, "hsts_enabled": false, "hsts_subdomains": false, "locations": [] }') # If Response contains a failure message indicating caddy apply failed, retry if echo "$RESPONSE" | grep -q "Failed to apply configuration"; then echo "Warning: failed to apply config on attempt $attempt, retrying..." # Wait for Caddy admin API on host to respond to /config to reduce collisions for i in $(seq 1 10); do if curl -s -o /dev/null -w "%{http_code}" http://localhost:${CADDY_ADMIN_PORT:-20194}/config/ >/dev/null 2>&1; then break fi sleep 1 done sleep $attempt continue fi break done ID=$(echo $RESPONSE | jq -r .uuid) if [ -z "$ID" ] || [ "$ID" = "null" ]; then echo "❌ Failed to create proxy host: $RESPONSE" exit 1 fi echo "✅ Proxy Host created (ID: $ID)" echo "Testing Proxy..." # We use Host header to route to the correct proxy host # We hit localhost:80 (Caddy) which should route to whoami HTTP_CODE=0 CONTENT="" # Retry probing Caddy for the new route for up to 30 seconds for i in $(seq 1 30); do HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" -H "Host: test.localhost" http://localhost:${CADDY_PORT} || true) CONTENT=$(curl -s -H "Host: test.localhost" http://localhost:${CADDY_PORT} || true) if [ "$HTTP_CODE" = "200" ] && echo "$CONTENT" | grep -q "Hostname:"; then break fi echo "Waiting for Caddy to pick up new route ($i/30)..." sleep 1 done if [ "$HTTP_CODE" = "200" ] && echo "$CONTENT" | grep -q "Hostname:"; then echo "✅ Proxy test passed! Content received from whoami." else echo "❌ Proxy test failed (Code: $HTTP_CODE)" echo "Content: $CONTENT" exit 1 fi