Skip to content

Commit 981b7c2

Browse files
committed
docs(permissions): the write-admission bypass row names the D10 organization-membership arm canWriteObject now runs
Row 6b of the system-context bypass table names every arm the elevated write-preview question runs; canWriteObject now also refuses, on a walled posture, a delegator who is not a member of the organization the request runs in. Claude-Session: https://claude.ai/code/session_01DPxprKQnzCbhdMTXUGRu31 Co-authored-by: Claude <noreply@anthropic.com>
1 parent 8bb2d5e commit 981b7c2

1 file changed

Lines changed: 1 addition & 1 deletion

File tree

‎content/docs/permissions/system-context.mdx‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ that silently does not happen.
102102
| 4 | Field-level security returns **all** fields | plugin-security | Get: every column readable (`getReadableFields`) and writable (`getWritableFields`). Lose: field masking | `packages/plugins/plugin-security/src/security-plugin.ts#resolveProjectionFieldMask` |
103103
| 5 | Export permission granted unconditionally | plugin-security | Get: `canExport` is `true` | `packages/plugins/plugin-security/src/security-plugin.ts#canExport` |
104104
| 6 | Object-level read admission granted unconditionally | plugin-security | Get: `canReadObject` is `true`. This is the OBJECT-level half of a read — "may this caller read this object at all" — which the doors that bypass this middleware ask before they compile a statement of their own; `getReadFilter` is its row-level half, and the two are not interchangeable | `packages/plugins/plugin-security/src/security-plugin.ts#canReadObject` |
105-
| 6b | WRITE admission granted unconditionally | plugin-security | Get: `canWriteObject` is `true`. The WRITE twin of the object-level read admission above, asked by the write PREVIEW (`ObjectQL.validate()`), which runs no middleware for its target object and so has no gate of its own. It exists because a validation rule that reads one hop through a reference field is evaluated against a related row fetched under system authority, and that elevation is bounded to the arms the question RUNS — named, ⛔ never a category of the write decision, and ⛔ not a promise the write would succeed. The arms: the ADR-0103 engine-owned affordance gate and the ADR-0090 D12 delegated-admin gate (both ahead of every resolution), the fail-closed postures (#3545's unresolvable posture and the D10 dangling delegator), the ADR-0066 D3 capability arm, the CRUD grant, the ADR-0090 D10 delegator arm that a bare CRUD-grant check misses, the field-level-security write gate over the caller's payload when one is supplied, and the ADR-0123 D2 no-active-organization wall | `packages/plugins/plugin-security/src/security-plugin.ts#canWriteObject` |
105+
| 6b | WRITE admission granted unconditionally | plugin-security | Get: `canWriteObject` is `true`. The WRITE twin of the object-level read admission above, asked by the write PREVIEW (`ObjectQL.validate()`), which runs no middleware for its target object and so has no gate of its own. It exists because a validation rule that reads one hop through a reference field is evaluated against a related row fetched under system authority, and that elevation is bounded to the arms the question RUNS — named, ⛔ never a category of the write decision, and ⛔ not a promise the write would succeed. The arms: the ADR-0103 engine-owned affordance gate and the ADR-0090 D12 delegated-admin gate (both ahead of every resolution), the fail-closed postures (#3545's unresolvable posture, the D10 dangling delegator and, on a walled posture, the D10 delegator who is not a member of the organization the request runs in), the ADR-0066 D3 capability arm, the CRUD grant, the ADR-0090 D10 delegator arm that a bare CRUD-grant check misses, the field-level-security write gate over the caller's payload when one is supplied, and the ADR-0123 D2 no-active-organization wall | `packages/plugins/plugin-security/src/security-plugin.ts#canWriteObject` |
106106
| 6c | The tenant wall's per-row verdict for the write PREVIEW answers **"not asked"** | plugin-security | Get: `writeWallVerdict` returns `null`, so `ObjectQL.validate()` treats the rows exactly as it does with no verdict registered: no row is refused by the Layer 0 tenant wall, and the elevated preview's `readonly` strips stay skipped as they always were. That is what the elevated write does: the whole security middleware short-circuits before step 3.7, so the wall never judges an elevated row's organization. Lose: nothing the write enforces. The verdict exists so a preview answers a row's organization as its write answers it (#25062), and an elevated write meets no tenant wall to answer for | `packages/plugins/plugin-security/src/security-plugin.ts#writeWallVerdict` |
107107
| 7 | Write bypass = `true`, effective write scope = `org` | plugin-security | Get: widest write scope without holding any capability | `packages/plugins/plugin-security/src/security-plugin.ts#start` |
108108
| 8 | Metadata-plane schema masking exempt (ADR-0106 D4) | metadata-core | Get: unmasked object schema. Note: the exemption is a **caller** property — it short-circuits before the security service is consulted | `packages/metadata-core/src/object-schema-fls.ts#isObjectSchemaMaskExempt` |

0 commit comments

Comments
 (0)