#!/bin/sh set -eu stack_dir=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd) cd "$stack_dir" env_file=${ENV_FILE:-.env} if [ ! -f "$env_file" ]; then echo "$env_file does not exist; copy .env.example and replace every placeholder first." >&2 exit 66 fi secret_file_keys='IMAGE_UPLOAD_CORE2026_SECRET_FILE IMAGE_SYNC_CORE2026_SECRET_FILE' if [ "$(sed -n 's/^WEB_PUSH_ENABLED=//p' "$env_file" | tail -n 1)" = true ]; then secret_file_keys="$secret_file_keys WEB_PUSH_VAPID_PRIVATE_KEY_FILE" fi for key in $secret_file_keys; do value=$(sed -n "s/^${key}=//p" "$env_file" | tail -n 1) if [ -z "$value" ]; then echo "$key must name a readable, non-empty secret file." >&2 exit 66 fi case "$value" in /*) secret_path=$value ;; *) secret_path=$stack_dir/$value ;; esac if [ ! -r "$secret_path" ] || [ ! -s "$secret_path" ]; then echo "$key must name a readable, non-empty secret file." >&2 exit 66 fi if [ "$key" = WEB_PUSH_VAPID_PRIVATE_KEY_FILE ] && grep -q '^replace-with-' "$secret_path"; then echo "$key must not use the tracked example placeholder." >&2 exit 66 fi done docker run --rm --network=none --memory=128m --memory-swap=128m --cpus=1 --pids-limit=64 --env-file "$env_file" \ -v "$stack_dir/runtime/validate-env.mjs:/opt/sammo/validate-env.mjs:ro" \ node:24.18.0-bookworm-slim node /opt/sammo/validate-env.mjs docker compose --env-file "$env_file" config --quiet docker compose --env-file "$env_file" -f compose.yaml -f compose.dev.yaml config --quiet docker compose --env-file "$env_file" -f compose.yaml -f compose.smoke.yaml config --quiet docker compose --env-file "$env_file" config --format json | \ docker run --rm -i --network=none --memory=128m --memory-swap=128m --cpus=1 --pids-limit=64 \ -v "$stack_dir/runtime/validate-compose-model.mjs:/opt/sammo/validate-compose-model.mjs:ro" \ node:24.18.0-bookworm-slim node /opt/sammo/validate-compose-model.mjs production docker compose --env-file "$env_file" -f compose.yaml -f compose.dev.yaml config --format json | \ docker run --rm -i --network=none --memory=128m --memory-swap=128m --cpus=1 --pids-limit=64 \ -v "$stack_dir/runtime/validate-compose-model.mjs:/opt/sammo/validate-compose-model.mjs:ro" \ node:24.18.0-bookworm-slim node /opt/sammo/validate-compose-model.mjs development docker compose --env-file "$env_file" -f compose.yaml -f compose.smoke.yaml config --format json | \ docker run --rm -i --network=none --memory=128m --memory-swap=128m --cpus=1 --pids-limit=64 \ -v "$stack_dir/runtime/validate-compose-model.mjs:/opt/sammo/validate-compose-model.mjs:ro" \ node:24.18.0-bookworm-slim node /opt/sammo/validate-compose-model.mjs smoke docker run --rm --network=none --memory=128m --memory-swap=128m --cpus=1 --pids-limit=64 \ -v "$stack_dir/caddy/Caddyfile:/etc/caddy/Caddyfile:ro" \ -e SITE_ADDRESS=:80 -e ACME_EMAIL=validate@example.invalid caddy:2.10.2-alpine \ caddy validate --config /etc/caddy/Caddyfile echo 'Compose and Caddy configuration are valid.'