Skip to content

Batería de Pruebas Adversarias Obligatorias — RLS Real (Fase 4-A) ​

Este protocolo de verificación forense documenta los casos de prueba adversarios obligatorios para validar que la seguridad a nivel de filas (Row Level Security - RLS) aísla de forma hermética la información entre condominios, restringe los privilegios de comités y residentes, y bloquea de raíz a usuarios anónimos o no autorizados.


1. Métodos de Ejecución de Pruebas ​

Método A: En Supabase SQL Editor (Simulación de Claims JWT) ​

En PostgreSQL, Supabase permite simular un usuario autenticado configurando las variables de sesión del JWT:

sql
BEGIN;
  -- Simular usuario autenticado
  SET LOCAL ROLE authenticated;
  -- Asignar el UUID del usuario (auth.uid) y su correo
  SET LOCAL "request.jwt.claim.sub" = '00000000-0000-0000-0000-000000000001';
  SET LOCAL "request.jwt.claim.email" = 'admin_condo_a@itecel.com';

  -- EJECUTAR AQUÍ LAS SENTENCIAS DE PRUEBA
  SELECT count(*) FROM housing_units;

ROLLBACK; -- Siempre revertir tras la prueba de aislamiento

Método B: Vía Consola del Navegador (App en Vivo) ​

Con la sesión iniciada en la aplicación, abrir las DevTools (F12) → Pestaña Console:

javascript
// Obtener cliente Supabase activo
const sb = window.__SUPABASE__ || (await import('/src/lib/supabaseClient.ts')).supabase;

// Probar lectura de otro condominio
const { data, error } = await sb.from('housing_units').select('*').eq('condo_id', 'condo-b-id');
console.log('Filas devueltas:', data?.length, 'Error:', error);

2. Escenarios y Casos de Prueba ​

CASO 1: Aislamiento Multi-Condominio (Admin A vs Condominio B) ​

  • Objetivo: Demostrar que el administrador del Condominio A no puede leer ni modificar ningún dato del Condominio B.
  • Pre-condición:
    • Condominio A (id = 'condo-alpha'), Admin: admin_a@test.com.
    • Condominio B (id = 'condo-beta'), Admin: admin_b@test.com.
  • Prueba SQL:
sql
BEGIN;
  SET LOCAL ROLE authenticated;
  SET LOCAL "request.jwt.claim.email" = 'admin_a@test.com';

  -- 1.1 Intento de Lectura no autorizada
  SELECT * FROM housing_units WHERE condo_id = 'condo-beta';
  -- RESULTADO ESPERADO: 0 filas devueltas (Aislamiento total).

  -- 1.2 Intento de Inserción no autorizada
  INSERT INTO housing_units (id, condo_id, unit_number) 
  VALUES ('hack-unit-1', 'condo-beta', '999');
  -- RESULTADO ESPERADO: ERROR: new row violates row-level security policy for table "housing_units".

  -- 1.3 Intento de Actualización maliciosa
  UPDATE condos SET name = 'Condo Hackeado' WHERE id = 'condo-beta';
  -- RESULTADO ESPERADO: 0 filas actualizadas.

  -- 1.4 Intento de Eliminación de datos ajenos
  DELETE FROM expenses WHERE condo_id = 'condo-beta';
  -- RESULTADO ESPERADO: 0 filas eliminadas.
ROLLBACK;

CASO 2: Restricción de Privilegios del Comité (Solo Lectura) ​

  • Objetivo: Comprobar que un miembro del comité puede auditar la información de su propio condominio pero no puede realizar mutaciones (INSERT, UPDATE o DELETE).
  • Pre-condición:
    • Usuario comite@test.com registrado con rol 'committee' en Condominio A (id = 'condo-alpha').
  • Prueba SQL:
sql
BEGIN;
  SET LOCAL ROLE authenticated;
  SET LOCAL "request.jwt.claim.email" = 'comite@test.com';

  -- 2.1 Lectura de datos de su condominio
  SELECT count(*) FROM expenses WHERE condo_id = 'condo-alpha';
  -- RESULTADO ESPERADO: Retorna el conteo real de egresos del condominio (Permitido).

  SELECT count(*) FROM bank_accounts WHERE condo_id = 'condo-alpha';
  -- RESULTADO ESPERADO: Retorna las cuentas bancarias de su condominio (Permitido para auditoría).

  -- 2.2 Intento de Inserción (Mutación prohibida)
  INSERT INTO expenses (id, condo_id, concept, amount, expense_date) 
  VALUES ('exp-malicious', 'condo-alpha', 'Gasto no autorizado', 500, '2026-09-13');
  -- RESULTADO ESPERADO: ERROR: new row violates row-level security policy for table "expenses".

  -- 2.3 Intento de Modificación de adeudos
  UPDATE generated_debts SET paid_amount = 999 WHERE condo_id = 'condo-alpha';
  -- RESULTADO ESPERADO: 0 filas actualizadas.
ROLLBACK;

CASO 3: Restricción Estricta de Residentes (Solo su Vivienda) ​

  • Objetivo: Comprobar que un copropietario solo puede ver su propia vivienda y adeudos, y tiene bloqueadas las cuentas bancarias, proveedores, egresos, presupuestos y viviendas vecinas.
  • Pre-condición:
    • Residente residente101@test.com con role = 'resident', condo_id = 'condo-alpha', unit_id = 'unit-101'.
  • Prueba SQL:
sql
BEGIN;
  SET LOCAL ROLE authenticated;
  SET LOCAL "request.jwt.claim.email" = 'residente101@test.com';

  -- 3.1 Consulta de su propia vivienda
  SELECT id, unit_number FROM housing_units WHERE id = 'unit-101';
  -- RESULTADO ESPERADO: 1 fila devuelta (Su vivienda).

  -- 3.2 Intento de espiar viviendas vecinas
  SELECT id, unit_number, contact_name FROM housing_units WHERE condo_id = 'condo-alpha';
  -- RESULTADO ESPERADO: Solo devuelve 1 fila correspondiente a 'unit-101'. Cero datos de vecinos.

  -- 3.3 Intento de consultar cuentas bancarias del condominio
  SELECT * FROM bank_accounts WHERE condo_id = 'condo-alpha';
  -- RESULTADO ESPERADO: 0 filas devueltas (Bloqueo total por política RLS).

  -- 3.4 Intento de consultar egresos y proveedores
  SELECT * FROM expenses WHERE condo_id = 'condo-alpha';
  SELECT * FROM suppliers WHERE condo_id = 'condo-alpha';
  -- RESULTADO ESPERADO: 0 filas devueltas.

  -- 3.5 Intento de alterar un adeudo
  UPDATE generated_debts SET status = 'paid' WHERE unit_id = 'unit-101';
  -- RESULTADO ESPERADO: 0 filas actualizadas.
ROLLBACK;

CASO 4: Bloqueo de Peticiones Anónimas / Sin Autenticación ​

  • Objetivo: Verificar que peticiones con la llave pública anon pero sin sesión iniciada reciban cero datos.
  • Prueba SQL:
sql
BEGIN;
  SET LOCAL ROLE anon;

  SELECT count(*) FROM condos;
  -- RESULTADO ESPERADO: 0.

  SELECT count(*) FROM housing_units;
  -- RESULTADO ESPERADO: 0.

  SELECT count(*) FROM payment_records;
  -- RESULTADO ESPERADO: 0.
ROLLBACK;

CASO 5: Bypass Autorizado para Edge Functions (service_role) ​

  • Objetivo: Comprobar que los servicios backend (send-statement, send-invitation, send-password-recovery) que operan con SUPABASE_SERVICE_ROLE_KEY continúan ejecutándose normalmente sin bloqueos de RLS.
  • Verificación:
    • En PostgreSQL, el rol service_role posee el flag BYPASSRLS.
    • La Edge Function send-statement lee adeudos de cualquier condominio para generar los PDFs.
    • La Edge Function send-invitation upserta en user_invitations y app_users.
  • Prueba SQL:
sql
BEGIN;
  SET LOCAL ROLE service_role;

  -- Debe poder consultar y operar sobre cualquier condominio
  SELECT count(*) FROM housing_units;
  -- RESULTADO ESPERADO: Conteo completo de todas las viviendas en la base de datos.
ROLLBACK;

CASO 6: Verificación de Regresión del Piloto Actual (Condominio #1) ​

  • Objetivo: Garantizar que el socio y sus colaboradores en el Condominio #1 continúan operando sin interrupción.
  • Pasos de verificación en vivo:
    1. Iniciar sesión con la cuenta de administrador del piloto.
    2. Verificar que resolveUserRole detecta role: 'admin' y su condo_id.
    3. Navegar a Directorio de Viviendas: Las unidades deben cargar de inmediato.
    4. Navegar a Finanzas / Egresos / Cuentas Bancarias: La información se visualiza y sincroniza normalmente.
    5. Probar un guardado o sincronización manual: El proceso debe completarse exitosamente con código de respuesta HTTP 200/201/204 de Supabase.

3. Matriz de Resultados Forenses ​

Caso de PruebaRol EvaluadoAcción EvaluadaComportamiento ObservadoEstatus
1.1Admin Condo ASELECT en Condo B0 filas retornadasAPROBADO
1.2Admin Condo AINSERT en Condo BExcepción RLS violadaAPROBADO
1.3Admin Condo AUPDATE en Condo B0 filas afectadasAPROBADO
2.1Miembro ComitéSELECT en su CondoLectura permitidaAPROBADO
2.2Miembro ComitéINSERT en su CondoExcepción RLS violadaAPROBADO
3.1ResidenteSELECT de su unidadLectura exitosa de su unidadAPROBADO
3.2ResidenteSELECT de otras unidades0 filas ajenas devueltasAPROBADO
3.3ResidenteSELECT en bancos/egresos0 filas devueltasAPROBADO
4.1AnónimoSELECT en cualquier tabla0 filas devueltasAPROBADO
5.1service_roleOperaciones backendEjecución irrestricta (BYPASSRLS)APROBADO
6.1Admin Piloto #1Flujo diario de la appOperación fluida sin regresionesAPROBADO

Wiki Técnica Oficial — ITECEL ADM