107 lines
5.8 KiB
Markdown
107 lines
5.8 KiB
Markdown
# INSUMOS — Etapa Audit Log append-only (Sprint compliance, SEC-002)
|
|
|
|
> Material de contexto para que Claude (Projects, arquitecto) redacte el ETAPA_PROMPT.md
|
|
> de esta etapa. No es el prompt en sí — es lo que el arquitecto necesita para escribirlo
|
|
> bien, sin tener que releer todo el repo.
|
|
|
|
---
|
|
|
|
## 1. Por qué esta etapa, y por qué este alcance
|
|
|
|
`BACKLOG.md` (SEC-002) y `COMPLIANCE.md` §5.1 piden, dentro del sprint de compliance,
|
|
un "registro de auditoría append-only (log inmutable de operaciones sensibles)". El
|
|
director priorizó esta pieza primero, antes de hashing de integridad, trazabilidad de
|
|
cambios o cifrado en reposo (esas quedan para etapas futuras del mismo sprint).
|
|
|
|
COMPLIANCE.md §5.1 pide loggear 3 cosas: accesos a datos sensibles, cambios de
|
|
configuración, y ejecución de migraciones. Evalué las 3 y propongo **acotar el alcance
|
|
de esta etapa a 2 de las 3**:
|
|
|
|
1. **Migraciones (DDL)** — factible con un event trigger nativo de Postgres
|
|
(`ddl_command_end`), sin tocar el flujo de deploy.
|
|
2. **Cambios de configuración** — triggers `AFTER INSERT/UPDATE/DELETE` en
|
|
`user_roles` (altas/bajas/cambios de `app_role`/`org_id`) y en `surveys` cuando
|
|
cambia `status` (activación/desactivación de encuestas).
|
|
3. **Acceso a datos sensibles — propongo DEFERIR explícitamente.** Verificado en
|
|
COMPLIANCE.md §3.2: hoy ningún camino de código (ni `/admin/responses` ni las RPCs
|
|
`rpc_me_*`) lee columnas `is_sensitive=true`. Instrumentar "acceso" sin que exista
|
|
un acceso real sería simular cobertura. Cuando se construya el primer camino que sí
|
|
lea sensibles, ESE PR debe agregar su propio log de acceso junto con el código que
|
|
lo necesita — no antes.
|
|
|
|
El arquitecto puede confirmar o ajustar este recorte; lo presento como punto de partida,
|
|
no como cerrado (esto todavía no se aprobó con el director, se está armando el prompt).
|
|
|
|
---
|
|
|
|
## 2. Decisiones de diseño que ya tienen forma (para que el prompt las fije)
|
|
|
|
- **Tabla nueva:** `public.audit_log` — append-only real:
|
|
- Ningún rol (`anon`, `authenticated`, ni `service_role` vía API) tiene
|
|
`INSERT`/`UPDATE`/`DELETE` directo. Solo escriben funciones `SECURITY DEFINER`
|
|
de los triggers, propiedad de `postgres` (mismo patrón que
|
|
`custom_access_token_hook`, ver `supabase/migrations/20260627000001_auth_user_roles.sql`).
|
|
- Trigger `BEFORE UPDATE OR DELETE ON audit_log` que aborta con excepción — segunda
|
|
barrera, defensa en profundidad (no a prueba de un operador con `psql -U postgres`
|
|
en el VPS — ver gap conocido abajo).
|
|
- Lectura: RLS, solo `platform_admin` (reusar `current_app_role()`, ver
|
|
`supabase/migrations/20260531000003_rls_policies.sql:17`).
|
|
- **Columnas sugeridas (a validar por el arquitecto):** `id bigserial pk`,
|
|
`occurred_at timestamptz default now()`, `actor_role text`, `actor_user_id uuid`,
|
|
`action text`, `target_table text`, `target_id text`, `detail jsonb`.
|
|
- **Gap conocido a documentar, no a resolver en esta etapa:** esto no protege contra
|
|
`TRUNCATE`/`DROP` ejecutado por un superusuario directo en el VPS — mismo gap ya
|
|
registrado en `SEC-003` (BACKLOG.md). Append-only a nivel de aplicación/RLS, no a
|
|
prueba de acceso root a la base.
|
|
|
|
---
|
|
|
|
## 3. Convenciones del repo que el prompt debe respetar
|
|
|
|
- **Migraciones:** `supabase/migrations/`, naming `YYYYMMDDHHMMSS_descripcion.sql`.
|
|
Última migración aplicada: `20260627000001_auth_user_roles.sql`. La próxima debe
|
|
fecharse después de esa.
|
|
- **Patrón SECURITY DEFINER + GRANT EXECUTE puntual:** ver
|
|
`custom_access_token_hook` en `20260627000001_auth_user_roles.sql` — función
|
|
`SECURITY DEFINER STABLE`, `GRANT EXECUTE ... TO supabase_auth_admin` (rol
|
|
específico, no `PUBLIC`). Mismo patrón a replicar para las funciones de trigger
|
|
de `audit_log`.
|
|
- **Helpers RLS existentes a reusar, no reinventar:** `public.current_app_role()`
|
|
y `public.current_org_id()` (`20260531000003_rls_policies.sql:17-30`).
|
|
- **Verificación obligatoria antes de aplicar en VPS:** mostrar el SQL final completo
|
|
y esperar OK explícito del director antes de correrlo en producción (ya es práctica
|
|
establecida en este proyecto — ver incidente VPS del 27 jun, recuperación documentada
|
|
en `docs/estado/ESTADO_PROYECTO_JUNIO_2026.md` §2.1).
|
|
- **Formato esperado del archivo de etapa:** seguir la estructura de
|
|
`sprints/sprint-4/ETAPA_AUTH_PROMPT.md` o `ETAPA_4G_PROMPT.md` — Objetivo,
|
|
Decisiones ya tomadas (no consultar), Tareas, DoD, Qué reportar (datos concretos,
|
|
no "funcionó"), Qué NO hacer, Versionado (mensaje de commit sugerido con tag
|
|
`[compliance]` o similar).
|
|
|
|
---
|
|
|
|
## 4. Qué NO debería pedir el prompt (fuera de alcance de esta etapa)
|
|
|
|
- Hashing de integridad SHA-256 (siguiente pieza del mismo sprint, etapa separada).
|
|
- Cifrado en reposo (es trabajo de VPS/infraestructura, no de migración SQL).
|
|
- Trazabilidad histórica completa de cambios de datos (triggers de historial / WAL) —
|
|
etapa separada también.
|
|
- Logging de acceso a datos sensibles (ver §1, punto 3 — deferido a cuando exista
|
|
código que lea sensibles).
|
|
- pgaudit o cualquier extensión nueva — no está en el Supabase self-hosted actual,
|
|
agregar una extensión es Nivel 3 aparte (afecta infraestructura/dependencias).
|
|
|
|
---
|
|
|
|
## 5. Referencias
|
|
|
|
- `COMPLIANCE.md` §5 (roadmap auditabilidad), §5.2 (por qué no blockchain), §3.2
|
|
(qué es sensible y cómo se protege hoy).
|
|
- `BACKLOG.md` → SEC-002, SEC-003 (gap de TRUNCATE), SEC-004 (bypass REST, contexto
|
|
de otro riesgo residual ya aceptado, mismo espíritu de "documentar en vez de
|
|
sobre-construir").
|
|
- `TECH_DEBT.md` → TECH-DEBT-008 (resuelto 27 jun, ejemplo de cómo se cierra un ítem).
|
|
- `docs/estado/ESTADO_PROYECTO_JUNIO_2026.md` — estado general post-release v3.0.0
|
|
+ incidente VPS, para que el arquitecto tenga el panorama completo antes de escribir
|
|
el prompt.
|