panels-origin/db/provision/verify-isolation.sh
Cursor Agent b87b0205a8
db: migrar infraestructura de BD a Postgres (fase 0-1)
- Fase 0: scripts de aprovisionamiento (db/provision/) para roles, dos
  bases de datos separadas (panels_platform / panels_product con
  esquemas iam+core) y ACLs de Redis por modulo, con verificacion
  automatizada de aislamiento (verify-isolation.sh) y setup local
  reproducible (dev-local.sh).
- Fase 1: changelogs de Liquibase reescritos para Postgres
  (db/platform, db/iam, db/core reemplazan db/app + los changesets
  SQLite de platform). Baseline como estado final (no replay literal),
  tipos traducidos (IDENTITY, TIMESTAMPTZ/DATE, NUMERIC, BOOLEAN,
  CITEXT), contexts dev vs. schema/catalogos, RLS por tenant_id como
  defensa en profundidad, uploaded_by/created_by como snapshot
  desnormalizado (sin FK hacia iam).
- Migraciones ya no corren en el arranque de la API: paso explicito de
  deploy via db/update.sh con credenciales _owner.

Verificado end-to-end contra Postgres 16 + Redis local.

Co-authored-by: alberto.martinez <alberto.martinez@mrdev.mx>
2026-09-02 20:00:49 +00:00

67 lines
2.9 KiB
Bash
Executable file

#!/usr/bin/env bash
# PANELS · Fase 0 · verifica que el aislamiento entre módulos realmente
# se cumple (no solo que las credenciales existan). Pensado para correr
# después de 01-04 (Postgres) y 05 (Redis), en cualquier ambiente.
#
# Uso: source el .env con DATABASE_URL_*/REDIS_URL_* y correr este script.
set -uo pipefail
cd "$(dirname "$0")"
fail=0
check() {
local desc="$1"; local expect_fail="$2"; shift 2
if "$@" >/tmp/verify-out.$$ 2>&1; then
ok=1
else
ok=0
fi
if [[ "$expect_fail" == "yes" && "$ok" == "0" ]] || [[ "$expect_fail" == "no" && "$ok" == "1" ]]; then
echo "OK - $desc"
else
echo "FAIL - $desc"
cat /tmp/verify-out.$$
fail=1
fi
rm -f /tmp/verify-out.$$
}
: "${DATABASE_URL_PLATFORM:?}"; : "${DATABASE_URL_IAM:?}"; : "${DATABASE_URL_CORE:?}"
: "${REDIS_URL_IAM:?}"; : "${REDIS_URL_CORE:?}"
extract_pw() { echo "$1" | sed -E 's#[a-zA-Z]+://[^:]+:([^@]+)@.*#\1#'; }
PLATFORM_HOST=$(echo "$DATABASE_URL_PLATFORM" | sed -E 's#.*@([^/]+)/.*#\1#')
echo "== Postgres: DML normal funciona =="
check "iam_app puede hacer SELECT en su esquema" no psql "$DATABASE_URL_IAM" -c "SELECT 1;"
check "core_app puede hacer SELECT en su esquema" no psql "$DATABASE_URL_CORE" -c "SELECT 1;"
echo "== Postgres: aislamiento cruzado =="
check "iam_app NO puede leer schema core" yes psql "$DATABASE_URL_IAM" -c "SELECT * FROM core.pg_tables LIMIT 1;"
check "core_app NO puede leer schema iam" yes psql "$DATABASE_URL_CORE" -c "SELECT 1 FROM iam.pg_am LIMIT 1;"
check "iam_app NO puede hacer DDL (solo _owner puede)" yes psql "$DATABASE_URL_IAM" -c "CREATE TABLE iam.probe_$$(id int);"
PLATFORM_APP_PW=$(extract_pw "$DATABASE_URL_PLATFORM")
IAM_APP_PW=$(extract_pw "$DATABASE_URL_IAM")
check "platform_app NO puede CONNECT a panels_product" yes \
psql "postgresql://panels_platform_app:${PLATFORM_APP_PW}@${PLATFORM_HOST%/*}/panels_product" -c "SELECT 1;"
check "iam_app NO puede CONNECT a panels_platform" yes \
psql "postgresql://panels_iam_app:${IAM_APP_PW}@${PLATFORM_HOST%/*}/panels_platform" -c "SELECT 1;"
echo "== Redis: ACL por módulo =="
IAM_REDIS_HOST=$(echo "$REDIS_URL_IAM" | sed -E 's#redis://[^@]+@##')
IAM_REDIS_PW=$(extract_pw "$REDIS_URL_IAM")
CORE_REDIS_PW=$(extract_pw "$REDIS_URL_CORE")
check "panels_iam_redis puede escribir iam:*" no \
redis-cli -u "redis://panels_iam_redis:${IAM_REDIS_PW}@${IAM_REDIS_HOST}" SET iam:verify:probe 1
check "panels_iam_redis NO puede leer core:* (NOPERM)" no \
bash -c "redis-cli -u 'redis://panels_iam_redis:${IAM_REDIS_PW}@${IAM_REDIS_HOST}' GET core:probe 2>&1 | grep -q NOPERM"
check "panels_core_redis NO puede leer iam:* (NOPERM)" no \
bash -c "redis-cli -u 'redis://panels_core_redis:${CORE_REDIS_PW}@${IAM_REDIS_HOST}' GET iam:probe 2>&1 | grep -q NOPERM"
echo ""
if [[ "$fail" == "0" ]]; then
echo "Todas las verificaciones de aislamiento pasaron."
else
echo "Hay verificaciones fallidas -- revisar antes de continuar."
exit 1
fi