Commit 04c56aa
* feat(security): fail-closed authored-row-write verdict on ISecurityService (#5493 step 1) (#6735)
`ISecurityService` gains an optional, verdict-shaped, by-id method
`checkAuthoredRowWrite(object, recordId, operation, context)` returning
`'admit' | 'abstain'`, plus `AuthoredRowWriteVerdict` /
`AuthoredRowWriteOperation`.
The question it answers is the one no existing surface could: does an
APP-AUTHORED row-level policy admit this row for this write, on its own,
with the platform's ownership floor taken out by PROVENANCE?
Every other method reports the COMPOSED RLS verdict, and inside that
composition sits the platform's own wildcard write floor (`created_by ==
current_user.id`, on the `member_default` baseline every authenticated
member resolves). #5493 probe E-A measured the gap: a creator who is no
longer the owner is admitted by the floor and refused by sharing with a
byte-identical envelope, so a deferral keyed on the composed answer hands
transferred records back to their former creators.
Implementation reuses the #6684 provenance split — the SAME
`computeLayeredRlsFilter` the middleware enforces with, driven by the SAME
`dropPlatformOwnershipFloor` knob. No second RLS evaluator. A null Layer 1
is read as `abstain` (nothing authored is gating the write), and Layer 0
stays AND-ed in so the tenant wall holds.
Fail-closed in the `abstain` direction throughout: the method is OPTIONAL,
so a deployment without it behaves byte-for-byte as today; a principal-less
or on-behalf-of context, an unresolvable probe and a thrown lookup all
return `abstain`, and nothing throws outward.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011sGk4SKHqGRgmmqUok1P8M
* chore(spec): regenerate the contracts API-surface snapshot for the new verdict types (#6735)
`check:api-surface` reported 0 breaking / 2 added — the expected additive
product of declaring `AuthoredRowWriteVerdict` and `AuthoredRowWriteOperation`
on the security-service contract. Regenerated with
`pnpm --filter @objectstack/spec gen:api-surface`; the delta is exactly those
two entries.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011sGk4SKHqGRgmmqUok1P8M
---------
Co-authored-by: Claude <noreply@anthropic.com>
1 parent 43a7a8d commit 04c56aa
6 files changed
Lines changed: 835 additions & 2 deletions
File tree
- .changeset
- packages
- plugins/plugin-security/src
- spec
- api-surface
- src/contracts
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
0 commit comments