""" Pruebas de aislamiento multi-tenant para tickets y usuarios. Usa solo los fixtures definidos en conftest.py. Roles en juego: client_tenant_a → SUPPORT_MANAGER (aduanasoft) — restringido a su tenant client_tenant_b → CLIENT_ADMIN (empresa-test) — restringido a su tenant client_admin → ADMIN global (aduanasoft) — acceso a todos los tenants """ import pytest @pytest.mark.asyncio async def test_tenant_a_cannot_see_tenant_b_tickets( client_tenant_a, create_ticket_tenant_b ): """ El usuario del tenant B crea un ticket. El usuario del tenant A (SUPPORT_MANAGER) lista sus tickets. El ticket de tenant B NO debe aparecer en la respuesta. """ # El usuario del tenant B crea un ticket ticket_b = await create_ticket_tenant_b() ticket_b_id = ticket_b["id"] # El usuario del tenant A lista sus tickets response = await client_tenant_a.get("/v1/tickets/") assert response.status_code == 200 ids_visibles = {t["id"] for t in response.json()} # El ticket de tenant B no debe ser visible para tenant A assert ticket_b_id not in ids_visibles, ( f"Fallo de aislamiento: ticket de tenant B ({ticket_b_id}) " f"visible para usuario de tenant A" ) @pytest.mark.asyncio async def test_tenant_b_cannot_edit_tenant_a_ticket( create_ticket_tenant_a, client_tenant_b ): """ El usuario del tenant A crea un ticket. El usuario del tenant B intenta editar ese ticket vía PATCH. Debe recibir 403 (prohibido) o 404 (no encontrado). """ # El usuario del tenant A crea un ticket ticket_a = await create_ticket_tenant_a() ticket_a_id = ticket_a["id"] # El usuario del tenant B intenta editar el ticket de tenant A response = await client_tenant_b.patch( f"/v1/tickets/{ticket_a_id}", json={"status": "CLOSED"}, ) # Debe recibir 403 o 404 — nunca 200 assert response.status_code in (403, 404), ( f"Fallo de aislamiento: tenant B pudo editar ticket de tenant A " f"(HTTP {response.status_code})" ) @pytest.mark.asyncio async def test_tenant_a_cannot_see_tenant_b_users( client_tenant_a, create_user_tenant_b ): """ El usuario del tenant B crea un usuario nuevo. El usuario del tenant A (SUPPORT_MANAGER) lista los usuarios. El usuario de tenant B NO debe aparecer en la respuesta. """ # El usuario del tenant B crea un usuario user_b = await create_user_tenant_b() user_b_id = user_b["id"] # El usuario del tenant A lista los usuarios de su tenant response = await client_tenant_a.get("/v1/users/") assert response.status_code == 200 ids_visibles = {u["id"] for u in response.json()} # El usuario de tenant B no debe ser visible para tenant A assert user_b_id not in ids_visibles, ( f"Fallo de aislamiento: usuario de tenant B ({user_b_id}) " f"visible para usuario de tenant A" ) @pytest.mark.asyncio async def test_admin_sees_all_tenant_data( client_admin, create_ticket_tenant_a, create_ticket_tenant_b, create_user_tenant_a, create_user_tenant_b, ): """ El ADMIN global debe poder ver tickets y usuarios de TODOS los tenants. - Tickets: vía /v1/tickets/admin/all (endpoint multi-tenant). - Usuarios: vía /v1/users/ (ADMIN bypasa el filtro de tenant). """ # Crear datos en ambos tenants ticket_a = await create_ticket_tenant_a() ticket_b = await create_ticket_tenant_b() user_a = await create_user_tenant_a() user_b = await create_user_tenant_b() # El admin lista todos los tickets (endpoint multi-tenant) resp_tickets = await client_admin.get("/v1/tickets/admin/all") assert resp_tickets.status_code == 200 ids_tickets = {t["id"] for t in resp_tickets.json()} assert ticket_a["id"] in ids_tickets, "El ADMIN no ve el ticket de tenant A" assert ticket_b["id"] in ids_tickets, "El ADMIN no ve el ticket de tenant B" # El admin lista todos los usuarios (ADMIN bypasa filtro de tenant) resp_users = await client_admin.get("/v1/users/") assert resp_users.status_code == 200 ids_users = {u["id"] for u in resp_users.json()} assert user_a["id"] in ids_users, "El ADMIN no ve el usuario de tenant A" assert user_b["id"] in ids_users, "El ADMIN no ve el usuario de tenant B"