test(isolation): per-user cross-isolation suite across modules #196
Loading…
Reference in a new issue
No description provided.
Delete branch "feat/pms-264-per-user-isolation-suite"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Add
tests/per_user_isolation.rs, the PMS-264 regression suite (Step 9 of 9 of the PMS-255 per-user-isolation epic). It stands up two users in two distinct personal tenants (each provisioned viaTenantService::ensure_personal_tenant, so each carries the full seeded lookup set) and drives the real HTTP API as a client would.cross_user_read_and_write_denied_across_modules(AC #1) has user A create a record in every module with real handlers (contacts companies + contacts, tickets, time_tracking time entries). User B then gets 404 on every single-record GET of A's ids and B's list never contains A's rows (read denial). For writes, B aims an UPDATE then a DELETE at A's row id; handlers differ on the surface code for a cross-tenant id (a tenant-scoped write matches no row, so some 404 and some report a no-op 200), so the suite asserts the isolation EFFECT instead: A's row stays present and keeps its original field value, never B's "hijacked" sentinel. That is the request-path face of the WITH CHECK guarantee (PMS-255.2 / PMS-257); the DB-engine face (SQLSTATE 42501 on a GUC-mismatched write) is pinned intests/rls_isolation.rs.cross_user_tenant_endpoint_denied(AC #1, tenants module) proves B cannot read A's tenant row (403 authz guard).dashboard_aggregate_is_caller_scoped(AC #2) provesreports::dashboardcounts only the caller's own tickets across the two tenants.Actors are ordinary
technicianusers, not super_admin: super_admin is the cross-tenant system role (get_tenantlets it read any tenant) and would mask the isolation under test. The module-gated time_tracking / reports endpoints check module enablement (copied into each personal tenant), not role, so a technician still reaches every module. Each test tenant is pre-markedsettings.demo_seeded = trueto neuter the racy first-visit demo-seed middleware (PMS-157) that would otherwise inject nondeterministic rows; demo seeding keeps its own coverage intests/seed_demo.rs.AC #3 (RLS fail-closed regression) and AC #4 (per-user lookup seeding / isolation) are already pinned by
tests/rls_isolation.rsandtests/personal_tenant_seed.rs; the suite docstring cross-references both so the PMS-264 coverage reads as one set.#PMS-264