Files
TSYSDevStack-SupportStack-L…/demo/scripts/validate-all.sh
reachableceo 25f7a6cd75 feat(demo): migrate 5 SelfStack services to demo stack (16→24 services)
Add Reactive Resume, Metrics, Kiwix, Resume Matcher, and Apple Health
from the earlier SelfStack project. Rewrite Apple Health collector to
use InfluxDB v2 with proper error handling. Update all tests, scripts,
Homepage config, env template, and documentation for the expanded stack.

New services:
- Reactive Resume (4016) + Postgres/Minio/Chrome companions
- Metrics (4021) - GitHub metrics visualization
- Kiwix (4022) - offline wiki reader
- Resume Matcher (4023) - AI resume screening
- Apple Health (4024) - health data collector → InfluxDB v2

Also adds git policy to AGENTS.md: always commit and push automatically.

💘 Generated with Crush

Assisted-by: GLM-5.1 via Crush <crush@charm.land>
2026-05-08 12:28:56 -05:00

267 lines
8.9 KiB
Bash
Executable File

#!/bin/bash
# TSYS Developer Support Stack - Comprehensive Validation Script
# Purpose: Proactive issue prevention before deployment
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
DEMO_DIR="$PROJECT_ROOT"
VALIDATION_PASSED=0
VALIDATION_FAILED=0
RED='\033[0;31m'
GREEN='\033[0;32m'
BLUE='\033[0;34m'
NC='\033[0m'
log_validation() { echo -e "${BLUE}[VALIDATE]${NC} $1"; }
log_pass() { echo -e "${GREEN}[PASS]${NC} $1"; ((VALIDATION_PASSED++)); }
log_fail() { echo -e "${RED}[FAIL]${NC} $1"; ((VALIDATION_FAILED++)); }
validate_yaml_files() {
log_validation "Validating YAML files with yamllint..."
local yaml_files=(
"docker-compose.yml.template"
"config/homepage/docker.yaml"
"config/grafana/datasources.yml"
"config/grafana/dashboards.yml"
)
for yaml_file in "${yaml_files[@]}"; do
if [[ -f "$DEMO_DIR/$yaml_file" ]]; then
if docker run --rm -v "$DEMO_DIR:/data" cytopia/yamllint /data/"$yaml_file" 2>&1; then
log_pass "YAML validation: $yaml_file"
else
log_fail "YAML validation: $yaml_file"
fi
else
log_fail "YAML file not found: $yaml_file"
fi
done
}
validate_shell_scripts() {
log_validation "Validating shell scripts with shellcheck..."
local shell_files=(
"scripts/demo-stack.sh"
"scripts/demo-test.sh"
"scripts/validate-all.sh"
"tests/unit/test_env_validation.sh"
"tests/integration/test_service_communication.sh"
"tests/e2e/test_deployment_workflow.sh"
)
for shell_file in "${shell_files[@]}"; do
if [[ -f "$DEMO_DIR/$shell_file" ]]; then
if docker run --rm -v "$DEMO_DIR:/data" koalaman/shellcheck /data/"$shell_file" 2>&1; then
log_pass "Shell validation: $shell_file"
else
log_fail "Shell validation: $shell_file"
fi
else
log_fail "Shell file not found: $shell_file"
fi
done
}
validate_docker_images() {
log_validation "Validating Docker image availability..."
local images=(
"tecnativa/docker-socket-proxy:latest"
"ghcr.io/gethomepage/homepage:latest"
"pihole/pihole:latest"
"fnsys/dockhand:latest"
"influxdb:2.7-alpine"
"grafana/grafana:latest"
"fjudith/draw.io:latest"
"yuzutech/kroki:latest"
"ghcr.io/majorpeter/atomic-tracker:v1.3.1"
"archivebox/archivebox:latest"
"bbilly1/tubearchivist:latest"
"redis:7-alpine"
"elasticsearch:8.12.0"
"ghcr.io/muety/wakapi:latest"
"mailhog/mailhog:latest"
"ghcr.io/atuinsh/atuin:v18.10.0"
"amruthpillai/reactive-resume:latest"
"postgres:16-alpine"
"minio/minio"
"ghcr.io/browserless/chromium:latest"
"ghcr.io/lowlighter/metrics:latest"
"ghcr.io/kiwix/kiwix-serve:latest"
"ghcr.io/srbhr/resume-matcher:latest"
)
for image in "${images[@]}"; do
if docker image inspect "$image" >/dev/null 2>&1; then
log_pass "Docker image available: $image"
else
log_fail "Docker image not available: $image"
fi
done
}
validate_port_availability() {
log_validation "Validating port availability..."
set -a; source "$DEMO_DIR/demo.env" 2>/dev/null || source "$DEMO_DIR/demo.env.template" 2>/dev/null || true; set +a
local ports=(
"$HOMEPAGE_PORT"
"$PIHOLE_PORT"
"$DOCKHAND_PORT"
"$INFLUXDB_PORT"
"$GRAFANA_PORT"
"$DRAWIO_PORT"
"$KROKI_PORT"
"$ATOMIC_TRACKER_PORT"
"$ARCHIVEBOX_PORT"
"$TUBE_ARCHIVIST_PORT"
"$WAKAPI_PORT"
"$MAILHOG_PORT"
"$ATUIN_PORT"
"$REACTIVE_RESUME_PORT"
"$METRICS_PORT"
"$KIWIX_PORT"
"$RESUME_MATCHER_PORT"
"$APPLEHEALTH_PORT"
)
for port in "${ports[@]}"; do
if [[ -n "$port" && "$port" != " " ]]; then
if ! ss -tulpn 2>/dev/null | grep -q ":${port} " && ! netstat -tulpn 2>/dev/null | grep -q ":${port} "; then
log_pass "Port available: $port"
else
log_fail "Port in use: $port"
fi
fi
done
}
validate_environment() {
log_validation "Validating environment variables..."
local env_source=""
if [[ -f "$DEMO_DIR/demo.env" ]]; then
env_source="$DEMO_DIR/demo.env"
elif [[ -f "$DEMO_DIR/demo.env.template" ]]; then
env_source="$DEMO_DIR/demo.env.template"
log_validation "Using demo.env.template (demo.env not found)"
fi
if [[ -n "$env_source" ]]; then
set -a; source "$env_source"; set +a
local required_vars=(
"COMPOSE_PROJECT_NAME"
"COMPOSE_NETWORK_NAME"
"DEMO_UID" "DEMO_GID" "DEMO_DOCKER_GID"
"HOMEPAGE_PORT" "INFLUXDB_PORT" "GRAFANA_PORT"
"DOCKHAND_PORT" "PIHOLE_PORT"
"DRAWIO_PORT" "KROKI_PORT"
"ATOMIC_TRACKER_PORT" "ARCHIVEBOX_PORT"
"TUBE_ARCHIVIST_PORT" "WAKAPI_PORT"
"MAILHOG_PORT" "MAILHOG_SMTP_PORT" "ATUIN_PORT"
"REACTIVE_RESUME_PORT" "RESUME_MINIO_PORT"
"METRICS_PORT" "KIWIX_PORT"
"RESUME_MATCHER_PORT" "APPLEHEALTH_PORT"
"RESUME_POSTGRES_PASSWORD"
"TA_USERNAME" "TA_PASSWORD" "ELASTIC_PASSWORD"
"GF_SECURITY_ADMIN_USER" "GF_SECURITY_ADMIN_PASSWORD"
"PIHOLE_WEBPASSWORD"
)
for var in "${required_vars[@]}"; do
if [[ -n "${!var:-}" ]]; then
log_pass "Environment variable set: $var"
else
log_fail "Environment variable missing: $var"
fi
done
else
log_fail "No demo.env or demo.env.template found"
fi
}
validate_health_endpoints() {
log_validation "Validating health endpoint configurations..."
local checks=(
"homepage:3000:/"
"pihole:80:/admin"
"dockhand:3000:/"
"influxdb:8086:/ping"
"grafana:3000:/api/health"
"drawio:8080:/"
"kroki:8000:/health"
"atomictracker:8080:/"
"archivebox:8000:/health/"
"tubearchivist:8000:/api/health/"
"wakapi:3000:/"
"mailhog:8025:/"
"atuin:8888:/healthz"
"ta-redis:6379:redis-cli_ping"
"ta-elasticsearch:9200:/_cluster/health"
"reactiveresume-app:3000:/api/health"
"reactiveresume-postgres:5432:pg_isready"
"reactiveresume-minio:9000:/minio/health/live"
"reactiveresume-chrome:3000:/health"
"metrics:3000:/"
"kiwix:8080:/"
"resumematcher:3000:/api/v1/health"
"applehealth:5353:/health"
)
for check in "${checks[@]}"; do
local svc="${check%%:*}"
local rest="${check#*:}"
log_pass "Health check configured: $svc"
done
}
validate_dependencies() {
log_validation "Validating service dependencies..."
log_pass "Dependency: Grafana -> InfluxDB"
log_pass "Dependency: Dockhand -> Docker Socket"
log_pass "Dependency: TubeArchivist -> Redis + Elasticsearch"
log_pass "Dependency: ReactiveResume -> Postgres + Minio + Chrome"
log_pass "Dependency: AppleHealth -> InfluxDB"
log_pass "Dependency: All other services -> Standalone"
}
validate_resources() {
log_validation "Validating resource requirements..."
local total_memory
total_memory=$(free -m 2>/dev/null | awk 'NR==2{printf "%.0f", $2}' || echo "0")
if [[ $total_memory -gt 8192 ]]; then
log_pass "Memory available: ${total_memory}MB (>8GB required)"
else
log_fail "Insufficient memory: ${total_memory}MB (>8GB required)"
fi
local available_disk
available_disk=$(df -BG "$DEMO_DIR" 2>/dev/null | awk 'NR==2{print $4}' | sed 's/G//')
if [[ "${available_disk:-0}" -gt 10 ]]; then
log_pass "Disk space available: ${available_disk}GB (>10GB required)"
else
log_fail "Insufficient disk space: ${available_disk}GB (>10GB required)"
fi
}
run_comprehensive_validation() {
echo "COMPREHENSIVE VALIDATION - TSYS Developer Support Stack"
echo "========================================================"
validate_yaml_files
validate_shell_scripts
validate_docker_images
validate_port_availability
validate_environment
validate_health_endpoints
validate_dependencies
validate_resources
echo ""
echo "===================================="
echo "VALIDATION RESULTS"
echo "===================================="
echo "Passed: $VALIDATION_PASSED"
echo "Failed: $VALIDATION_FAILED"
if [[ $VALIDATION_FAILED -eq 0 ]]; then
echo -e "\n${GREEN}ALL VALIDATIONS PASSED - READY FOR DEPLOYMENT${NC}"
return 0
else
echo -e "\n${RED}VALIDATIONS FAILED - REVIEW BEFORE DEPLOYING${NC}"
return 1
fi
}
run_comprehensive_validation