Appearance
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 aislamientoMé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.
- Condominio A (
- 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.comregistrado con rol'committee'en Condominio A (id = 'condo-alpha').
- Usuario
- 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.comconrole = 'resident',condo_id = 'condo-alpha',unit_id = 'unit-101'.
- Residente
- 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
anonpero 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 conSUPABASE_SERVICE_ROLE_KEYcontinúan ejecutándose normalmente sin bloqueos de RLS. - Verificación:
- En PostgreSQL, el rol
service_roleposee el flagBYPASSRLS. - La Edge Function
send-statementlee adeudos de cualquier condominio para generar los PDFs. - La Edge Function
send-invitationupserta enuser_invitationsyapp_users.
- En PostgreSQL, el rol
- 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:
- Iniciar sesión con la cuenta de administrador del piloto.
- Verificar que
resolveUserRoledetectarole: 'admin'y sucondo_id. - Navegar a Directorio de Viviendas: Las unidades deben cargar de inmediato.
- Navegar a Finanzas / Egresos / Cuentas Bancarias: La información se visualiza y sincroniza normalmente.
- 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 Prueba | Rol Evaluado | Acción Evaluada | Comportamiento Observado | Estatus |
|---|---|---|---|---|
| 1.1 | Admin Condo A | SELECT en Condo B | 0 filas retornadas | APROBADO |
| 1.2 | Admin Condo A | INSERT en Condo B | Excepción RLS violada | APROBADO |
| 1.3 | Admin Condo A | UPDATE en Condo B | 0 filas afectadas | APROBADO |
| 2.1 | Miembro Comité | SELECT en su Condo | Lectura permitida | APROBADO |
| 2.2 | Miembro Comité | INSERT en su Condo | Excepción RLS violada | APROBADO |
| 3.1 | Residente | SELECT de su unidad | Lectura exitosa de su unidad | APROBADO |
| 3.2 | Residente | SELECT de otras unidades | 0 filas ajenas devueltas | APROBADO |
| 3.3 | Residente | SELECT en bancos/egresos | 0 filas devueltas | APROBADO |
| 4.1 | Anónimo | SELECT en cualquier tabla | 0 filas devueltas | APROBADO |
| 5.1 | service_role | Operaciones backend | Ejecución irrestricta (BYPASSRLS) | APROBADO |
| 6.1 | Admin Piloto #1 | Flujo diario de la app | Operación fluida sin regresiones | APROBADO |