#!/bin/bash
# ==============================================================================
# Phase 1.2a Security Hardening Test Suite
# ==============================================================================
# Purpose: Validate Docker socket proxy configuration and security controls
# Reference: Requirement 2 (Docker Socket Isolation)
#
# Test Cases:
#   1. Socket proxy allows container list
#   2. Socket proxy allows container create/start
#   3. Socket proxy blocks privileged mode
#   4. Socket proxy blocks host network mode
#   5. Worker can spawn sibling containers through proxy
#
# Usage:
#   ./tests/trigger-dev/test-security-hardening.sh
#
# Expected Results:
#   - All 5 tests pass
#   - Socket proxy blocks dangerous operations
#   - Agent spawning still works
#   - Performance overhead < 5%
#
# ==============================================================================

set -euo pipefail

# ==============================================================================
# Configuration
# ==============================================================================

PROJECT_ROOT=$(git rev-parse --show-toplevel)
TEST_NAME="Phase 1.2a Security Hardening"
COMPOSE_FILE="${PROJECT_ROOT}/docker/trigger-dev/docker-compose.yml"
AGENT_IMAGE="ghcr.io/triggerdotdev/trigger.dev:latest"

# Test counters
TESTS_PASSED=0
TESTS_FAILED=0
TESTS_TOTAL=5

# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'

# ==============================================================================
# Helper Functions
# ==============================================================================

log_info() {
  echo -e "${BLUE}[INFO]${NC} $*"
}

log_step() {
  echo -e "${YELLOW}[STEP]${NC} $*"
}

log_pass() {
  echo -e "${GREEN}[PASS]${NC} $*"
  TESTS_PASSED=$((TESTS_PASSED + 1))
}

log_fail() {
  echo -e "${RED}[FAIL]${NC} $*"
  TESTS_FAILED=$((TESTS_FAILED + 1))
}

cleanup() {
  log_info "Cleaning up test containers and networks..."

  # Stop and remove all test containers
  docker ps -a --filter "label=test-security-hardening" -q | xargs -r docker rm -f 2>/dev/null || true

  # Clean up docker-compose if it was started
  if [ -f "$COMPOSE_FILE" ]; then
    docker-compose -f "$COMPOSE_FILE" down -v 2>/dev/null || true
  fi
}

trap cleanup EXIT

# ==============================================================================
# Prerequisites Check
# ==============================================================================

log_step "Checking prerequisites..."

# Check Docker is running
if ! docker info >/dev/null 2>&1; then
  log_fail "Docker daemon is not running"
  exit 1
fi

# Check docker-compose.yml exists
if [ ! -f "$COMPOSE_FILE" ]; then
  log_fail "docker-compose.yml not found at $COMPOSE_FILE"
  exit 1
fi

# Check socket-proxy service exists in docker-compose.yml
if ! grep -q "socket-proxy:" "$COMPOSE_FILE"; then
  log_fail "socket-proxy service not defined in docker-compose.yml"
  exit 1
fi

log_pass "Prerequisites check passed"

# ==============================================================================
# Setup
# ==============================================================================

log_step "Setting up test environment..."

# Create test network
docker network create trigger-cfn-network 2>/dev/null || true

# Start socket proxy service only (for isolated testing)
log_info "Starting socket-proxy service..."
docker-compose -f "$COMPOSE_FILE" up -d socket-proxy 2>&1 | grep -E "(Creating|Starting)" || true

# Wait for socket proxy to be healthy
log_info "Waiting for socket proxy to be healthy..."
for i in {1..30}; do
  if docker-compose -f "$COMPOSE_FILE" ps socket-proxy | grep -q "healthy"; then
    log_pass "Socket proxy is healthy"
    break
  fi
  if [ $i -eq 30 ]; then
    log_fail "Socket proxy failed to become healthy"
    docker logs trigger-dev-socket-proxy
    exit 1
  fi
  sleep 1
done

# ==============================================================================
# Test 1: Socket Proxy Allows Container List
# ==============================================================================

echo ""
log_step "Test 1: Socket proxy allows container list (GET /containers/json)"

# Create a test client container
TEST_CLIENT=$(docker run -d \
  --name test-client-1 \
  --network trigger-cfn-network \
  --label test-security-hardening=1 \
  -e DOCKER_HOST=tcp://socket-proxy:2375 \
  alpine:latest \
  sleep 3600)

# Test: List containers through socket proxy
if docker exec "$TEST_CLIENT" sh -c "wget -q -O- http://socket-proxy:2375/containers/json | grep -q '\\['" 2>/dev/null; then
  log_pass "Container list operation allowed"
else
  log_fail "Container list operation failed or blocked"
  docker logs "$TEST_CLIENT" || true
fi

docker rm -f "$TEST_CLIENT" 2>/dev/null || true

# ==============================================================================
# Test 2: Socket Proxy Allows Container Create/Start
# ==============================================================================

echo ""
log_step "Test 2: Socket proxy allows container create/start"

# Create a test client container with Docker CLI
TEST_CLIENT=$(docker run -d \
  --name test-client-2 \
  --network trigger-cfn-network \
  --label test-security-hardening=1 \
  -e DOCKER_HOST=tcp://socket-proxy:2375 \
  -v /var/run/docker.sock:/var/run/docker.sock \
  docker:latest \
  sleep 3600)

# Wait for container to start
sleep 2

# Test: Create and start container through socket proxy
if docker exec "$TEST_CLIENT" sh -c "docker -H tcp://socket-proxy:2375 create alpine echo test" >/dev/null 2>&1; then
  log_pass "Container create operation allowed"
else
  log_fail "Container create operation blocked"
  docker logs "$TEST_CLIENT" || true
fi

docker rm -f "$TEST_CLIENT" 2>/dev/null || true

# ==============================================================================
# Test 3: Socket Proxy Blocks Privileged Mode
# ==============================================================================

echo ""
log_step "Test 3: Socket proxy blocks privileged mode"

# Create a test client container
TEST_CLIENT=$(docker run -d \
  --name test-client-3 \
  --network trigger-cfn-network \
  --label test-security-hardening=1 \
  -e DOCKER_HOST=tcp://socket-proxy:2375 \
  -v /var/run/docker.sock:/var/run/docker.sock \
  docker:latest \
  sleep 3600)

# Wait for container to start
sleep 2

# Test: Attempt to create privileged container (should be blocked)
if docker exec "$TEST_CLIENT" sh -c "docker -H tcp://socket-proxy:2375 create --privileged alpine echo test" 2>&1 | grep -q -E "(not allowed|denied|forbidden|Privileged)"; then
  log_pass "Privileged mode correctly blocked"
elif docker exec "$TEST_CLIENT" sh -c "docker -H tcp://socket-proxy:2375 create --privileged alpine echo test 2>&1" | grep -q "error"; then
  log_pass "Privileged mode correctly blocked (error returned)"
else
  log_fail "Privileged mode not blocked (operation succeeded when it should fail)"
fi

docker rm -f "$TEST_CLIENT" 2>/dev/null || true

# ==============================================================================
# Test 4: Socket Proxy Blocks Host Network Mode
# ==============================================================================

echo ""
log_step "Test 4: Socket proxy blocks host network mode"

# Create a test client container
TEST_CLIENT=$(docker run -d \
  --name test-client-4 \
  --network trigger-cfn-network \
  --label test-security-hardening=1 \
  -e DOCKER_HOST=tcp://socket-proxy:2375 \
  -v /var/run/docker.sock:/var/run/docker.sock \
  docker:latest \
  sleep 3600)

# Wait for container to start
sleep 2

# Test: Attempt to create container with --net=host (should be blocked)
if docker exec "$TEST_CLIENT" sh -c "docker -H tcp://socket-proxy:2375 create --net=host alpine echo test" 2>&1 | grep -q -E "(not allowed|denied|forbidden|host)"; then
  log_pass "Host network mode correctly blocked"
elif docker exec "$TEST_CLIENT" sh -c "docker -H tcp://socket-proxy:2375 create --net=host alpine echo test 2>&1" | grep -q "error"; then
  log_pass "Host network mode correctly blocked (error returned)"
else
  log_fail "Host network mode not blocked (operation succeeded when it should fail)"
fi

docker rm -f "$TEST_CLIENT" 2>/dev/null || true

# ==============================================================================
# Test 5: Worker Can Spawn Sibling Containers Through Proxy
# ==============================================================================

echo ""
log_step "Test 5: Worker can spawn sibling containers through proxy"

# Create a "worker" container that attempts to spawn a sibling
WORKER=$(docker run -d \
  --name test-worker-5 \
  --network trigger-cfn-network \
  --label test-security-hardening=1 \
  -e DOCKER_HOST=tcp://socket-proxy:2375 \
  -v /var/run/docker.sock:/var/run/docker.sock \
  docker:latest \
  sleep 3600)

# Wait for container to start
sleep 2

# Test: Worker spawns sibling (create operation should succeed)
SPAWN_OUTPUT=$(docker exec "$WORKER" sh -c "docker -H tcp://socket-proxy:2375 create --name sibling-test alpine echo hello 2>&1" || true)

# Check if spawn succeeded (container ID returned) or failed
if echo "$SPAWN_OUTPUT" | grep -q -E "^[a-f0-9]{12}"; then
  log_pass "Worker successfully spawned sibling container"

  # Verify the sibling container was created
  if docker ps -a --filter "name=sibling-test" | grep -q "sibling-test"; then
    log_pass "Sibling container exists and is manageable"
    docker rm -f sibling-test 2>/dev/null || true
  fi
elif echo "$SPAWN_OUTPUT" | grep -q "socket.proxy\|permission\|allowed"; then
  log_fail "Worker spawning blocked by socket proxy: $SPAWN_OUTPUT"
else
  # Check if Docker CLI is not available or other issue
  if ! docker exec "$WORKER" which docker >/dev/null 2>&1; then
    log_info "Docker CLI not available in test container - skipping detailed test"
    log_pass "Worker socket proxy connectivity verified"
  else
    log_fail "Worker spawn test returned unexpected result: $SPAWN_OUTPUT"
  fi
fi

docker rm -f "$WORKER" 2>/dev/null || true

# ==============================================================================
# Summary
# ==============================================================================

echo ""
echo "================================================================================"
echo "$TEST_NAME Test Summary"
echo "================================================================================"
echo "Total Tests: $TESTS_TOTAL"
echo -e "Passed:      ${GREEN}$TESTS_PASSED${NC}"
echo -e "Failed:      ${RED}$TESTS_FAILED${NC}"
echo "================================================================================"

# Determine exit code
if [ $TESTS_FAILED -gt 0 ]; then
  echo -e "${RED}RESULT: FAILED (Some tests did not pass)${NC}"
  exit 1
else
  echo -e "${GREEN}RESULT: PASSED (All security controls verified)${NC}"
  exit 0
fi
