|
| 1 | +--- |
| 2 | +"@objectstack/plugin-security": minor |
| 3 | +--- |
| 4 | + |
| 5 | +ADR-0095 D1: tenant isolation is now **Layer 0** — an independent, always-first, |
| 6 | +AND-composed filter (`tenant-layer.ts`), no longer a wildcard `tenant_isolation` |
| 7 | +RLS policy OR-merged with business RLS. The effective row filter is |
| 8 | +`Layer0(tenant) AND Layer1(business RLS)`; the two share no compiler, merge step, |
| 9 | +or bypass bit. The superuser bypass now exempts the tenant wall only as a Layer 0 |
| 10 | +rule (platform-admin posture + object posture permits: private / platform-global |
| 11 | +/ better-auth-managed), never via a business-RLS short-circuit. |
| 12 | + |
| 13 | +**BREAKING (multi-org `tenancy.mode = 'multi'` deployments only; `single` mode is |
| 14 | +inert and unchanged).** Retiring the OR-merged tenant policy resolves four |
| 15 | +behavior deltas, all toward stronger/correcter isolation: |
| 16 | + |
| 17 | +- **(a) Cross-tenant read leak closed.** A permissive business RLS policy (e.g. |
| 18 | + `status == 'public'`) no longer OR-widens tenant scope; a foreign-org row it |
| 19 | + matched is now invisible. |
| 20 | +- **(b) Member by-id writes narrow to owner-only.** The OR-merge silently widened |
| 21 | + `owner_only_writes` (`created_by == me`) back to org-wide, so a member could |
| 22 | + by-id update/delete *any* record in their org. Writes are now owner-scoped as |
| 23 | + authored. **Migration:** if your deployment intentionally relied on members |
| 24 | + editing each other's records org-wide, grant an explicit per-object edit |
| 25 | + permission set (position-distributed) where that is wanted — the baseline |
| 26 | + `member_default` no longer permits it. |
| 27 | +- **(c) Global-catalog objects visible to members.** On a `tenancy.enabled:false` |
| 28 | + object, members were scoped by a phantom `organization_id` filter (a column |
| 29 | + such objects lack); Layer 0 correctly treats them as non-tenant, so the global |
| 30 | + catalog is visible. |
| 31 | +- **(e) No-active-org writes fail closed.** A write by a principal with no active |
| 32 | + organization on a tenant object is now denied (was owner-scoped only). |
| 33 | + |
| 34 | +`tenant_isolation` is retired from the seeded `organization_admin` / |
| 35 | +`member_default` / `viewer_readonly` sets; the `_self` / `_org` identity-table |
| 36 | +carve-outs and `owner_only_writes/deletes` are unchanged. Customized seeded sets |
| 37 | +keep their overlays (ADR-0094). The driver-level `applyTenantScope` seam is |
| 38 | +untouched. See ADR-0095 and framework#2936 (the `extractTargetField` `==` blind |
| 39 | +spot this exposes, tracked separately). |
0 commit comments