339 lines
12 KiB
Bash
Executable File
339 lines
12 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
# ⚠️ DEPRECATED: This script is deprecated and will be removed in v2.0.0
|
|
# Please use: .github/skills/scripts/skill-runner.sh integration-test-crowdsec-startup
|
|
# 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-crowdsec-startup" >&2
|
|
echo " For more info: docs/AGENT_SKILLS_MIGRATION.md" >&2
|
|
echo "" >&2
|
|
sleep 1
|
|
|
|
# Brief: Focused integration test for CrowdSec startup in Charon container
|
|
# This test verifies that CrowdSec can start successfully without the fatal
|
|
# "no datasource enabled" error, which indicates a missing or empty acquis.yaml.
|
|
#
|
|
# Steps:
|
|
# 1. Build charon:local image if not present
|
|
# 2. Start container with CERBERUS_SECURITY_CROWDSEC_MODE=local
|
|
# 3. Wait for initialization (30 seconds)
|
|
# 4. Check for fatal errors
|
|
# 5. Check LAPI health
|
|
# 6. Check acquisition config
|
|
# 7. Check installed parsers/scenarios
|
|
# 8. Output clear PASS/FAIL results
|
|
# 9. Clean up container
|
|
|
|
# Ensure we operate from repo root
|
|
PROJECT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
cd "$PROJECT_ROOT"
|
|
|
|
# ============================================================================
|
|
# Configuration
|
|
# ============================================================================
|
|
CONTAINER_NAME="charon-crowdsec-startup-test"
|
|
INIT_WAIT_SECONDS=30
|
|
|
|
# Use unique ports to avoid conflicts with running Charon
|
|
API_PORT=8580
|
|
HTTP_PORT=8480
|
|
HTTPS_PORT=8443
|
|
|
|
# ============================================================================
|
|
# Colors for output
|
|
# ============================================================================
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
BLUE='\033[0;34m'
|
|
NC='\033[0m' # No Color
|
|
|
|
log_info() { echo -e "${GREEN}[INFO]${NC} $1"; }
|
|
log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
|
|
log_error() { echo -e "${RED}[ERROR]${NC} $1"; }
|
|
log_test() { echo -e "${BLUE}[TEST]${NC} $1"; }
|
|
|
|
# ============================================================================
|
|
# Test counters
|
|
# ============================================================================
|
|
PASSED=0
|
|
FAILED=0
|
|
CRITICAL_FAILURE=false
|
|
|
|
pass_test() {
|
|
PASSED=$((PASSED + 1))
|
|
echo -e " ${GREEN}✓ PASS${NC}"
|
|
}
|
|
|
|
fail_test() {
|
|
FAILED=$((FAILED + 1))
|
|
echo -e " ${RED}✗ FAIL${NC}: $1"
|
|
}
|
|
|
|
critical_fail() {
|
|
FAILED=$((FAILED + 1))
|
|
CRITICAL_FAILURE=true
|
|
echo -e " ${RED}✗ CRITICAL FAIL${NC}: $1"
|
|
}
|
|
|
|
# ============================================================================
|
|
# Cleanup function
|
|
# ============================================================================
|
|
cleanup() {
|
|
log_info "Cleaning up test resources..."
|
|
docker rm -f ${CONTAINER_NAME} 2>/dev/null || true
|
|
# Clean up test volumes
|
|
docker volume rm charon_crowdsec_startup_data 2>/dev/null || true
|
|
docker volume rm caddy_crowdsec_startup_data 2>/dev/null || true
|
|
docker volume rm caddy_crowdsec_startup_config 2>/dev/null || true
|
|
log_info "Cleanup complete"
|
|
}
|
|
|
|
# Set up trap for cleanup on exit (success or failure)
|
|
trap cleanup EXIT
|
|
|
|
echo "=============================================="
|
|
echo "=== CrowdSec Startup Integration Test ==="
|
|
echo "=============================================="
|
|
echo ""
|
|
|
|
# ============================================================================
|
|
# Step 1: Check dependencies
|
|
# ============================================================================
|
|
log_info "Checking dependencies..."
|
|
|
|
if ! command -v docker >/dev/null 2>&1; then
|
|
log_error "docker is not available; aborting"
|
|
exit 1
|
|
fi
|
|
|
|
# ============================================================================
|
|
# Step 2: Build image if needed
|
|
# ============================================================================
|
|
if ! docker image inspect charon:local >/dev/null 2>&1; then
|
|
log_info "Building charon:local image..."
|
|
docker build -t charon:local .
|
|
else
|
|
log_info "Using existing charon:local image"
|
|
fi
|
|
|
|
# ============================================================================
|
|
# Step 3: Clean up any existing container
|
|
# ============================================================================
|
|
log_info "Stopping any existing test containers..."
|
|
docker rm -f ${CONTAINER_NAME} 2>/dev/null || true
|
|
|
|
# ============================================================================
|
|
# Step 4: Start container with CrowdSec enabled
|
|
# ============================================================================
|
|
log_info "Starting Charon container with CERBERUS_SECURITY_CROWDSEC_MODE=local..."
|
|
|
|
docker run -d --name ${CONTAINER_NAME} \
|
|
-p ${HTTP_PORT}:80 \
|
|
-p ${HTTPS_PORT}:443 \
|
|
-p ${API_PORT}:8080 \
|
|
-e CHARON_ENV=development \
|
|
-e CHARON_DEBUG=1 \
|
|
-e FEATURE_CERBERUS_ENABLED=true \
|
|
-e CERBERUS_SECURITY_CROWDSEC_MODE=local \
|
|
-v charon_crowdsec_startup_data:/app/data \
|
|
-v caddy_crowdsec_startup_data:/data \
|
|
-v caddy_crowdsec_startup_config:/config \
|
|
charon:local
|
|
|
|
log_info "Waiting ${INIT_WAIT_SECONDS} seconds for CrowdSec to initialize..."
|
|
sleep ${INIT_WAIT_SECONDS}
|
|
|
|
echo ""
|
|
echo "=============================================="
|
|
echo "=== Running CrowdSec Startup Checks ==="
|
|
echo "=============================================="
|
|
echo ""
|
|
|
|
# ============================================================================
|
|
# Test 1: Check for fatal "no datasource enabled" error
|
|
# ============================================================================
|
|
log_test "Check 1: No fatal 'no datasource enabled' error"
|
|
|
|
FATAL_ERROR_COUNT=$(docker logs ${CONTAINER_NAME} 2>&1 | grep -c "no datasource enabled" || echo "0")
|
|
|
|
if [ "$FATAL_ERROR_COUNT" -ge 1 ]; then
|
|
critical_fail "Found fatal 'no datasource enabled' error - acquis.yaml is missing or empty"
|
|
echo ""
|
|
echo "=== Relevant Container Logs ==="
|
|
docker logs ${CONTAINER_NAME} 2>&1 | grep -i "crowdsec\|acquis\|datasource\|fatal" | tail -20
|
|
echo ""
|
|
else
|
|
log_info " No 'no datasource enabled' fatal error found"
|
|
pass_test
|
|
fi
|
|
|
|
# ============================================================================
|
|
# Test 2: Check LAPI health endpoint
|
|
# ============================================================================
|
|
log_test "Check 2: CrowdSec LAPI health (127.0.0.1:8085/health)"
|
|
|
|
# Use docker exec to check LAPI health from inside the container
|
|
LAPI_HEALTH=$(docker exec ${CONTAINER_NAME} wget -q -O- http://127.0.0.1:8085/health 2>/dev/null || echo "FAILED")
|
|
|
|
if [ "$LAPI_HEALTH" != "FAILED" ] && [ -n "$LAPI_HEALTH" ]; then
|
|
log_info " LAPI is healthy"
|
|
log_info " Response: $LAPI_HEALTH"
|
|
pass_test
|
|
else
|
|
fail_test "LAPI health check failed (port 8085 not responding)"
|
|
# This could be expected if CrowdSec binary is not in the image
|
|
log_warn " This may be expected if CrowdSec binary is not installed"
|
|
fi
|
|
|
|
# ============================================================================
|
|
# Test 3: Check acquisition config exists and has datasource
|
|
# ============================================================================
|
|
log_test "Check 3: Acquisition config exists and has 'source:' definition"
|
|
|
|
ACQUIS_CONTENT=$(docker exec ${CONTAINER_NAME} cat /etc/crowdsec/acquis.yaml 2>/dev/null || echo "")
|
|
|
|
if [ -z "$ACQUIS_CONTENT" ]; then
|
|
critical_fail "acquis.yaml does not exist or is empty"
|
|
else
|
|
SOURCE_COUNT=$(echo "$ACQUIS_CONTENT" | grep -c "source:" || echo "0")
|
|
if [ "$SOURCE_COUNT" -ge 1 ]; then
|
|
log_info " acquis.yaml found with $SOURCE_COUNT datasource definition(s)"
|
|
echo ""
|
|
echo " --- acquis.yaml content ---"
|
|
echo "$ACQUIS_CONTENT" | head -15 | sed 's/^/ /'
|
|
echo " ---"
|
|
echo ""
|
|
pass_test
|
|
else
|
|
critical_fail "acquis.yaml exists but has no 'source:' definition"
|
|
echo " Content:"
|
|
echo "$ACQUIS_CONTENT" | head -10 | sed 's/^/ /'
|
|
fi
|
|
fi
|
|
|
|
# ============================================================================
|
|
# Test 4: Check for installed parsers
|
|
# ============================================================================
|
|
log_test "Check 4: Installed parsers (at least one expected)"
|
|
|
|
PARSERS_OUTPUT=$(docker exec ${CONTAINER_NAME} cscli parsers list 2>&1 || echo "CSCLI_NOT_AVAILABLE")
|
|
|
|
if [ "$PARSERS_OUTPUT" = "CSCLI_NOT_AVAILABLE" ]; then
|
|
log_warn " cscli command not available - cannot check parsers"
|
|
# Not a failure - cscli may not be in the image
|
|
pass_test
|
|
elif echo "$PARSERS_OUTPUT" | grep -q "PARSERS"; then
|
|
# cscli output includes "PARSERS" header
|
|
PARSER_COUNT=$(echo "$PARSERS_OUTPUT" | grep -c "✔" || echo "0")
|
|
if [ "$PARSER_COUNT" -ge 1 ]; then
|
|
log_info " Found $PARSER_COUNT installed parser(s)"
|
|
echo "$PARSERS_OUTPUT" | head -10 | sed 's/^/ /'
|
|
pass_test
|
|
else
|
|
log_warn " No parsers installed (CrowdSec may not parse logs correctly)"
|
|
pass_test
|
|
fi
|
|
else
|
|
log_warn " Unexpected cscli output"
|
|
echo "$PARSERS_OUTPUT" | head -5 | sed 's/^/ /'
|
|
pass_test
|
|
fi
|
|
|
|
# ============================================================================
|
|
# Test 5: Check for installed scenarios
|
|
# ============================================================================
|
|
log_test "Check 5: Installed scenarios (at least one expected)"
|
|
|
|
SCENARIOS_OUTPUT=$(docker exec ${CONTAINER_NAME} cscli scenarios list 2>&1 || echo "CSCLI_NOT_AVAILABLE")
|
|
|
|
if [ "$SCENARIOS_OUTPUT" = "CSCLI_NOT_AVAILABLE" ]; then
|
|
log_warn " cscli command not available - cannot check scenarios"
|
|
pass_test
|
|
elif echo "$SCENARIOS_OUTPUT" | grep -q "SCENARIOS"; then
|
|
SCENARIO_COUNT=$(echo "$SCENARIOS_OUTPUT" | grep -c "✔" || echo "0")
|
|
if [ "$SCENARIO_COUNT" -ge 1 ]; then
|
|
log_info " Found $SCENARIO_COUNT installed scenario(s)"
|
|
echo "$SCENARIOS_OUTPUT" | head -10 | sed 's/^/ /'
|
|
pass_test
|
|
else
|
|
log_warn " No scenarios installed (CrowdSec may not detect attacks)"
|
|
pass_test
|
|
fi
|
|
else
|
|
log_warn " Unexpected cscli output"
|
|
echo "$SCENARIOS_OUTPUT" | head -5 | sed 's/^/ /'
|
|
pass_test
|
|
fi
|
|
|
|
# ============================================================================
|
|
# Test 6: Check CrowdSec process is running (if expected)
|
|
# ============================================================================
|
|
log_test "Check 6: CrowdSec process running"
|
|
|
|
CROWDSEC_PID=$(docker exec ${CONTAINER_NAME} pgrep -f "crowdsec" 2>/dev/null || echo "")
|
|
|
|
if [ -n "$CROWDSEC_PID" ]; then
|
|
log_info " CrowdSec process is running (PID: $CROWDSEC_PID)"
|
|
pass_test
|
|
else
|
|
log_warn " CrowdSec process not found (may not be installed or may have crashed)"
|
|
# Check if crowdsec binary exists
|
|
CROWDSEC_BIN=$(docker exec ${CONTAINER_NAME} which crowdsec 2>/dev/null || echo "")
|
|
if [ -z "$CROWDSEC_BIN" ]; then
|
|
log_warn " crowdsec binary not found in container"
|
|
fi
|
|
pass_test
|
|
fi
|
|
|
|
# ============================================================================
|
|
# Show last container logs for debugging
|
|
# ============================================================================
|
|
echo ""
|
|
echo "=== Container Logs (last 30 lines) ==="
|
|
docker logs ${CONTAINER_NAME} 2>&1 | tail -30
|
|
echo ""
|
|
|
|
# ============================================================================
|
|
# Results Summary
|
|
# ============================================================================
|
|
echo ""
|
|
echo "=============================================="
|
|
echo "=== CrowdSec Startup Test Results ==="
|
|
echo "=============================================="
|
|
echo ""
|
|
echo -e " ${GREEN}Passed:${NC} $PASSED"
|
|
echo -e " ${RED}Failed:${NC} $FAILED"
|
|
echo ""
|
|
|
|
if [ "$CRITICAL_FAILURE" = "true" ]; then
|
|
echo -e "${RED}=============================================="
|
|
echo "=== CRITICAL: CrowdSec STARTUP BROKEN ==="
|
|
echo "==============================================${NC}"
|
|
echo ""
|
|
echo "CrowdSec cannot start properly. The 'no datasource enabled' error"
|
|
echo "indicates that acquis.yaml is missing or has no datasource definitions."
|
|
echo ""
|
|
echo "To fix:"
|
|
echo " 1. Ensure configs/crowdsec/acquis.yaml exists with 'source:' definition"
|
|
echo " 2. Ensure Dockerfile copies acquis.yaml to /etc/crowdsec.dist/"
|
|
echo " 3. Ensure .docker/docker-entrypoint.sh copies configs to /etc/crowdsec/"
|
|
echo ""
|
|
exit 1
|
|
fi
|
|
|
|
if [ $FAILED -eq 0 ]; then
|
|
echo "=============================================="
|
|
echo "=== ALL CROWDSEC STARTUP TESTS PASSED ==="
|
|
echo "=============================================="
|
|
echo ""
|
|
exit 0
|
|
else
|
|
echo "=============================================="
|
|
echo "=== CROWDSEC STARTUP TESTS FAILED ==="
|
|
echo "=============================================="
|
|
echo ""
|
|
exit 1
|
|
fi
|