Skip to content

feat(dogfood): owner-isolated RLS fixture — hard, revert-provable #1994 gate - #2037

Merged
os-zhuang merged 1 commit into
mainfrom
feat/dogfood-rls-fixture
Jun 18, 2026
Merged

os-zhuang merged 1 commit into
mainfrom
feat/dogfood-rls-fixture

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

Why

The cross-owner RLS proof runner (src/rls.ts, from #2032) was unit-proven but had nothing live to exercise it. The harness boots single-tenant, so the org tenant_isolation policy is stripped and a fresh member falls back to member_default (broad read) — every object reports member-visible, so the #1994 invariant ("a user who cannot READ a record must not be able to WRITE it") never actually fired against an app.

Note: #2032's branch was removed before this work, so this PR also carries the #2032 runner commit (c3492faee) it builds on.

What

Two faithful ways to create real cross-owner isolation, both now live:

1. Owner-scoped fixture — the hard gate

test/rls-fixture.dogfood.test.ts + test/fixtures/rls-owner-fixture.ts: a one-object app (rls_note) whose member fallback permission set carries RLS.ownerPolicy('rls_note','created_by'). The predicate keys on created_by/current_user.id (not organization_id), so it survives single-tenant stripping — a fresh member genuinely can't read the admin's note.

2. Org-scoped / multi-tenant

test/rls-multitenant.dogfood.test.ts: bootDogfoodStack now takes { multiTenant: true }, registering plugin-org-scoping before SecurityPlugin so organization_id policies apply. CRM flips from every object member-visible (single-tenant) to 4 consistent / 0 holes / 0 member-visible — confirming the member-visible result was single-tenant RLS-stripping, not a broad-read default (the model real apps like hotcrm rely on). hotcrm isn't in this repo, so this validates against the in-repo CRM example and documents the path.

Harness

BootOptions gains security? (SecurityPlugin override for the fixture fallback) and multiTenant?. README documents both gates + the revert proof; the stale "next step" note in the single-tenant smoke now points at the two new tests.

Verification

🤖 Generated with Claude Code

@vercel

vercel Bot commented Jun 18, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
spec Ready Ready Preview, Comment Jun 18, 2026 12:53pm

Request Review

… gate

The cross-owner RLS proof runner (src/rls.ts, #2032) was unit-proven but had
nothing live to exercise it: the harness boots single-tenant, so the org
tenant_isolation policy is stripped and a fresh member falls back to
member_default (broad read) — every object reports `member-visible`, so the
#1994 by-id-write invariant ("can't read ⇒ can't write") never fired live.

Two faithful ways to create real isolation, both now live:

1. Owner-scoped fixture (test/rls-fixture.dogfood.test.ts + fixtures/):
   one object `rls_note` whose member fallback permission set carries
   RLS.ownerPolicy('rls_note','created_by'). Keyed on created_by/current_user.id
   (not organization_id), so it survives single-tenant stripping — a fresh
   member genuinely can't read the admin's note.
   - GREEN: owner policy on `all` ops → rls-consistent (pre-image check denies
     the by-id write).
   - AUTOMATED RED: owner policy on `select` only → rls-hole (read scoped, no
     write policy applies, by-id write lands) — #1994 hole class every CI run.
   - MANUAL REVERT PROOF (README): disabling the pre-image check flips the green
     fixture to "GET 404 yet MUTATED it by id (PATCH 200)". Verified, restored.

2. Multi-tenant org-scoped (test/rls-multitenant.dogfood.test.ts):
   bootDogfoodStack gains `{ multiTenant: true }` → registers plugin-org-scoping
   before SecurityPlugin so organization_id policies APPLY. CRM flips from
   every-object-member-visible (single-tenant) to 4 consistent / 0 holes /
   0 member-visible — confirming member-visible was single-tenant RLS-stripping,
   not a broad-read default (the model real apps like hotcrm rely on).

harness: BootOptions gains `security?` (SecurityPlugin override for the fixture
fallback) and `multiTenant?`. README documents both paths + the revert proof.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@os-zhuang
os-zhuang force-pushed the feat/dogfood-rls-fixture branch from 1e1413a to a2316e6 Compare June 18, 2026 12:49
@github-actions github-actions Bot added size/m documentation Improvements or additions to documentation dependencies Pull requests that update a dependency file tests labels Jun 18, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

No hand-written docs reference the 1 changed package(s). ✅

@os-zhuang
os-zhuang merged commit a2316e6 into main Jun 18, 2026
15 of 16 checks passed
@os-zhuang
os-zhuang deleted the feat/dogfood-rls-fixture branch June 18, 2026 12:50

This branch was successfully deployed

2 active deployments
Production — a2316e64 Deployed Jun 18, 2026 by vercel[bot]
Preview — a2316e64 Deployed Jun 18, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Pull requests that update a dependency file documentation Improvements or additions to documentation size/m tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant