Auditoría de esquema · Supabase LPDI

68 tablas del schema public en producción · 2026-08-05 · a raíz del caos de las taxonomías, se revisó el resto del esquema

Fase 0 APLICADA · exposición cerrada (2026-08-05)
2
Severidad alta
3
Severidad media
5
Severidad baja
1
Informativo
4
Fases del plan

Hallazgos (11)

H1Alta

PII de contactos ICG expuesta públicamente

Backups sin RLS con GRANT total a anon. REST anónimo devuelve HTTP 200. 43 + 37 filas con emails, teléfonos, tokens de invitación.

Revocar acceso YA (reversible). Fase 0

H2Alta

Counters y catálogo de códigos manipulables

Los consecutivos del SC y el mapeo de tipos sin RLS, HTTP 200 anónimo. Un anónimo podría alterar los códigos generados.

Revocar acceso; las funciones son SECURITY DEFINER y no se rompen. Fase 0

H3Media

Taxonomía vieja muerta: industries + sub_industries

Esquema single-industry anterior. 0 usos en código; columnas FK startups/icgs.sub_industry_id 100% NULL. La industria real vive en JSONB + catálogo v6.

Dump + drop de 2 columnas y 2 tablas. Fase 1

H4Media

País duplicado: paises vs catalogo_pais

paises (207, 0 usos) idéntica por ISO a catalogo_pais (207, activa). 207/207 match, 0 filas exclusivas.

Dump + drop de paises. Fase 1

H5Media

10 tablas backup/temp sin política de retención

Todas en public, sin PK ni RLS, con el grant abierto de H1/H2. Una vacía. El patrón "backup como tabla" es el origen de H1/H2.

Calendario de retención + drops escalonados. Fase 2

H6Baja

Catálogos sin uso en la app

catalogo_proposito_recursos y catalogo_tamano_equipo: 0 referencias. Probable: reservados para campos de inversión.

Decisión funcional con Frank. Fase 3

H7Baja

Autorización en 3 sistemas paralelos

admin_roles, module_permissions y roles de ecosistema conviven, todos activos. No hay respuesta única a "qué puede hacer un usuario".

Documentar el mapa en el SC; no unificar aún. Fase 3

H8Baja

5 tablas con RLS y 0 policies

Deny total para el cliente; solo el service role accede. La app funciona, así que es un patrón server-only intencional y seguro.

Documentar como intencional. Fase 3

H9Baja

10 features activas con 0 filas

Código vivo, aún sin datos (super_eventos tiene 14 usos). Son features esperando adopción, no tablas muertas.

NO tocar; línea base para revisar en 6 meses. sin fase

H10Baja

Convención de nombres mezclada

ES/EN mezclados; prefijo catalogo_ vs sin prefijo (justo las 2 muertas no lo llevan). La convención nueva es la buena.

Fijar convención para tablas nuevas; no renombrar. Fase 3

H11Info

Columnas de auditoría 100% NULL

deleted_by, granted_by, edited_by, etc. Flujos de trazabilidad aún sin ejercitar. No son legacy.

Ninguna acción. sin fase

Plan de acción por fases

Fase 0
Cerrar la exposición pública · urgente y reversible

Que H1 y H2 dejen de ser explotables hoy. REVOKE ALL FROM anon, authenticated en las tablas expuestas. No borra nada; un GRANT lo revierte. Verificación post: los REST anónimos deben pasar de 200 a 401/403, y smoke test de generación de códigos. Precondición ya verificada: las funciones de códigos son SECURITY DEFINER.

Fase 1
Drop de los duplicados muertos (H3, H4)

Con dump previo verificado (única red sin PITR) y re-grep de 0 uso justo antes. Orden: drop columnas sub_industry_id → drop sub_industriesindustriespaises. Todo en transacción.

Fase 2
Retención y limpieza de backups (H5, cierre de H1)

Drop directo de la tabla vacía; export cifrado de la PII histórica (cruzando antes contra bajas/anonimización) y drop. Los backup_taxonomia_v6_* se mantienen hasta ~2026-08-12 como red de la migración. Regla nueva: nunca más backups como tabla en public.

Fase 3
Decisiones funcionales y documentación (H6-H10)

Frank decide sobre los 2 catálogos sin uso. Documentar en el SC: mapa de autorización, tablas server-only, y la convención de nombres. Registrar la línea base de features a 0 filas.

NO tocar