Repository navigation
Commit f2d4371
fix(tenancy): make the isolation cases assert what their names claim
Round 1 of Step 11's review, and the finding was that three of the five cases
tested something other than their name — one of them nothing at all.
Write_With_Foreign_TenantId_Is_Rejected_By_WithCheck performed no INSERT. It
asserted that an anonymous POST failed, which a 404 satisfies, so it passed
against a DELETED endpoint and against a database with every policy dropped. It
now issues the INSERT on the ambient connection, naming a tenant other than the
announced one, and asserts the 42501 that WITH CHECK raises. Raw SQL
deliberately: a write through EF carries the filter's tenant and could never name
a foreign one.
Org_X_cannot_read_Org_Y read `organizations`, which is the tenant-WIDE class —
within a tenant every organization is visible to every other, by design — and the
narrowing came from a Where the probe handler wrote itself. It now reads
`tenant_settings`, the organization-scoped class, and narrows nothing.
TenantWide_Row_Of_TenantB_Is_Invisible_To_TenantA read `platform_host_to_tenant`,
which is platform-scoped and whose policy has no organization term, so it named
the wrong mechanism entirely. It now reads the row shape the superseded template
actually leaked: tenant-owned, organization_id IS NULL.
Unsetting_tenant_context never reached a handler or read a table — it duplicated
an existing 404-parity assertion more weakly. It now runs a tenant-owned SELECT
under a PlatformHost request, which is the only way to put a real query in front
of an unresolved context.
The remark about what the suite constrains was half a measurement. Deleting both
query filters leaves all five green because RLS holds; disabling RLS leaves the
four reads green because the filters hold; removing both turns all five red. Both
directions are now recorded, along with the write case being the one that
observes a policy alone.
Also: the file moved under Database/, where Standards 06 puts Docker-bound tests
and where the trait guard can see it; the probe returns ToActionResult() so a
refusal is a status rather than a 200 with an empty body; and two Packet 7
comments the sweep missed.
Module: Tenancy
ADR: 0003, 0036
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>1 parent a7bab71 commit f2d4371
3 files changed
Lines changed: 583 additions & 428 deletions
File tree
- backend/tests/LearnStack.Tests.Integration
- Database
0 commit comments