#!/usr/bin/env sh set -eu compose_file=${COMPOSE_FILE:-docker-compose.yml} nginx_port=${NGINX_PORT:-8088} wait_for_url() { name=$1 url=$2 attempts=30 while [ "$attempts" -gt 0 ]; do if curl --fail --silent --show-error --output /dev/null "$url"; then return 0 fi attempts=$((attempts - 1)) sleep 2 done echo "$name did not become ready: $url" >&2 return 1 } assert_healthy() { service=$1 attempts=30 while [ "$attempts" -gt 0 ]; do container_id=$(docker compose -f "$compose_file" ps --quiet "$service") if [ -n "$container_id" ]; then health=$(docker inspect --format '{{if .State.Health}}{{.State.Health.Status}}{{else}}{{.State.Status}}{{end}}' "$container_id") if [ "$health" = "healthy" ]; then return 0 fi else health="not-running" fi attempts=$((attempts - 1)) sleep 2 done echo "$service is not healthy: $health" >&2 return 1 } for service in postgres keycloak app nginx; do assert_healthy "$service" done wait_for_url "Keycloak discovery" \ "http://localhost:8080/realms/master/.well-known/openid-configuration" wait_for_url "Spring Boot health" "http://localhost:8081/actuator/health" wait_for_url "nginx health" "http://localhost:${nginx_port}/health" wait_for_url "public API" "http://localhost:${nginx_port}/api/public" protected_status=$(curl --silent --output /dev/null --write-out '%{http_code}' \ "http://localhost:${nginx_port}/api/me") if [ "$protected_status" != "401" ]; then echo "expected unauthenticated /api/me to return 401, got $protected_status" >&2 exit 1 fi echo "baseline stack verified: 4 healthy services, public 200, protected 401"