#!/usr/bin/env bash
#
# tools/podman-check.sh — gate estático do runtime podman (chamado pelo `make check`).
#
# Não precisa de podman instalado: valida o **contrato** entre os dois arquivos Compose e a
# decisão de SELinux do host. Serve para o dia em que alguém adicionar um serviço com
# `user:` e esquecer o `userns_mode: keep-id` (o sintoma seria `Permission denied` no bind
# mount, longe da causa) ou expuser uma porta no override.
#
# Invariantes:
#   1. todo serviço do `docker-compose.yml` com `user:` tem `userns_mode: keep-id` no override;
#   2. todo serviço do override desliga o label SELinux (`label=disable`);
#   3. `postgres` **não** tem `userns_mode` (o entrypoint roda como root no namespace);
#   4. o override não publica portas nem altera redes (a postura de segurança não muda);
#   5. o bind mount do repo/storage usa `${MOUNT_LABEL-:Z}` (permite desligar o relabel);
#   6. quando `CONTAINER_RUNTIME=podman`, o socket do usuário está ativo e o Compose mesclado
#      valida.
set -Eeuo pipefail

ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "$ROOT"

BASE="docker-compose.yml"
OVER="docker-compose.podman.yml"
errors=0
fail() { printf 'podman-check: %s\n' "$*" >&2; errors=$((errors + 1)); }

[ -f "$BASE" ] || { echo "podman-check: ${BASE} ausente." >&2; exit 1; }
[ -f "$OVER" ] || { echo "podman-check: ${OVER} ausente (sem override não há suporte a podman)." >&2; exit 1; }

service_block() { # service_block <arquivo> <serviço>
    sed -n "/^  ${2}:\$/,/^  [a-z0-9-]*:\$/p" "$1"
}

# ── 1. serviços com `user:` exigem keep-id ─────────────────────────────────────────
mapfile -t USER_SERVICES < <(
    awk '
        /^  [a-z0-9-]+:$/ { svc = substr($0, 3); sub(/:$/, "", svc); next }
        /^  [a-z]/        { svc = "" }
        svc != "" && /^    user:/ { print svc }
    ' "$BASE" | sort -u
)

[ "${#USER_SERVICES[@]}" -gt 0 ] || fail "nenhum serviço com 'user:' em ${BASE} — o gate perderia o sentido."

for svc in "${USER_SERVICES[@]}"; do
    block="$(service_block "$OVER" "$svc")"
    [ -n "$block" ] || { fail "${OVER}: serviço '${svc}' (usa user:) não está no override"; continue; }
    grep -qE '^    userns_mode: keep-id$' <<<"$block" \
        || fail "${OVER}: '${svc}' usa user: mas não tem 'userns_mode: keep-id' (escrita no bind mount falharia)"
done

# ── 2. todo serviço do override desliga o label SELinux ────────────────────────────
mapfile -t OVER_SERVICES < <(
    awk '/^  [a-z0-9-]+:$/ { svc = substr($0, 3); sub(/:$/, "", svc); print svc }' "$OVER" | sort -u
)
[ "${#OVER_SERVICES[@]}" -gt 0 ] || fail "${OVER} não declara serviços."

for svc in "${OVER_SERVICES[@]}"; do
    service_block "$OVER" "$svc" | grep -q 'label=disable' \
        || fail "${OVER}: '${svc}' não desliga o label SELinux (bind mounts do repo seriam negados)"
done

# ── 3. postgres: sem userns_mode ───────────────────────────────────────────────────
if grep -qE '^    userns_mode:' <<<"$(service_block "$OVER" postgres)"; then
    fail "${OVER}: 'postgres' não pode usar userns_mode — o entrypoint roda como root no namespace e faz chown do PGDATA"
fi

# ── 4. override não muda postura (portas/redes) ────────────────────────────────────
if grep -qE '^    (ports|expose|networks):' "$OVER"; then
    fail "${OVER}: não publique portas nem declare redes — o override é só de runtime (uid/SELinux)"
fi

# ── 5. bind mount parametrizado ────────────────────────────────────────────────────
grep -q 'MOUNT_LABEL' "$BASE" \
    || fail "${BASE}: bind mount do repo/storage sem \${MOUNT_LABEL-:Z} — o podman não conseguiria desligar o relabel"

# ── 6. runtime podman ativo: socket + config válido ────────────────────────────────
env_value() {
    grep -E "^${1}=" .env 2>/dev/null | head -1 | cut -d= -f2- \
        | sed -E 's/^"(.*)"$/\1/; s/^'"'"'(.*)'"'"'$/\1/' || true
}
RUNTIME_V="${CONTAINER_RUNTIME:-$(env_value CONTAINER_RUNTIME)}"
if [ "$RUNTIME_V" = "podman" ]; then
    if ! systemctl --user is-active --quiet podman.socket 2>/dev/null; then
        fail "CONTAINER_RUNTIME=podman mas podman.socket está inativo (rode 'make podman-prepare')"
    elif ! PODMAN_COMPOSE_WARNING_LOGS=false podman compose -p "$(bash "$ROOT/tools/project-name.sh" 2>/dev/null)" \
        --env-file .env -f "$BASE" -f "$OVER" config -q 2>/dev/null; then
        fail "o Compose mesclado não valida sob podman (docker-compose.yml + ${OVER})"
    fi
fi

if [ "$errors" -gt 0 ]; then
    printf 'podman-check: %d problema(s).\n' "$errors" >&2
    exit 1
fi

printf 'podman-check: OK — %d serviço(s) com user: cobertos pelo keep-id · label=disable em %d · postura intacta\n' \
    "${#USER_SERVICES[@]}" "${#OVER_SERVICES[@]}"
