Files
motor-de-encuestas/sprints/sprint-5/INSUMOS_AUDIT_LOG.md

5.8 KiB

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.