mirror of
https://github.com/bluewave-labs/Checkmate.git
synced 2026-01-04 00:29:51 -06:00
455 lines
12 KiB
Bash
Executable File
455 lines
12 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
|
|
# Dev/Test only: Not required in production
|
|
# This script tests the custom CA trust functionality in development environment
|
|
|
|
set -euo pipefail
|
|
|
|
# Colors for output
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
BLUE='\033[0;34m'
|
|
NC='\033[0m' # No Color
|
|
|
|
# Configuration
|
|
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
DEV_DIR="${ROOT_DIR}/docker/dev"
|
|
CERT_DIR="${DEV_DIR}/certs"
|
|
NGINX_DIR="${DEV_DIR}/nginx-test"
|
|
COMPOSE_BASELINE="${DEV_DIR}/docker-compose.yaml"
|
|
COMPOSE_CUSTOM_CA="${DEV_DIR}/docker-compose.custom-ca-example.yaml"
|
|
COMPOSE_NGINX_TEST="${NGINX_DIR}/docker-compose.nginx-test.yaml"
|
|
|
|
# Test configuration
|
|
NGINX_PORT=8443
|
|
CHECKMATE_PORT=52345
|
|
HEALTH_ENDPOINT="http://localhost:$CHECKMATE_PORT/api/v1/health"
|
|
TEST_URL="https://host.docker.internal:$NGINX_PORT"
|
|
MAX_WAIT=60
|
|
WAIT_INTERVAL=2
|
|
|
|
# Global flag for cleanup behavior
|
|
CLEAN_CERTS=false
|
|
|
|
# Function to print colored output
|
|
print_status() {
|
|
local status=$1
|
|
local message=$2
|
|
case $status in
|
|
"PASS")
|
|
echo -e "${GREEN}[PASS]${NC} $message"
|
|
;;
|
|
"FAIL")
|
|
echo -e "${RED}[FAIL]${NC} $message"
|
|
;;
|
|
"INFO")
|
|
echo -e "${BLUE}[INFO]${NC} $message"
|
|
;;
|
|
"WARN")
|
|
echo -e "${YELLOW}[WARN]${NC} $message"
|
|
;;
|
|
esac
|
|
}
|
|
|
|
# Function to check if a command exists
|
|
command_exists() {
|
|
command -v "$1" >/dev/null 2>&1
|
|
}
|
|
|
|
# Function to check if certificates exist and are valid
|
|
check_certificates() {
|
|
local ca_file="${CERT_DIR}/custom-ca.pem"
|
|
local cert_file="${CERT_DIR}/host-int-cert.pem"
|
|
local key_file="${CERT_DIR}/host-int-key.pem"
|
|
|
|
if [ ! -f "$ca_file" ] || [ ! -f "$cert_file" ] || [ ! -f "$key_file" ]; then
|
|
return 1
|
|
fi
|
|
|
|
# Check if files are not empty
|
|
if [ ! -s "$ca_file" ] || [ ! -s "$cert_file" ] || [ ! -s "$key_file" ]; then
|
|
return 1
|
|
fi
|
|
|
|
# Check if CA file starts with BEGIN CERTIFICATE
|
|
if ! head -1 "$ca_file" | grep -q "BEGIN CERTIFICATE"; then
|
|
return 1
|
|
fi
|
|
|
|
return 0
|
|
}
|
|
|
|
# Function to wait for service to be ready
|
|
wait_for_service() {
|
|
local url=$1
|
|
local service_name=$2
|
|
local elapsed=0
|
|
|
|
print_status "INFO" "Waiting for $service_name to be ready..."
|
|
|
|
while [ $elapsed -lt $MAX_WAIT ]; do
|
|
if curl -s -f "$url" >/dev/null 2>&1; then
|
|
print_status "PASS" "$service_name is ready after ${elapsed}s"
|
|
return 0
|
|
fi
|
|
|
|
sleep $WAIT_INTERVAL
|
|
elapsed=$((elapsed + WAIT_INTERVAL))
|
|
echo -n "."
|
|
done
|
|
|
|
print_status "FAIL" "$service_name failed to start within ${MAX_WAIT}s"
|
|
return 1
|
|
}
|
|
|
|
# Function to get container name by image
|
|
get_container_name() {
|
|
local image_name=$1
|
|
docker ps --filter "ancestor=$image_name" --format "{{.Names}}" | head -n1
|
|
}
|
|
|
|
# Function to run Node.js probe test
|
|
run_probe_test() {
|
|
local container_name=$1
|
|
local test_name=$2
|
|
local expected_exit_code=$3
|
|
|
|
print_status "INFO" "Running $test_name probe test..."
|
|
|
|
local probe_script="
|
|
const https = require('https');
|
|
https.get('https://host.docker.internal:8443', res => {
|
|
console.log('STATUS', res.statusCode);
|
|
process.exit(res.statusCode===200?0:1);
|
|
}).on('error', e => {
|
|
console.error('ERR', e.code||e.message);
|
|
process.exit(1);
|
|
});
|
|
"
|
|
|
|
local exit_code
|
|
if docker exec -i "$container_name" node -e "$probe_script" 2>/dev/null; then
|
|
exit_code=$?
|
|
else
|
|
exit_code=$?
|
|
fi
|
|
|
|
if [ $exit_code -eq $expected_exit_code ]; then
|
|
print_status "PASS" "$test_name probe test completed with expected exit code $expected_exit_code"
|
|
return 0
|
|
else
|
|
print_status "FAIL" "$test_name probe test failed with exit code $exit_code (expected $expected_exit_code)"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# Function to setup certificates if needed
|
|
setup_certificates_if_needed() {
|
|
if check_certificates; then
|
|
print_status "INFO" "Certificates already exist and are valid, skipping generation"
|
|
return 0
|
|
fi
|
|
|
|
print_status "INFO" "Certificates missing or invalid, generating new ones..."
|
|
if [ -x "${ROOT_DIR}/scripts/dev/setup-custom-ca.sh" ]; then
|
|
"${ROOT_DIR}/scripts/dev/setup-custom-ca.sh"
|
|
else
|
|
print_status "FAIL" "Certificate setup script not found at scripts/dev/setup-custom-ca.sh"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# Function to create nginx test configuration
|
|
create_nginx_test_config() {
|
|
print_status "INFO" "Setting up nginx test configuration..."
|
|
|
|
mkdir -p "$NGINX_DIR"
|
|
|
|
# Create nginx.conf if it doesn't exist
|
|
if [ ! -f "${NGINX_DIR}/nginx.conf" ]; then
|
|
cat > "${NGINX_DIR}/nginx.conf" << 'EOF'
|
|
events {}
|
|
http {
|
|
server {
|
|
listen 443 ssl;
|
|
ssl_certificate /etc/nginx/certs/server.crt;
|
|
ssl_certificate_key /etc/nginx/certs/server.key;
|
|
location / {
|
|
return 200 "hello from tls\n";
|
|
}
|
|
}
|
|
}
|
|
EOF
|
|
fi
|
|
|
|
# Create docker-compose.nginx-test.yaml if it doesn't exist
|
|
if [ ! -f "$COMPOSE_NGINX_TEST" ]; then
|
|
cat > "$COMPOSE_NGINX_TEST" << EOF
|
|
services:
|
|
nginx-test:
|
|
image: nginx:alpine
|
|
ports:
|
|
- "$NGINX_PORT:443"
|
|
volumes:
|
|
- ../certs/host-int-cert.pem:/etc/nginx/certs/server.crt:ro
|
|
- ../certs/host-int-key.pem:/etc/nginx/certs/server.key:ro
|
|
- ./nginx.conf:/etc/nginx/nginx.conf:ro
|
|
restart: unless-stopped
|
|
EOF
|
|
fi
|
|
|
|
print_status "PASS" "Nginx test configuration created"
|
|
}
|
|
|
|
# Function to start nginx test service
|
|
start_nginx_test() {
|
|
print_status "INFO" "Starting nginx test service..."
|
|
|
|
cd "$NGINX_DIR"
|
|
docker-compose -f docker-compose.nginx-test.yaml up -d
|
|
|
|
# Wait for nginx to be ready
|
|
local elapsed=0
|
|
while [ $elapsed -lt $MAX_WAIT ]; do
|
|
if curl -s -f -k "https://localhost:$NGINX_PORT" >/dev/null 2>&1; then
|
|
print_status "PASS" "Nginx test service is ready"
|
|
cd "$ROOT_DIR"
|
|
return 0
|
|
fi
|
|
|
|
sleep $WAIT_INTERVAL
|
|
elapsed=$((elapsed + WAIT_INTERVAL))
|
|
echo -n "."
|
|
done
|
|
|
|
print_status "FAIL" "Nginx test service failed to start"
|
|
cd "$ROOT_DIR"
|
|
return 1
|
|
}
|
|
|
|
# Function to stop nginx test service
|
|
stop_nginx_test() {
|
|
print_status "INFO" "Stopping nginx test service..."
|
|
cd "$NGINX_DIR"
|
|
docker-compose -f docker-compose.nginx-test.yaml down 2>/dev/null || true
|
|
cd "$ROOT_DIR"
|
|
}
|
|
|
|
# Function to run baseline test
|
|
run_baseline_test() {
|
|
print_status "INFO" "Running baseline test (should fail due to unknown CA)..."
|
|
|
|
# Start baseline Checkmate
|
|
cd "$DEV_DIR"
|
|
docker-compose -f docker-compose.yaml up -d --build
|
|
|
|
# Wait for Checkmate to be ready
|
|
if ! wait_for_service "$HEALTH_ENDPOINT" "Checkmate baseline"; then
|
|
cd "$ROOT_DIR"
|
|
return 1
|
|
fi
|
|
|
|
# Get container name
|
|
local container_name
|
|
container_name=$(get_container_name "uptime_server")
|
|
if [ -z "$container_name" ]; then
|
|
print_status "FAIL" "Could not find Checkmate server container"
|
|
cd "$ROOT_DIR"
|
|
return 1
|
|
fi
|
|
|
|
# Run probe test (should fail)
|
|
if run_probe_test "$container_name" "baseline" 1; then
|
|
print_status "PASS" "Baseline test completed - TLS failure as expected"
|
|
cd "$ROOT_DIR"
|
|
return 0
|
|
else
|
|
print_status "FAIL" "Baseline test failed - unexpected behavior"
|
|
cd "$ROOT_DIR"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# Function to run custom CA test
|
|
run_custom_ca_test() {
|
|
print_status "INFO" "Running custom CA test (should succeed)..."
|
|
|
|
# Stop baseline Checkmate
|
|
cd "$DEV_DIR"
|
|
docker-compose -f docker-compose.yaml down
|
|
|
|
# Start Checkmate with custom CA
|
|
docker-compose -f docker-compose.yaml -f docker-compose.custom-ca-example.yaml up -d --build
|
|
|
|
# Wait for Checkmate to be ready
|
|
if ! wait_for_service "$HEALTH_ENDPOINT" "Checkmate custom CA"; then
|
|
cd "$ROOT_DIR"
|
|
return 1
|
|
fi
|
|
|
|
# Get container name
|
|
local container_name
|
|
container_name=$(get_container_name "uptime_server")
|
|
if [ -z "$container_name" ]; then
|
|
print_status "FAIL" "Could not find Checkmate server container"
|
|
cd "$ROOT_DIR"
|
|
return 1
|
|
fi
|
|
|
|
# Run probe test (should succeed)
|
|
if run_probe_test "$container_name" "custom CA" 0; then
|
|
print_status "PASS" "Custom CA test completed - TLS success as expected"
|
|
cd "$ROOT_DIR"
|
|
return 0
|
|
else
|
|
print_status "FAIL" "Custom CA test failed - unexpected behavior"
|
|
cd "$ROOT_DIR"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# Function to cleanup everything
|
|
cleanup() {
|
|
print_status "INFO" "Cleaning up test environment..."
|
|
|
|
# Stop all services
|
|
cd "$DEV_DIR"
|
|
docker-compose -f docker-compose.yaml down 2>/dev/null || true
|
|
docker-compose -f docker-compose.yaml -f docker-compose.custom-ca-example.yaml down 2>/dev/null || true
|
|
|
|
stop_nginx_test
|
|
|
|
# Only remove certificates if --clean was specified
|
|
if [ "$CLEAN_CERTS" = true ]; then
|
|
print_status "INFO" "Removing certificates as requested with --clean"
|
|
rm -rf "${CERT_DIR:?}"/*
|
|
else
|
|
print_status "INFO" "Preserving certificates for future test runs"
|
|
fi
|
|
|
|
cd "$ROOT_DIR"
|
|
print_status "PASS" "Cleanup completed"
|
|
}
|
|
|
|
# Function to show usage
|
|
show_usage() {
|
|
echo "Usage: $0 [OPTIONS]"
|
|
echo ""
|
|
echo "Options:"
|
|
echo " --clean Clean up all test containers and certificates"
|
|
echo " --help Show this help message"
|
|
echo ""
|
|
echo "This script tests the custom CA trust functionality in Checkmate."
|
|
}
|
|
|
|
# Main function
|
|
main() {
|
|
local clean_only=false
|
|
|
|
# Parse command line arguments
|
|
while [[ $# -gt 0 ]]; do
|
|
case $1 in
|
|
--clean)
|
|
clean_only=true
|
|
CLEAN_CERTS=true
|
|
shift
|
|
;;
|
|
--help)
|
|
show_usage
|
|
exit 0
|
|
;;
|
|
*)
|
|
echo "Unknown option: $1"
|
|
show_usage
|
|
exit 1
|
|
;;
|
|
esac
|
|
done
|
|
|
|
print_status "INFO" "Starting Checkmate Custom CA Trust Test"
|
|
echo "=================================================="
|
|
|
|
if [ "$clean_only" = true ]; then
|
|
cleanup
|
|
exit 0
|
|
fi
|
|
|
|
# Check prerequisites
|
|
if ! command_exists docker; then
|
|
print_status "FAIL" "Docker is not installed or not in PATH"
|
|
exit 1
|
|
fi
|
|
|
|
if ! command_exists docker-compose; then
|
|
print_status "FAIL" "docker-compose is not installed or not in PATH"
|
|
exit 1
|
|
fi
|
|
|
|
# Check if required files exist
|
|
if [ ! -f "$COMPOSE_BASELINE" ]; then
|
|
print_status "FAIL" "Baseline docker-compose.yaml not found at $COMPOSE_BASELINE"
|
|
exit 1
|
|
fi
|
|
|
|
if [ ! -f "$COMPOSE_CUSTOM_CA" ]; then
|
|
print_status "FAIL" "Custom CA docker-compose override not found at $COMPOSE_CUSTOM_CA"
|
|
exit 1
|
|
fi
|
|
|
|
# Setup test environment
|
|
setup_certificates_if_needed
|
|
create_nginx_test_config
|
|
start_nginx_test
|
|
|
|
# Run tests
|
|
local baseline_result=false
|
|
local custom_ca_result=false
|
|
|
|
if run_baseline_test; then
|
|
baseline_result=true
|
|
fi
|
|
|
|
if run_custom_ca_test; then
|
|
custom_ca_result=true
|
|
fi
|
|
|
|
# Print summary
|
|
echo ""
|
|
echo "=================================================="
|
|
print_status "INFO" "Test Summary"
|
|
echo "=================================================="
|
|
|
|
if [ "$baseline_result" = true ]; then
|
|
print_status "PASS" "Baseline: TLS failure as expected"
|
|
else
|
|
print_status "FAIL" "Baseline: Unexpected behavior"
|
|
fi
|
|
|
|
if [ "$custom_ca_result" = true ]; then
|
|
print_status "PASS" "Custom CA: TLS success (STATUS 200)"
|
|
else
|
|
print_status "FAIL" "Custom CA: Unexpected behavior"
|
|
fi
|
|
|
|
if [ "$baseline_result" = true ] && [ "$custom_ca_result" = true ]; then
|
|
echo ""
|
|
print_status "PASS" "All tests passed! Custom CA trust is working correctly."
|
|
echo ""
|
|
print_status "INFO" "To clean up, run: $0 --clean"
|
|
exit 0
|
|
else
|
|
echo ""
|
|
print_status "FAIL" "Some tests failed. Custom CA trust may not be working correctly."
|
|
echo ""
|
|
print_status "INFO" "To clean up, run: $0 --clean"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
# Trap cleanup on script exit
|
|
trap cleanup EXIT
|
|
|
|
# Run main function
|
|
main "$@"
|