#!/usr/bin/env bash set -euo pipefail ROOT=$(CDPATH='' cd -- "$(dirname -- "$0")/.." && pwd) env_file=${1:-} if [[ -z "$env_file" || ! -f "$env_file" ]]; then echo "Usage: $0 EDGE_ENV_FILE" >&2 exit 1 fi if [[ "$(stat -c '%a' "$env_file")" != 600 ]]; then echo "Edge environment must have mode 0600: $env_file" >&2 exit 1 fi if [[ "$(stat -c '%u' "$env_file")" != "$(id -u)" ]]; then echo "Edge environment must be owned by the current operator." >&2 exit 1 fi read_value() { local key=$1 awk -v key="$key" ' index($0, key "=") == 1 { print substr($0, length(key) + 2) found = 1 exit } END { if (!found) exit 1 } ' "$env_file" } require_value() { local key=$1 local value if ! value=$(read_value "$key") || [[ -z "$value" ]]; then echo "$key is missing or empty in $env_file." >&2 exit 1 fi printf '%s' "$value" } validate_hostname() { local key=$1 local value=$2 if [[ ! "$value" =~ ^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?(\.[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)+$ ]]; then echo "$key must be a lowercase ASCII DNS hostname." >&2 exit 1 fi } validate_upstream() { local key=$1 local value=$2 if [[ ! "$value" =~ ^[a-z0-9]([a-z0-9.-]*[a-z0-9])?:[0-9]+$ ]]; then echo "$key must be a lowercase host and numeric port." >&2 exit 1 fi } compose_project_name=$(require_value EDGE_COMPOSE_PROJECT_NAME) public_edge_network=$(require_value PUBLIC_EDGE_NETWORK) edge_bind_address=$(require_value EDGE_BIND_ADDRESS) edge_http_port=$(require_value EDGE_HTTP_PORT) edge_https_port=$(require_value EDGE_HTTPS_PORT) primary_domain=$(require_value PRIMARY_DOMAIN) primary_upstream=$(require_value PRIMARY_UPSTREAM) test_domain=$(require_value TEST_DOMAIN) test_upstream=$(require_value TEST_UPSTREAM) [[ "$compose_project_name" =~ ^[a-zA-Z0-9_-]+$ ]] || { echo "EDGE_COMPOSE_PROJECT_NAME contains unsupported characters." >&2 exit 1 } [[ "$public_edge_network" =~ ^[a-zA-Z0-9_-]+$ ]] || { echo "PUBLIC_EDGE_NETWORK contains unsupported characters." >&2 exit 1 } [[ "$edge_bind_address" == "0.0.0.0" || "$edge_bind_address" == "127.0.0.1" ]] || { echo "EDGE_BIND_ADDRESS must be 0.0.0.0 or 127.0.0.1." >&2 exit 1 } for port_name in edge_http_port edge_https_port; do port=${!port_name} if [[ ! "$port" =~ ^[0-9]+$ ]] || ((port < 1 || port > 65535)); then echo "${port_name^^} must be between 1 and 65535." >&2 exit 1 fi done [[ "$edge_http_port" != "$edge_https_port" ]] || { echo "EDGE_HTTP_PORT and EDGE_HTTPS_PORT must be different." >&2 exit 1 } validate_hostname PRIMARY_DOMAIN "$primary_domain" validate_hostname TEST_DOMAIN "$test_domain" validate_upstream PRIMARY_UPSTREAM "$primary_upstream" validate_upstream TEST_UPSTREAM "$test_upstream" [[ "$primary_domain" != "$test_domain" ]] || { echo "PRIMARY_DOMAIN and TEST_DOMAIN must be different." >&2 exit 1 } [[ "$primary_upstream" != "$test_upstream" ]] || { echo "PRIMARY_UPSTREAM and TEST_UPSTREAM must be different." >&2 exit 1 } docker compose \ --project-name "$compose_project_name" \ --project-directory "$ROOT" \ --env-file "$env_file" \ --file "$ROOT/compose.edge.yaml" \ config --quiet echo "Public edge environment passed structural validation."