#!/bin/sh
set -eu

ROOT=$(CDPATH='' cd -- "$(dirname -- "$0")/.." && pwd)
cd "$ROOT"

SHELLCHECK_IMAGE="koalaman/shellcheck-alpine:v0.11.0@sha256:9955be09ea7f0dbf7ae942ac1f2094355bb30d96fffba0ec09f5432207544002"
HADOLINT_IMAGE="hadolint/hadolint:v2.14.0-debian@sha256:158cd0184dcaa18bd8ec20b61f4c1cabdf8b32a592d062f57bdcb8e4c1d312e2"
ACTIONLINT_IMAGE="rhysd/actionlint:1.7.12@sha256:b1934ee5f1c509618f2508e6eb47ee0d3520686341fec936f3b79331f9315667"
TRIVY_IMAGE="aquasec/trivy:0.72.0@sha256:cffe3f5161a47a6823fbd23d985795b3ed72a4c806da4c4df16266c02accdd6f"
PROMETHEUS_IMAGE="quay.io/prometheus/prometheus:v3.13.1@sha256:3c42b892cf723fa54d2f262c37a0e1f80aa8c8ddb1da7b9b0df9455a35a7f893"
ALERTMANAGER_IMAGE="quay.io/prometheus/alertmanager:v0.33.1@sha256:9e082985f56f4c8c9f724e18f2288c6708f472e56a5286b8863d080434ea065d"
PYTHON_IMAGE="python:3.14.6-alpine3.23@sha256:b165067c5afc37fa5608a3c05609cc3d51aafd808a30fbfd822ee594fef55ad4"

run_id="$(date -u +%Y%m%d%H%M%S)-$$"
project="wnh_quality_$(printf '%s' "$run_id" | tr -d '-')"
quality_image="who-need-help:quality-$run_id"
assets_image="who-need-help:assets-audit-$run_id"
e2e_image="who-need-help:e2e-audit-$run_id"
release_image="who-need-help:security-$run_id"
backup_image="who-need-help:backup-audit-$run_id"
minio_image="who-need-help:minio-audit-$run_id"
mc_image="who-need-help:mc-audit-$run_id"
boundary_mock_image="who-need-help:boundary-mock-audit-$run_id"
socket_proxy_image="who-need-help:socket-proxy-audit-$run_id"
postgis_image="who-need-help:postgis-audit-$run_id"
caddy_image="who-need-help:caddy-audit-$run_id"
socket_proxy_container="wnh-socket-proxy-audit-$run_id"
scan_dir=$(mktemp -d "${TMPDIR:-/tmp}/wnh-quality-scan.XXXXXX")
scan_list="${scan_dir}.files"
scan_tar="${scan_dir}.tar"

umask 077
QUALITY_POSTGRES_USER="wnh_quality_$(openssl rand -hex 6)"
QUALITY_POSTGRES_PASSWORD=$(openssl rand -base64 48 | tr -d '\n')
export QUALITY_POSTGRES_USER QUALITY_POSTGRES_PASSWORD
QUALITY_POSTGIS_IMAGE=$postgis_image
export QUALITY_POSTGIS_IMAGE

compose="docker compose -p $project -f $ROOT/compose.quality.yaml"

cleanup() {
  $compose down --volumes --remove-orphans >/dev/null 2>&1 || true
  docker rm --force "$socket_proxy_container" >/dev/null 2>&1 || true
  docker image rm "$quality_image" "$assets_image" "$e2e_image" "$release_image" \
    "$backup_image" "$minio_image" "$mc_image" \
    "$boundary_mock_image" "$socket_proxy_image" "$postgis_image" \
    "$caddy_image" \
    >/dev/null 2>&1 || true
  rm -rf "$scan_dir" "$scan_list" "$scan_tar"
}
trap cleanup EXIT HUP INT TERM

echo "Checking shell scripts with ShellCheck 0.11.0"
# Word splitting is intentional: find emits repository-controlled paths and
# ShellCheck expects each file as a separate argument.
# shellcheck disable=SC2046
docker run --rm \
  --volume "$ROOT:/mnt:ro" \
  --workdir /mnt \
  --entrypoint shellcheck \
  "$SHELLCHECK_IMAGE" \
  $(find scripts -type f -name '*.sh' -print | sort)

echo "Checking Dockerfiles with Hadolint 2.14.0"
for dockerfile in Dockerfile Dockerfile.backup Dockerfile.minio \
  Dockerfile.postgis Dockerfile.socket-proxy \
  android/Dockerfile e2e/Dockerfile ops/external-boundaries/Dockerfile; do
  docker run --rm --interactive "$HADOLINT_IMAGE" \
    hadolint --failure-threshold warning - <"$dockerfile"
done

echo "Checking the GitHub and Gitea Actions workflows with actionlint 1.7.12"
docker run --rm \
  --volume "$ROOT:/repo:ro" \
  --workdir /repo \
  "$ACTIONLINT_IMAGE" \
  -config-file .github/actionlint.yaml \
  .github/workflows/quality.yml \
  .gitea/workflows/quality.yml

echo "Checking crash dumps are excluded from the Docker build context"
grep -Fx 'core' .dockerignore >/dev/null
grep -Fx 'core.*' .dockerignore >/dev/null

echo "Checking local Gitea runner state is excluded from Git and Docker contexts"
grep -Fx '/.runner' .gitignore >/dev/null
grep -Fx '/act_runner' .gitignore >/dev/null
grep -Fx '/act_runner-data/' .gitignore >/dev/null
grep -Fx '/.runner' .dockerignore >/dev/null
grep -Fx '/act_runner' .dockerignore >/dev/null
grep -Fx '/act_runner-data/' .dockerignore >/dev/null

echo "Checking production environment initialization and validation"
edge_env="$scan_dir/.env.edge"
./scripts/init-edge-env.sh help.test staging.help.test "$edge_env" >/dev/null
test "$(stat -c '%a' "$edge_env")" = 600
./scripts/validate-edge-env.sh "$edge_env" >/dev/null
if ./scripts/init-edge-env.sh help.test staging.help.test "$edge_env" >/dev/null 2>&1; then
  echo "Edge environment initializer overwrote an existing file." >&2
  exit 1
fi
staging_env="$scan_dir/.env.staging"
if ./scripts/init-staging-env.sh staging.help.test \
  "$scan_dir/.env.staging.missing-codex" >/dev/null 2>&1; then
  echo "Staging environment initializer accepted a missing Codex session ID." >&2
  exit 1
fi
STAGING_CODEX_SESSION_ID=00000000-0000-0000-0000-000000000001 \
STAGING_GOOGLE_OAUTH_CLIENT_ID=quality-staging-client \
STAGING_GOOGLE_OAUTH_CLIENT_SECRET=quality-staging-secret \
  ./scripts/init-staging-env.sh staging.help.test "$staging_env" >/dev/null
test "$(stat -c '%a' "$staging_env")" = 600
grep -Fx 'DEPLOYMENT_ENV=development' "$staging_env" >/dev/null
grep -Fx 'COMPOSE_PROJECT_NAME=who_need_help_staging' "$staging_env" >/dev/null
grep -Fx 'APP_TOPOLOGY=compact' "$staging_env" >/dev/null
grep -Fx 'DATABASE_MODE=container' "$staging_env" >/dev/null
grep -Fx 'PUBLIC_EDGE_ENABLED=true' "$staging_env" >/dev/null
grep -Fx 'PUBLIC_UPSTREAM_NAME=who-need-help-staging' "$staging_env" >/dev/null
grep -Fx 'PHX_HOST=staging.help.test' "$staging_env" >/dev/null
grep -Fx 'PHX_SCHEME=https' "$staging_env" >/dev/null
grep -Fx 'PHX_URL_PORT=443' "$staging_env" >/dev/null
grep -Fx 'EMAIL_DELIVERY_PROVIDER=smtp' "$staging_env" >/dev/null
grep -Fx 'SMTP_RELAY=mailpit' "$staging_env" >/dev/null
grep -Fx 'EMAIL_FROM_NAME="Who Need Help Staging"' "$staging_env" >/dev/null
grep -Fx 'GOOGLE_OAUTH_CLIENT_ID=quality-staging-client' "$staging_env" >/dev/null
"$ROOT/scripts/compose.sh" "$staging_env" config --quiet
if STAGING_CODEX_SESSION_ID=00000000-0000-0000-0000-000000000001 \
  STAGING_GOOGLE_OAUTH_CLIENT_ID=quality-staging-client \
  ./scripts/init-staging-env.sh staging.help.test \
    "$scan_dir/.env.staging.partial-google" >/dev/null 2>&1; then
  echo "Staging environment initializer accepted partial Google OAuth credentials." >&2
  exit 1
fi
if STAGING_CODEX_SESSION_ID=00000000-0000-0000-0000-000000000001 \
  ./scripts/init-staging-env.sh staging.help.test "$staging_env" >/dev/null 2>&1; then
  echo "Staging environment initializer overwrote an existing file." >&2
  exit 1
fi
production_env="$scan_dir/.env.production"
missing_codex_env="$scan_dir/.env.production.missing-codex"
if PRODUCTION_TRAEFIK_TRUSTED_IPS=172.20.0.1/32 \
  PRODUCTION_SMTP_RELAY=smtp.help.test \
  PRODUCTION_SMTP_PORT=587 \
  PRODUCTION_SMTP_USERNAME=quality-user \
  PRODUCTION_SMTP_PASSWORD=quality-password \
  PRODUCTION_SMTP_AUTH=always \
  PRODUCTION_SMTP_TLS=always \
  PRODUCTION_SMTP_SSL=false \
  PRODUCTION_EMAIL_FROM_ADDRESS=contact@help.test \
  ./scripts/init-production-env.sh help.test "$missing_codex_env" >/dev/null 2>&1; then
  echo "Production environment initializer accepted a missing Codex session ID." >&2
  exit 1
fi
PRODUCTION_TRAEFIK_TRUSTED_IPS=172.20.0.1/32 \
PRODUCTION_SMTP_RELAY=smtp.help.test \
PRODUCTION_SMTP_PORT=587 \
PRODUCTION_SMTP_USERNAME=quality-user \
PRODUCTION_SMTP_PASSWORD=quality-password \
PRODUCTION_SMTP_AUTH=always \
PRODUCTION_SMTP_TLS=always \
PRODUCTION_SMTP_SSL=false \
PRODUCTION_EMAIL_FROM_ADDRESS=contact@help.test \
PRODUCTION_CODEX_SESSION_ID=00000000-0000-0000-0000-000000000001 \
  ./scripts/init-production-env.sh help.test "$production_env" >/dev/null
test "$(stat -c '%a' "$production_env")" = 600
./scripts/validate-production-env.sh "$production_env" help.test >/dev/null
api_production_env="$scan_dir/.env.production.unisender-go"
PRODUCTION_EMAIL_DELIVERY_PROVIDER=unisender_go \
PRODUCTION_UNISENDER_GO_API_KEY=quality-unisender-go-api-key \
PRODUCTION_EMAIL_FROM_ADDRESS=contact@help.test \
PRODUCTION_CODEX_SESSION_ID=00000000-0000-0000-0000-000000000001 \
  ./scripts/init-production-env.sh help.test "$api_production_env" >/dev/null
./scripts/validate-production-env.sh "$api_production_env" help.test >/dev/null
grep -Fx 'EMAIL_DELIVERY_PROVIDER=unisender_go' "$api_production_env" >/dev/null
grep -Fx 'UNISENDER_GO_SKIP_UNSUBSCRIBE=false' "$api_production_env" >/dev/null
api_override_env="$scan_dir/.env.production.unisender-go-skip-unsubscribe"
PRODUCTION_EMAIL_DELIVERY_PROVIDER=unisender_go \
PRODUCTION_UNISENDER_GO_API_KEY=quality-unisender-go-api-key \
PRODUCTION_UNISENDER_GO_SKIP_UNSUBSCRIBE=true \
PRODUCTION_EMAIL_FROM_ADDRESS=contact@help.test \
PRODUCTION_CODEX_SESSION_ID=00000000-0000-0000-0000-000000000001 \
  ./scripts/init-production-env.sh help.test "$api_override_env" >/dev/null
./scripts/validate-production-env.sh "$api_override_env" help.test >/dev/null
grep -Fx 'UNISENDER_GO_SKIP_UNSUBSCRIBE=true' "$api_override_env" >/dev/null
if PRODUCTION_EMAIL_DELIVERY_PROVIDER=unisender_go \
  PRODUCTION_CODEX_SESSION_ID=00000000-0000-0000-0000-000000000001 \
  ./scripts/init-production-env.sh \
  help.test "$scan_dir/.env.production.missing-api-key" >/dev/null 2>&1; then
  echo "Production initializer accepted UniSender Go without an API key." >&2
  exit 1
fi
invalid_api_url_env="$scan_dir/.env.production.invalid-api-url"
cp "$api_production_env" "$invalid_api_url_env"
chmod 600 "$invalid_api_url_env"
sed -i \
  's#^UNISENDER_GO_BASE_URL=.*#UNISENDER_GO_BASE_URL=http://goapi.example.test/v1#' \
  "$invalid_api_url_env"
if ./scripts/validate-production-env.sh \
  "$invalid_api_url_env" help.test >/dev/null 2>&1; then
  echo "Production validator accepted a non-HTTPS UniSender Go API URL." >&2
  exit 1
fi
placeholder_codex_env="$scan_dir/.env.production.placeholder-codex"
cp "$production_env" "$placeholder_codex_env"
chmod 600 "$placeholder_codex_env"
sed -i \
  's/^CODEX_SESSION_ID=.*/CODEX_SESSION_ID=copy-the-main-local-codex-session-id/' \
  "$placeholder_codex_env"
if ./scripts/validate-production-env.sh \
  "$placeholder_codex_env" help.test >/dev/null 2>&1; then
  echo "Production environment validator accepted the template Codex session ID." >&2
  exit 1
fi
external_production_env="$scan_dir/.env.production.external-db"
PRODUCTION_DATABASE_MODE=external \
PRODUCTION_DATABASE_URL=ecto://quality:external-password@database.internal/who_need_help \
PRODUCTION_SMTP_RELAY=smtp.help.test \
PRODUCTION_SMTP_PORT=587 \
PRODUCTION_SMTP_USERNAME=quality-user \
PRODUCTION_SMTP_PASSWORD=quality-password \
PRODUCTION_SMTP_AUTH=always \
PRODUCTION_SMTP_TLS=always \
PRODUCTION_SMTP_SSL=false \
PRODUCTION_EMAIL_FROM_ADDRESS=contact@help.test \
PRODUCTION_CODEX_SESSION_ID=00000000-0000-0000-0000-000000000001 \
  ./scripts/init-production-env.sh help.test "$external_production_env" >/dev/null
./scripts/validate-production-env.sh "$external_production_env" help.test >/dev/null
external_socket_production_env="$scan_dir/.env.production.external-db-socket"
PRODUCTION_DATABASE_MODE=external \
PRODUCTION_DATABASE_URL=ecto://quality:external-password@localhost/who_need_help \
PRODUCTION_DATABASE_SOCKET_DIR=/var/run/postgresql \
PRODUCTION_SMTP_RELAY=smtp.help.test \
PRODUCTION_SMTP_PORT=587 \
PRODUCTION_SMTP_USERNAME=quality-user \
PRODUCTION_SMTP_PASSWORD=quality-password \
PRODUCTION_SMTP_AUTH=always \
PRODUCTION_SMTP_TLS=always \
PRODUCTION_SMTP_SSL=false \
PRODUCTION_EMAIL_FROM_ADDRESS=contact@help.test \
PRODUCTION_CODEX_SESSION_ID=00000000-0000-0000-0000-000000000001 \
  ./scripts/init-production-env.sh help.test "$external_socket_production_env" >/dev/null
./scripts/validate-production-env.sh \
  "$external_socket_production_env" help.test >/dev/null
if PRODUCTION_DATABASE_MODE=external \
  PRODUCTION_DATABASE_URL=ecto://quality:external-password@localhost/who_need_help \
  PRODUCTION_DATABASE_SOCKET_DIR=relative/socket \
  PRODUCTION_CODEX_SESSION_ID=00000000-0000-0000-0000-000000000001 \
  ./scripts/init-production-env.sh \
  help.test "$scan_dir/.env.production.invalid-socket" >/dev/null 2>&1; then
  echo "Production initializer accepted a relative database socket path." >&2
  exit 1
fi
if PRODUCTION_DATABASE_SOCKET_DIR=/var/run/postgresql \
  PRODUCTION_CODEX_SESSION_ID=00000000-0000-0000-0000-000000000001 \
  ./scripts/init-production-env.sh \
  help.test "$scan_dir/.env.production.container-socket" >/dev/null 2>&1; then
  echo "Production initializer accepted a host socket in container database mode." >&2
  exit 1
fi
external_split_production_env="$scan_dir/.env.production.external-db-split"
PRODUCTION_APP_TOPOLOGY=split \
PRODUCTION_DATABASE_MODE=external \
PRODUCTION_DATABASE_URL=ecto://quality:external-password@database.internal/who_need_help \
PRODUCTION_TRAEFIK_TRUSTED_IPS=172.20.0.1/32 \
PRODUCTION_SMTP_RELAY=smtp.help.test \
PRODUCTION_SMTP_PORT=587 \
PRODUCTION_SMTP_USERNAME=quality-user \
PRODUCTION_SMTP_PASSWORD=quality-password \
PRODUCTION_SMTP_AUTH=always \
PRODUCTION_SMTP_TLS=always \
PRODUCTION_SMTP_SSL=false \
PRODUCTION_EMAIL_FROM_ADDRESS=contact@help.test \
PRODUCTION_CODEX_SESSION_ID=00000000-0000-0000-0000-000000000001 \
  ./scripts/init-production-env.sh help.test "$external_split_production_env" >/dev/null
./scripts/validate-production-env.sh "$external_split_production_env" help.test >/dev/null
invalid_external_env="$scan_dir/.env.production.invalid-external-db"
cp "$external_production_env" "$invalid_external_env"
chmod 600 "$invalid_external_env"
sed -i 's#^DATABASE_URL=.*#DATABASE_URL=ecto://quality:external-password@db/who_need_help#' \
  "$invalid_external_env"
if ./scripts/validate-production-env.sh \
  "$invalid_external_env" help.test >/dev/null 2>&1; then
  echo "Production environment validator accepted the Compose db host in external mode." >&2
  exit 1
fi
partial_google_env="$scan_dir/.env.production.partial-google"
cp "$production_env" "$partial_google_env"
chmod 600 "$partial_google_env"
sed -i 's/^GOOGLE_OAUTH_CLIENT_ID=.*/GOOGLE_OAUTH_CLIENT_ID=quality-client/' \
  "$partial_google_env"
if ./scripts/validate-production-env.sh \
  "$partial_google_env" help.test >/dev/null 2>&1; then
  echo "Production environment validator accepted partial Google OAuth credentials." >&2
  exit 1
fi
if ./scripts/init-production-env.sh help.test "$production_env" >/dev/null 2>&1; then
  echo "Production environment initializer overwrote an existing file." >&2
  exit 1
fi
incomplete_production_env="$scan_dir/.env.production.incomplete"
PRODUCTION_CODEX_SESSION_ID=00000000-0000-0000-0000-000000000001 \
  ./scripts/init-production-env.sh help.test "$incomplete_production_env" >/dev/null
if ./scripts/validate-production-env.sh \
  "$incomplete_production_env" help.test >/dev/null 2>&1; then
  echo "Production environment validator accepted unresolved deployment inputs." >&2
  exit 1
fi

echo "Rendering every Docker Compose profile"
CADDY_IMAGE=who-need-help:caddy-local \
docker compose --project-directory "$ROOT" --env-file "$edge_env" \
  --file compose.edge.yaml config --format json |
  jq --exit-status '
    .services.edge.image == "who-need-help:caddy-local" and
    .services.edge.user == "1000:1000" and
    .services.edge.read_only == true and
    .services.edge.cap_drop == ["ALL"] and
    .services.edge.cap_add == ["NET_BIND_SERVICE"] and
    .services.edge.security_opt == ["no-new-privileges:true"] and
    (.services.edge.tmpfs | index("/tmp") != null) and
    (.services.edge.ports | map(select(.target == 80 and .published == "80" and .protocol == "tcp")) | length) == 1 and
    (.services.edge.ports | map(select(.target == 443 and .published == "443" and .protocol == "tcp")) | length) == 1 and
    (.services.edge.ports | map(select(.target == 443 and .published == "443" and .protocol == "udp")) | length) == 1 and
    .networks.public_edge.name == "who_need_help_public_edge"
  ' >/dev/null
./scripts/compose.sh .env.example config --quiet
./scripts/compose.sh "$production_env" config --quiet
./scripts/compose.sh "$api_production_env" config --quiet
./scripts/compose.sh "$api_override_env" config --format json |
  jq --exit-status '
    .services.app.environment.UNISENDER_GO_SKIP_UNSUBSCRIBE == "true" and
    .services.migrate.environment.UNISENDER_GO_SKIP_UNSUBSCRIBE == "true"
  ' >/dev/null
./scripts/compose.sh "$external_production_env" config --quiet
./scripts/compose.sh "$external_socket_production_env" config --quiet
./scripts/compose.sh "$external_split_production_env" config --quiet
./scripts/compose.sh "$staging_env" config --format json |
  jq --exit-status '
    .services.app.networks.internal.interface_name == "eth0" and
    .services.app.networks.egress.interface_name == "eth1" and
    .services.app.networks.public_edge.interface_name == "eth2" and
    .services.app.networks.public_edge.aliases == ["who-need-help-staging"]
  ' >/dev/null
./scripts/compose.sh .env.example config --format json |
  jq --exit-status '
    . as $root
    | [$root.services.migrate, $root.services.web, $root.services.worker]
    | all(
        .environment.ERL_ZFLAGS == "+Q 65536" and
        .environment.CLUSTER_INTERFACE == "eth0" and
        .read_only == true and
        .cap_drop == ["ALL"] and
        .security_opt == ["no-new-privileges:true"] and
        (.tmpfs | index("/tmp") != null)
      )
    and $root.services.web.environment.POOL_SIZE == "4"
    and $root.services.worker.environment.POOL_SIZE == "2"
    and $root.services.migrate.environment.POOL_SIZE == "2"
    and $root.services.worker.environment.OBAN_MAINTENANCE_CONCURRENCY == "2"
    and $root.services.worker.environment.OBAN_PUSH_CONCURRENCY == "1"
    and $root.services.web.deploy.replicas == 2
    and $root.services.worker.deploy.replicas == 2
    and ($root.services.proxy.networks | keys | sort) == ["docker-api", "edge", "ingress"]
    and ($root.services.web.networks | keys | sort) == ["egress", "ingress", "internal"]
    and ($root.services.worker.networks | keys | sort) == ["egress", "internal"]
    and ($root.services.migrate.networks | keys | sort) == ["egress", "internal"]
    and $root.services.web.networks.internal.interface_name == "eth0"
    and $root.services.web.networks.internal.aliases == ["cluster-web"]
    and $root.services.web.networks.ingress.interface_name == "eth1"
    and $root.services.web.networks.egress.interface_name == "eth2"
    and $root.services.web.networks.egress.gw_priority == 1
    and $root.services.worker.networks.internal.interface_name == "eth0"
    and $root.services.worker.networks.egress.interface_name == "eth1"
    and $root.services.worker.networks.egress.gw_priority == 1
    and ($root.services.db.networks | keys) == ["internal"]
    and $root.networks.ingress.internal == true
    and $root.networks.internal.internal == true
    and ($root.networks.egress.internal // false) == false
    and $root.services.db.security_opt == ["no-new-privileges:true"]
    and $root.services.proxy.ports[0].host_ip == "0.0.0.0"
    and $root.services.mailpit.ports[0].host_ip == "127.0.0.1"
  ' >/dev/null
./scripts/compose.sh "$production_env" config --format json |
  jq --exit-status '
    (.services | has("app")) and
    (.services | has("db")) and
    (.services | has("web") | not) and
    (.services | has("worker") | not) and
    (.services | has("proxy") | not) and
    (.services | has("docker-api-proxy") | not) and
    (.services | has("mailpit") | not) and
    .services.app.environment.APP_ROLE == "combined" and
    .services.app.environment.DNS_CLUSTER_QUERY == "ignore" and
    .services.app.environment.POOL_SIZE == "4" and
    .services.app.networks.internal.interface_name == "eth0" and
    .services.app.networks.egress.interface_name == "eth1" and
    .services.app.networks.public_edge.interface_name == "eth2" and
    .services.app.networks.public_edge.aliases == ["who-need-help-production"] and
    .networks.public_edge.external == true and
    .services.app.ports[0].host_ip == "127.0.0.1"
  ' >/dev/null
./scripts/compose.sh "$external_production_env" config --format json |
  jq --exit-status '
    (.services | has("app")) and
    (.services | has("db") | not) and
    (.services | has("web") | not) and
    (.services | has("worker") | not) and
    (.services | has("proxy") | not) and
    .services.app.networks.public_edge.interface_name == "eth2" and
    .services.app.networks.public_edge.aliases == ["who-need-help-production"]
  ' >/dev/null
./scripts/compose.sh "$external_socket_production_env" config --format json |
  jq --exit-status '
    (.services | has("app")) and
    (.services | has("db") | not) and
    .services.app.environment.DATABASE_SOCKET_DIR == "/var/run/postgresql" and
    .services.migrate.environment.DATABASE_SOCKET_DIR == "/var/run/postgresql" and
    (.services.app.volumes |
      any(
        .type == "bind" and
        .source == "/var/run/postgresql" and
        .target == "/var/run/postgresql" and
        .read_only == true
      )) and
    (.services.migrate.volumes |
      any(
        .type == "bind" and
        .source == "/var/run/postgresql" and
        .target == "/var/run/postgresql" and
        .read_only == true
      ))
  ' >/dev/null
./scripts/compose.sh "$external_socket_production_env" config --profiles |
  grep -Fx container-database >/dev/null
./scripts/compose.sh "$external_split_production_env" config --format json |
  jq --exit-status '
    (.services | has("db") | not) and
    (.services | has("app") | not) and
    (.services | has("web")) and
    (.services | has("worker")) and
    (.services | has("proxy")) and
    .services.web.networks.internal.interface_name == "eth0" and
    .services.web.networks.ingress.interface_name == "eth1" and
    .services.web.networks.egress.interface_name == "eth2" and
    .services.web.networks.public_edge.interface_name == "eth3" and
    .services.web.networks.public_edge.aliases == ["who-need-help-production"] and
    .services.web.deploy.replicas == 2 and
    .services.worker.deploy.replicas == 2
  ' >/dev/null
HTTP_BIND_ADDRESS=127.0.0.1 \
  ./scripts/compose.sh .env.example config --format json |
  jq --exit-status '
    .services.proxy.ports[0].host_ip == "127.0.0.1"
  ' >/dev/null
WEB_REPLICAS=1 WORKER_REPLICAS=1 \
  ./scripts/compose.sh .env.example config --format json |
  jq --exit-status '
    .services.web.deploy.replicas == 1 and
    .services.worker.deploy.replicas == 1
  ' >/dev/null
CPU_REPLAY_WEB_CPUS=1 \
CPU_REPLAY_WORKER_CPUS=1 \
CPU_REPLAY_WEB_SCHEDULERS=1 \
CPU_REPLAY_WORKER_SCHEDULERS=1 \
  docker compose --env-file .env.example \
  -f compose.yaml -f compose.cpu-replay.yaml config --quiet
PORTABILITY_IMAGE=who-need-help:portability-render \
  docker compose --env-file .env.example \
  -f compose.yaml -f compose.portability.yaml config --quiet
mkdir -p "$scan_dir/e2e-output"
E2E_OUTPUT_DIR="$scan_dir/e2e-output" docker compose --env-file .env.e2e.example \
  -f compose.yaml -f compose.e2e.yaml config --quiet
REHEARSAL_IMAGE=who-need-help:rehearsal-render \
  docker compose --env-file .env.e2e.example \
  -f compose.yaml -f compose.upgrade-rehearsal.yaml config --quiet
docker compose --env-file .env.load.example \
  -f compose.yaml -f compose.load.yaml config --quiet
test "$(
  docker compose --env-file .env.load.example \
    -f compose.yaml -f compose.load.yaml config --format json |
    jq -r '.services.db.command | join(" ")'
)" = "postgres -c shared_preload_libraries=pg_stat_statements -c compute_query_id=on"
mkdir -p "$scan_dir/observability-runtime/prometheus" \
  "$scan_dir/observability-runtime/grafana"
OBSERVABILITY_RUNTIME_DIR="$scan_dir/observability-runtime" \
  docker compose --env-file .env.load.example \
  -f compose.yaml -f compose.load.yaml -f compose.observability.yaml \
  --profile observability config --quiet
mkdir -p "$scan_dir/backup-runtime"
BACKUP_RUNTIME_DIR="$scan_dir/backup-runtime" \
BACKUP_HOST_UID="$(id -u)" \
BACKUP_HOST_GID="$(id -g)" \
  docker compose --env-file .env.load.example \
  -f compose.yaml -f compose.load.yaml -f compose.backup.yaml \
  --profile backup config --quiet
docker compose -p "$project" -f compose.quality.yaml config --quiet
mkdir -p "$scan_dir/external-boundary-output"
EXTERNAL_BOUNDARY_APP_IMAGE=who-need-help:boundary-render \
EXTERNAL_BOUNDARY_MOCK_IMAGE=who-need-help:boundary-mock-render \
EXTERNAL_BOUNDARY_OUTPUT_DIR="$scan_dir/external-boundary-output" \
EXTERNAL_BOUNDARY_HOST_UID="$(id -u)" \
EXTERNAL_BOUNDARY_HOST_GID="$(id -g)" \
EXTERNAL_OAUTH_CLIENT_ID=render-client \
EXTERNAL_OAUTH_CLIENT_SECRET=render-secret \
EXTERNAL_PUSH_BEARER_TOKEN=render-push-token \
EXTERNAL_METRICS_TOKEN=render-metrics-token \
EXTERNAL_POSTGRES_PASSWORD=render-database-secret \
EXTERNAL_DATABASE_URL=ecto://boundary:render-database-secret@boundary-db/boundary \
EXTERNAL_SECRET_KEY_BASE=render-secret-key-base \
EXTERNAL_HANDOVER_SECRET=render-handover-secret \
  docker compose -f compose.external-boundaries.yaml config --quiet

echo "Validating local observability configuration"
sed \
  -e 's/__SCRAPE_INTERVAL__/1s/g' \
  -e 's/__EVALUATION_INTERVAL__/1s/g' \
  ops/observability/prometheus.template.yml \
  >"$scan_dir/observability-runtime/prometheus/prometheus.yml"
printf '%s' 'isolated-quality-metrics-token' \
  >"$scan_dir/observability-runtime/prometheus/metrics-token"
printf '%s\n' '[]' \
  >"$scan_dir/observability-runtime/prometheus/web-targets.json"
printf '%s\n' '[]' \
  >"$scan_dir/observability-runtime/prometheus/worker-targets.json"
docker run --rm \
  --user 0:0 \
  --volume "$scan_dir/observability-runtime/prometheus:/runtime:ro" \
  --volume "$ROOT/ops/observability/rules.yml:/etc/prometheus/rules.yml:ro" \
  --entrypoint /bin/promtool \
  "$PROMETHEUS_IMAGE" check config /runtime/prometheus.yml
docker run --rm \
  --user 0:0 \
  --volume "$ROOT/ops/observability/alertmanager.yml:/etc/alertmanager/alertmanager.yml:ro" \
  --entrypoint /bin/amtool \
  "$ALERTMANAGER_IMAGE" check-config /etc/alertmanager/alertmanager.yml
docker run --rm \
  --volume "$ROOT/scripts/alert-receiver.py:/src/alert-receiver.py:ro" \
  "$PYTHON_IMAGE" python -c \
  'import py_compile; py_compile.compile("/src/alert-receiver.py", cfile="/tmp/alert-receiver.pyc", doraise=True)'
docker run --rm \
  --volume "$ROOT/ops/external-boundaries/mock_server.py:/src/mock_server.py:ro" \
  "$PYTHON_IMAGE" python -c \
  'import py_compile; py_compile.compile("/src/mock_server.py", cfile="/tmp/mock_server.pyc", doraise=True)'
jq --exit-status \
  'type == "object" and .uid == "wnh-overview" and (.panels | length) == 10' \
  ops/observability/grafana/dashboards/who-need-help-overview.json \
  >/dev/null

echo "Linting the Helm chart"
"$ROOT/scripts/bootstrap-kubernetes-tools.sh" >/dev/null
"$ROOT/.tools/bin/helm" lint \
  --values "$ROOT/deploy/helm/who-need-help/values-kind.yaml" \
  "$ROOT/deploy/helm/who-need-help"

echo "Scanning only tracked and non-ignored source files"
# The single-quoted program must expand $path inside the child shell.
# shellcheck disable=SC2016
git ls-files --cached --others --exclude-standard -z |
  xargs -0 -r sh -c '
    for path do
      if [ -f "$path" ]; then
        printf "%s\0" "$path"
      fi
    done
  ' sh >"$scan_list"
tar --null --no-recursion --files-from="$scan_list" --create --file="$scan_tar"
tar --extract --file="$scan_tar" --directory "$scan_dir"
"$ROOT/.tools/bin/helm" template who-need-help \
  --values "$ROOT/deploy/helm/who-need-help/values-kind.yaml" \
  "$ROOT/deploy/helm/who-need-help" \
  >"$scan_dir/rendered-helm.yaml"
"$ROOT/.tools/bin/helm" template who-need-help \
  --values "$ROOT/deploy/helm/who-need-help/values-kind.yaml" \
  --set app.unisenderGoSkipUnsubscribe=true \
  "$ROOT/deploy/helm/who-need-help" \
  >"$scan_dir/rendered-helm-unisender-override.yaml"
test "$(
  grep -c 'name: ERL_ZFLAGS' "$scan_dir/rendered-helm.yaml"
)" -eq 5
test "$(
  grep -c 'value: "+Q 65536"' "$scan_dir/rendered-helm.yaml"
)" -eq 5
test "$(
  grep -c 'name: UNISENDER_GO_SKIP_UNSUBSCRIBE' "$scan_dir/rendered-helm.yaml"
)" -eq 5
test "$(
  grep -c 'name: UNISENDER_GO_SKIP_UNSUBSCRIBE' \
    "$scan_dir/rendered-helm-unisender-override.yaml"
)" -eq 5
test "$(
  grep -A1 'name: UNISENDER_GO_SKIP_UNSUBSCRIBE' \
    "$scan_dir/rendered-helm-unisender-override.yaml" |
    grep -c 'value: "true"'
)" -eq 5
test "$(
  grep -c '^kind: NetworkPolicy$' "$scan_dir/rendered-helm.yaml"
)" -eq 1
mkdir -p "$ROOT/.tools/trivy-cache"
docker run --rm \
  --volume "$scan_dir:/scan:ro" \
  --volume "$ROOT/.tools/trivy-cache:/root/.cache/trivy" \
  "$TRIVY_IMAGE" fs \
  --scanners misconfig,secret \
  --severity HIGH,CRITICAL \
  --exit-code 1 \
  /scan

echo "Building, smoke-testing, and scanning pinned runtime infrastructure images"
docker build --tag "$socket_proxy_image" --file Dockerfile.socket-proxy .
docker build --tag "$postgis_image" --file Dockerfile.postgis .
docker build --tag "$caddy_image" --file Dockerfile.caddy .
test "$(docker image inspect --format '{{.Config.User}}' "$socket_proxy_image")" = "haproxy"
test "$(docker image inspect --format '{{.Config.User}}' "$postgis_image")" = "postgres"
test "$(docker image inspect --format '{{.Config.User}}' "$caddy_image")" = "1000:1000"
docker run --rm "$caddy_image" version | grep -F 'v2.11.4' >/dev/null
docker run --rm --entrypoint sh "$postgis_image" -euc '
  test ! -e /usr/local/bin/gosu
  test "$(id -u)" = 70
'

docker run --detach \
  --name "$socket_proxy_container" \
  --read-only \
  --tmpfs /run:uid=99,gid=99,mode=0755 \
  --tmpfs /tmp \
  --cap-drop ALL \
  --group-add "$(stat -c '%g' /var/run/docker.sock)" \
  --security-opt no-new-privileges \
  --env CONTAINERS=1 \
  --env EVENTS=1 \
  --env INFO=1 \
  --env NETWORKS=1 \
  --env PING=1 \
  --env POST=0 \
  --env VERSION=1 \
  --volume /var/run/docker.sock:/var/run/docker.sock:ro \
  --publish 127.0.0.1::2375 \
  "$socket_proxy_image" >/dev/null
socket_proxy_port=$(
  docker port "$socket_proxy_container" 2375/tcp |
    sed -n 's/.*://p' |
    head -n 1
)
test -n "$socket_proxy_port"
socket_proxy_ready=false
for _attempt in $(seq 1 30); do
  if curl --fail --silent --show-error \
    "http://127.0.0.1:$socket_proxy_port/_ping" >/dev/null; then
    socket_proxy_ready=true
    break
  fi
  sleep 1
done
test "$socket_proxy_ready" = true
test "$(
  curl --silent --output /dev/null --write-out '%{http_code}' \
    "http://127.0.0.1:$socket_proxy_port/containers/json"
)" = "200"
test "$(
  curl --silent --output /dev/null --write-out '%{http_code}' \
    --request POST \
    "http://127.0.0.1:$socket_proxy_port/containers/create"
)" = "403"
docker rm --force "$socket_proxy_container" >/dev/null

for image in \
  "$socket_proxy_image" \
  "$postgis_image" \
  "traefik:v3.7.8@sha256:4299bbed850421258fc5448c2e0e6ad350981d4d335a68de11b92448aedbefe5" \
  "$caddy_image" \
  "axllent/mailpit:v1.30.4@sha256:5a49a77c5bdbe7c5474450b4f46348d09949df3695257729c93a30369382d4f6"; do
  docker run --rm \
    --volume /var/run/docker.sock:/var/run/docker.sock \
    --volume "$ROOT/.tools/trivy-cache:/root/.cache/trivy" \
    "$TRIVY_IMAGE" image \
    --scanners vuln \
    --severity HIGH,CRITICAL \
    --ignore-unfixed \
    --exit-code 1 \
    "$image"
done

echo "Building the pinned quality image and cached Dialyzer PLTs"
docker build --target quality --tag "$quality_image" .

echo "Running Elixir format, compiler, xref, Credo, Sobelow, Dialyzer, and Hex audit"
docker run --rm "$quality_image" sh -euc '
  mix format --check-formatted
  mix compile --force --warnings-as-errors
  mix xref graph --label compile-connected --fail-above 0
  mix credo --strict --min-priority high
  mix sobelow --exit --strict --private --skip
  mix dialyzer
  mix hex.audit
'

echo "Starting an isolated PostgreSQL/PostGIS volume for the Phoenix suite"
$compose up --detach --wait db
docker run --rm \
  --network "${project}_internal" \
  --env MIX_ENV=test \
  --env DB_HOST=db \
  --env "DB_USER=$QUALITY_POSTGRES_USER" \
  --env "DB_PASSWORD=$QUALITY_POSTGRES_PASSWORD" \
  --env TEST_POOL_SIZE=10 \
  "$quality_image" \
  mix test

echo "Auditing locked browser dependencies"
docker build --target node_deps --tag "$assets_image" .
docker run --rm "$assets_image" npm audit --audit-level=high
docker build --tag "$e2e_image" e2e
docker run --rm "$e2e_image" npm audit --audit-level=high

echo "Building and scanning the pinned non-root backup tool image"
docker build --tag "$backup_image" --file Dockerfile.backup .
test "$(docker image inspect --format '{{.Config.User}}' "$backup_image")" = \
  "10001:10001"
backup_versions=$(docker run --rm \
  --user 10001:10001 \
  --read-only \
  --tmpfs /tmp \
  "$backup_image" \
  sh -euc 'restic version; pg_dump --version; test "$(id -u)" = 10001')
printf '%s\n' "$backup_versions"
printf '%s\n' "$backup_versions" |
  grep -F 'restic 0.19.1 compiled with go1.26.5' >/dev/null
printf '%s\n' "$backup_versions" |
  grep -F 'pg_dump (PostgreSQL) 18.4' >/dev/null
docker run --rm \
  --volume /var/run/docker.sock:/var/run/docker.sock \
  --volume "$ROOT/.tools/trivy-cache:/root/.cache/trivy" \
  "$TRIVY_IMAGE" image \
  --scanners vuln \
  --severity HIGH,CRITICAL \
  --ignore-unfixed \
  --exit-code 1 \
  "$backup_image"

echo "Building and scanning the pinned non-root MinIO server and client images"
docker build --target server --tag "$minio_image" --file Dockerfile.minio .
docker build --target client --tag "$mc_image" --file Dockerfile.minio .
test "$(docker image inspect --format '{{.Config.User}}' "$minio_image")" = \
  "10001:10001"
test "$(docker image inspect --format '{{.Config.User}}' "$mc_image")" = \
  "10001:10001"
minio_version=$(docker run --rm \
  --user 10001:10001 \
  --read-only \
  --tmpfs /tmp \
  "$minio_image" \
  --version)
mc_version=$(docker run --rm \
  --user 10001:10001 \
  --read-only \
  --tmpfs /tmp \
  "$mc_image" \
  --version)
printf '%s\n' "$minio_version"
printf '%s\n' "$mc_version"
printf '%s\n' "$minio_version" |
  grep -F 'RELEASE.2025-10-15T17-29-55Z' >/dev/null
printf '%s\n' "$minio_version" |
  grep -F 'commit-id=9e49d5e7a648f00e26f2246f4dc28e6b07f8c84a' >/dev/null
printf '%s\n' "$minio_version" |
  grep -F 'Runtime: go1.26.5 linux/' >/dev/null
printf '%s\n' "$mc_version" |
  grep -F 'RELEASE.2025-08-13T08-35-41Z' >/dev/null
printf '%s\n' "$mc_version" |
  grep -F 'commit-id=7394ce0dd2a80935aded936b09fa12cbb3cb8096' >/dev/null
printf '%s\n' "$mc_version" |
  grep -F 'Runtime: go1.26.5 linux/' >/dev/null
for image in "$minio_image" "$mc_image"; do
  docker run --rm \
    --volume /var/run/docker.sock:/var/run/docker.sock \
    --volume "$ROOT/.tools/trivy-cache:/root/.cache/trivy" \
    "$TRIVY_IMAGE" image \
    --scanners vuln \
    --severity HIGH,CRITICAL \
    --ignore-unfixed \
    --exit-code 1 \
    "$image"
done

echo "Building and scanning the pinned non-root external-boundary mock image"
docker build \
  --tag "$boundary_mock_image" \
  --file ops/external-boundaries/Dockerfile \
  ops/external-boundaries
test "$(docker image inspect --format '{{.Config.User}}' "$boundary_mock_image")" = \
  "10001:10001"
docker run --rm \
  --volume /var/run/docker.sock:/var/run/docker.sock \
  --volume "$ROOT/.tools/trivy-cache:/root/.cache/trivy" \
  "$TRIVY_IMAGE" image \
  --scanners vuln \
  --severity HIGH,CRITICAL \
  --ignore-unfixed \
  --exit-code 1 \
  "$boundary_mock_image"

echo "Building and scanning the production release image"
docker build --target release --tag "$release_image" .
docker run --rm \
  --volume /var/run/docker.sock:/var/run/docker.sock \
  --volume "$ROOT/.tools/trivy-cache:/root/.cache/trivy" \
  "$TRIVY_IMAGE" image \
  --scanners vuln \
  --severity HIGH,CRITICAL \
  --ignore-unfixed \
  --exit-code 1 \
  "$release_image"

echo "All isolated quality and security gates passed."
