#!/usr/bin/env bash
#
# Provisions the test database and the non-superuser test role.
#
# Why this exists: PostgreSQL lets superusers bypass FORCE ROW LEVEL SECURITY,
# so an RLS test run as one passes regardless of the policy (plan chunk2,
# experiment 1). The suite therefore connects as `3eegitim_test`, which must
# exist before the first test runs — including on a fresh CI agent.
#
# Idempotent: safe to run repeatedly. Chunk2's role migration is the canonical
# owner of the role set and skips roles that already exist; this script only
# gets the environment far enough to run the suite.
#
# Usage:
#   deployment/scripts/setup-test-database.sh
#
# Reads from .env.testing (see .env.testing.example). No secret is written
# into this file or into any file that is committed.

# ⚠ Bu script `composer test`in ILK adimidir — elle calistirilan bir kurulum
# adimi degil. Idempotent olmasi bunu mumkun kiliyor: rol varsa sifresi
# guncellenir, veritabani varsa dokunulmaz.
#
# Gerekce (26.07.2026): PostgreSQL 18 yukseltmesinde cluster sifirdan kuruldu ve
# CI 13 testle dustu — test rolu ve veritabani yoktu, cunku bu script yalnizca
# elle kosuluyordu. Kendi veritabanini kuramayan bir build, ortam her
# yenilendiginde kirilir. Ayrica script sonundaki "test rolu superuser degil"
# dogrulamasi boylece HER kosumda calisir; ayni gun temiz kurulumda uygulama
# rolunun superuser dogdugu bir kusur bulundu (bkz. docs/issues.md).


set -euo pipefail

ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
ENV_FILE="${ROOT_DIR}/.env.testing"

if [[ ! -f "${ENV_FILE}" ]]; then
    echo "Missing ${ENV_FILE} — copy .env.testing.example and fill it in." >&2
    exit 1
fi

# shellcheck disable=SC1090
set -a; source "${ENV_FILE}"; set +a

# The test role name is fixed in phpunit.xml with force="true"; read it from
# there rather than repeating it, so the two cannot drift apart.
DB_USERNAME="$(sed -n 's/.*name="DB_USERNAME" value="\([^"]*\)".*/\1/p' "${ROOT_DIR}/phpunit.xml")"

: "${DB_HOST:?DB_HOST is required}"
: "${DB_PORT:?DB_PORT is required}"
: "${DB_DATABASE:?DB_DATABASE is required}"
: "${DB_USERNAME:?DB_USERNAME could not be read from phpunit.xml}"
: "${DB_PASSWORD:?DB_PASSWORD is required}"
: "${DB_ADMIN_USERNAME:?DB_ADMIN_USERNAME is required}"
: "${DB_ADMIN_PASSWORD:?DB_ADMIN_PASSWORD is required}"

psql_admin() {
    PGPASSWORD="${DB_ADMIN_PASSWORD}" psql \
        --host "${DB_HOST}" --port "${DB_PORT}" \
        --username "${DB_ADMIN_USERNAME}" \
        --no-psqlrc --quiet --set ON_ERROR_STOP=1 "$@"
}

echo "→ role ${DB_USERNAME}"
psql_admin --dbname postgres --command "
    DO \$\$
    BEGIN
        IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = '${DB_USERNAME}') THEN
            -- CREATEDB is needed by parallel testing, which gives every worker
            -- process its own database. It grants nothing over existing data
            -- and does not touch row security: the role still cannot read a
            -- row a policy hides from it.
            CREATE ROLE \"${DB_USERNAME}\" LOGIN NOSUPERUSER CREATEDB NOCREATEROLE
                PASSWORD '${DB_PASSWORD}';
        ELSE
            ALTER ROLE \"${DB_USERNAME}\" PASSWORD '${DB_PASSWORD}';
        END IF;
    END
    \$\$;
"

# BYPASSRLS is never granted — not to the test role, not to anyone. A role that
# can skip row security removes the second line of defence entirely.
psql_admin --dbname postgres --command "
    ALTER ROLE \"${DB_USERNAME}\" NOSUPERUSER NOBYPASSRLS CREATEDB;
"

echo "→ database ${DB_DATABASE}"
if ! psql_admin --dbname postgres --tuples-only --no-align \
        --command "SELECT 1 FROM pg_database WHERE datname = '${DB_DATABASE}'" | grep -q 1; then
    psql_admin --dbname postgres --command "CREATE DATABASE \"${DB_DATABASE}\""
fi

echo "→ extensions and grants"
psql_admin --dbname "${DB_DATABASE}" --command "
    -- Yalniz migration'i olan extension kurulur. Test veritabaninin temiz bir
    -- production kurulumunda bulunmayan bir extension tasimasi, o extension'a
    -- dayanan kodun testte gecip prod'da kirilmasi demektir (kirmizi cizgi 6).
    -- unaccent burada da var cunku parallel testing worker basina veritabani
    -- acar ve migration'in ilk calismasi icin gerekir.
    CREATE EXTENSION IF NOT EXISTS unaccent;
    GRANT CONNECT, CREATE ON DATABASE \"${DB_DATABASE}\" TO \"${DB_USERNAME}\";
    GRANT USAGE, CREATE ON SCHEMA public TO \"${DB_USERNAME}\";
"

echo "→ verifying the test role is not a superuser"
privileges="$(PGPASSWORD="${DB_PASSWORD}" psql \
    --host "${DB_HOST}" --port "${DB_PORT}" \
    --username "${DB_USERNAME}" --dbname "${DB_DATABASE}" \
    --no-psqlrc --tuples-only --no-align --set ON_ERROR_STOP=1 \
    --command "SELECT rolsuper || ',' || rolbypassrls FROM pg_roles WHERE rolname = current_user")"

if [[ "${privileges}" != "false,false" ]]; then
    echo "REFUSING: ${DB_USERNAME} reports rolsuper,rolbypassrls = ${privileges}." >&2
    echo "Tenant isolation cannot be tested with a role that can bypass it." >&2
    exit 1
fi

echo "✓ test database ready"
