test(isolation): automate PMS-236 tenant-isolation QA across the API #216
Loading…
Reference in a new issue
No description provided.
Delete branch "feat/pms-236-tenant-isolation-integration-test"
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?
Summary
Automates the PMS-236 tenant-isolation QA plan as a Rust integration suite (
tests/tenant_isolation.rs): 8#[sqlx::test]cases that drive the real HTTP API with a Bearer token per tenant, against two tenants each carrying the full seeded lookup set and a tenant-scopedadminuser. Closes PMS-236.The issue was framed as a manual QA pass; the chosen form is automation so the invariants are regression-protected in CI.
Coverage (AC mapping)
cross_tenant_idor_reads_return_404(AC #4): B gets 404 for A's company/contact/site/ticket ids (existence-hiding, never 403); A reads its own.cross_tenant_admin_cannot_read_other_tenant(AC #5): a tenant-scopedadmin(not super_admin) is denied another tenant's row with 403. Actors areadminbecause super_admin is the cross-tenant system role and would mask the guard.search_and_list_do_not_leak_across_tenants(AC #2/#6): full and partial (trigram)q=searches on tickets/companies/contacts return zero of A's rows from B.ticket_number_sequence_is_per_tenant(AC #2): both tenants' first ticket share a number; a global sequence would offset B by A's volume.deletion_is_tenant_scoped(AC #3).settings_and_branding_are_tenant_scoped(AC #8): tenant_settings,tenants.branding, andmodule_configstay at B's defaults when A writes.users_are_tenant_scoped(AC #9 users): A's admin cannot list or manage B's users; same email in both tenants scopes the session to onetenant_id.rls_read_scoping_with_guc(AC #9 RLS): two real tenants under aNOBYPASSRLSrole withapp.current_tenantset to B - B's row visible, A's hidden by the policy, so the result does not depend on the fail-open default.Relationship to the sibling suites (not a duplicate)
Documented in the module header:
per_user_isolation.rs(PMS-264) pins cross-module read/write denial betweentechnicianactors;rls_isolation.rs(PMS-257) pins the fail-closed +WITH CHECKDB-engine face. This file adds the admin-role cross-tenant guard, search scoping,ticket_number, settings/branding/module isolation, and user scoping.Findings for follow-up (filed separately, not in this PR)
TenantService::create_tenantomits the NOT-NULLtenants.kindcolumn and 500s with SQLSTATE 23502; no existing test exercises that INSERT, so the defect is latent (POST /api/v1/tenantswould fail). The suite sidesteps it by provisioning viaensure_personal_tenant.Verification
cargo test -p mokosh-server --test tenant_isolation: 8 passed, 0 failed (against postgres:18.2-alpine, the CI image).cargo fmt --all --checkclean;cargo clippy --test tenant_isolationclean.