82 lines
5.1 KiB
Markdown
82 lines
5.1 KiB
Markdown
# ETAPA 1C — Cierre de la fundación: REVOKE del GRANT peligroso + documentación
|
|
|
|
> Prompt versionado (Patrón B.1). Cierra la auditoría de la Etapa 1B con el único cambio bloqueante
|
|
> que encontró y documenta tres decisiones que el agente tomó por iniciativa. Claude Code lo ejecuta
|
|
> tras leer `CLAUDE.md`, `DATA_MODEL.md` y este prompt.
|
|
|
|
## 1. Objetivo
|
|
Quitar el `GRANT SELECT ON consent_records TO authenticated` (puerta apoyada-sin-llave: hoy inerte,
|
|
peligrosa si alguien suma una policy SELECT a futuro), **confirmar en ejecución que no rompe el flujo
|
|
de envío de la encuesta** (la FK `responses.consent_record_id`), y documentar en `DATA_MODEL.md` tres
|
|
decisiones tomadas en la 1B.
|
|
|
|
## 2. Contexto previo
|
|
La 1B aplicó las migraciones 001-006 a Supabase Cloud y la auditoría aprobó la fundación de datos
|
|
salvo este punto. La migración **006 ya está aplicada en Cloud** → **NO se edita** (rompería el
|
|
historial de migraciones). El cambio va en una migración nueva, 007.
|
|
|
|
## 3. Decisiones ya tomadas (no consultar de nuevo)
|
|
- El cambio es un `REVOKE`, en migración **nueva** 007. NO editar 001-006.
|
|
- El `GRANT INSERT ON consent_records TO anon, authenticated` **se mantiene** (el envío del formulario
|
|
lo necesita). Solo se revoca el SELECT.
|
|
- NO se agrega ninguna policy SELECT a `consent_records`. El analyst lee vía `service_role` (que
|
|
bypassa RLS y no necesita GRANTs).
|
|
- No se toca el resto del esquema, ni las policies, ni `service_role`.
|
|
|
|
## 4. Tareas
|
|
1. Crear la migración con `supabase migration new revoke_consent_select` y poner como contenido:
|
|
```sql
|
|
-- 007: Revoca el SELECT sobre consent_records a authenticated.
|
|
-- Auditoría 1B: GRANT inerte hoy (no hay policy SELECT) pero peligroso si a futuro alguien
|
|
-- agrega una policy SELECT para org_admin → expondría quién consintió qué, vector de
|
|
-- correlación con respuestas en encuesta anónima. El analyst lee vía service_role.
|
|
REVOKE SELECT ON public.consent_records FROM authenticated;
|
|
```
|
|
2. Aplicar a Cloud: `supabase db push` (usar `npx supabase ...` si el CLI no es global).
|
|
3. Correr las validaciones de la sección 6 contra la base real.
|
|
4. Documentar en `DATA_MODEL.md` las tres decisiones (texto exacto en la sección 5 de este prompt).
|
|
|
|
## 5. Texto EXACTO a agregar al final de `DATA_MODEL.md` (sección nueva)
|
|
```markdown
|
|
## Decisiones ratificadas en ejecución (Sprint 1)
|
|
- **`options` en preguntas `rating` (F3, G4):** se guarda como objeto
|
|
`{"min":1,"max":5,"min_label":"...","max_label":"..."}`, NO como array. El frontend (Sprint 2)
|
|
debe manejar dos formas de `options`: array para `single_choice`/`multiple_choice`, objeto para
|
|
`rating`.
|
|
- **`required = false` en todas las preguntas seeded:** la obligatoriedad real se define en Sprint 2
|
|
(validación del formulario). Nota: B1 estaba marcada obligatoria en el mockup; revisar al construir
|
|
el formulario.
|
|
- **Policies de `org_admin` presentes pero inertes en v1:** las policies RLS para `org_admin`
|
|
(acceso multi-tenant por empresa) existen en migración 003, pero v1 NO tiene login de cliente
|
|
("nosotros presentamos a cada empresa"). El acceso real lo hace el analyst vía `service_role`. El
|
|
camino `org_admin` queda reservado para un futuro de auto-servicio, no operado en v1.
|
|
```
|
|
|
|
## 6. Validaciones automatizadas mandatorias (contra la base Cloud)
|
|
La central es la #1 — confirma que revocar el SELECT NO rompe el envío:
|
|
- **FK intacta:** simulando rol `anon` (SET ROLE anon + claims, o vía anon key), `INSERT` en
|
|
`consent_records` → obtener su id → `INSERT` en `responses` referenciando ese `consent_record_id`
|
|
(con `survey_id` de una encuesta `status='live'` y `respondent_id` NULL) → **debe insertar sin
|
|
error**. Esto prueba que la verificación de FK no requiere SELECT sobre `consent_records`.
|
|
- **REVOKE efectivo:** como `authenticated`, `SELECT FROM consent_records` → ahora "permission
|
|
denied" (ya no "0 filas"). Confirma que el revoke aplicó.
|
|
- **Sin regresión:** re-correr las claves de la 1B → RLS sobre `responses`/`answers` = 0 filas para
|
|
org_admin; `agg_segment` n=3 → suprimido, n=5 → valor; inmutabilidad de `consent_records` (UPDATE/
|
|
DELETE → error) sigue vigente.
|
|
- Si CUALQUIERA falla: **NO declarar lista la etapa.** Reportar y esperar. En especial, si la #1
|
|
fallara (la FK SÍ necesitaba el SELECT), **detenerse y reportar** — sería el caso que invalida el
|
|
cambio.
|
|
|
|
## 7. Qué reportar
|
|
- **Verificado:** salida concreta de cada validación (el INSERT anónimo que efectivamente insertó, el
|
|
"permission denied" del SELECT como authenticated, y las 3 de no-regresión).
|
|
- **Asumido / Hallazgos / Decisiones por iniciativa** (clasificadas por nivel).
|
|
- **`git diff --name-only HEAD`:** debe contener solo la migración 007 nueva + `DATA_MODEL.md`.
|
|
|
|
## 8. Qué NO hacer
|
|
- NO editar las migraciones 001-006 (006 ya está en Cloud).
|
|
- NO agregar policy SELECT a `consent_records`.
|
|
- NO tocar `service_role`, ni las policies de org_admin, ni el resto del esquema.
|
|
- NO usar `respondent_id` ni exponer texto libre.
|
|
- Ante conflicto entre una restricción y "que aplique limpio": **detenerse y reportar**, no resolver
|
|
unilateralmente. |