MotirBuilding in public
MOTIR · moooon
onMotir
You’re viewing a public project. Anyone can view it — no account needed. Sign in to submit, upvote, or comment on requests.View-only — you can’t edit work items
MOTIR-42

1.3.6 Project isolation E2E + direct-DB RLS test

Done
Description

Estimate: 16m · Depends on: 1.3.2, 1.3.4

The Story-closing test that proves project-level multi-tenancy is structural, mirroring 1.2.7's two-layer approach. (1) E2E (Playwright, @smoke): user A in workspace A cannot see or act on workspace B's projects — switching the active workspace shows only that workspace's projects, and any project-scoped Server Action / endpoint operating on a foreign project is refused (cross-tenant returns 404, not 403, per the Story AC and 1.2.7's anti-enumeration rule). (2) Direct-DB (Vitest, SET LOCAL ROLE prodect_app): a transaction without the app.workspace_id GUC sees zero project rows; with workspace A's GUC sees only A's projects; cross-workspace UPDATE affects zero rows; INSERT for a non-matching workspace is denied.

Reuse, don't reinvent: the E2E helpers (db-reset, email-capture), the signUp helper, and the rate-limit env-gate (E2E_DISABLE_RATE_LIMIT, already on main per finding #9) from 1.2.6/1.2.7. The RLS test reuses the SET LOCAL ROLE prodect_app harness from tests/multi-tenant-rls.test.ts.

Acceptance criteria

  • tests/e2e/project-isolation.spec.ts (@smoke): the project switcher shows only the active workspace's projects; a cross-tenant project-scoped action returns 404 (not 403, not 200). Passes locally + CI, no flakes (verify with --repeat-each).
  • tests/project-rls.test.ts: no-GUC → zero project rows; workspace-A GUC → only A's projects; cross-workspace UPDATE → 0 rows; cross-workspace INSERT → RLS denial (42501) — all under prodect_app.
  • Cascade re-verified: deleting a workspace removes its projects (and their future work items by extension).
  • All quality gates green; prior suites stay green.

Context refs

  • tests/e2e/multi-tenant-isolation.spec.ts + tests/multi-tenant-rls.test.ts from 1.2.7 — the exact two-layer patterns to mirror
  • tests/e2e/_helpers/{db-reset,email-capture}.ts + tests/e2e/workspace-flows.spec.ts's signUp helper
  • playwright.config.ts — the E2E_DISABLE_RATE_LIMIT env-gate (finding #9)
  • PRODECT_FINDINGS.md #5 (RLS inert under superuser) — why the role switch is mandatory
Status
Done
Type
Sub-task