Skip to content

Commit 740affb

Browse files
committed
docs(verify): the RLS probe grant holds its set by name, not by row id
Two comments in rls.ts still described the grant resolution that ADR-0131 D3/D4 replaced: that the grant is keyed by row id and the resolver reads the set row to learn its name, and that resolvePermissionSets falls back to a sys_permission_set row that drops rowLevelSecurity. On main the resolver reads the grant's permission_set column and every definition source is the registry. The row is read only for the id the still-required permission_set_id column takes. Claude-Session: https://claude.ai/code/session_01M5baMwzrfukawVWc496yxD Co-authored-by: Claude <noreply@anthropic.com>
1 parent 9f5eca5 commit 740affb

1 file changed

Lines changed: 14 additions & 11 deletions

File tree

‎packages/verify/src/rls.ts‎

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -375,12 +375,12 @@ export function rlsProbePermissionSet(config: any): PermissionSet {
375375
* above.
376376
*
377377
* The probe set must be REGISTERED at boot, not written as a bare
378-
* `sys_permission_set` row: `PermissionEvaluator.resolvePermissionSets` resolves
379-
* a name from metadata first, the bootstrap list second, and the DB row only as
380-
* a last resort — and that last-resort loader hydrates `objects` / `fields` /
381-
* `systemPermissions` / `tabPermissions` but NOT `rowLevelSecurity`. A row-only
382-
* probe set would therefore grant the object bits and silently drop the
383-
* narrowing, which is the one thing that makes the persona a probe at all.
378+
* `sys_permission_set` row: [ADR-0131 D3/D4] a set's definition comes from the
379+
* registry alone — `PermissionEvaluator.resolvePermissionSets` reads metadata,
380+
* then the bootstrap list, then the security catalog, and none of the three
381+
* reads a `sys_permission_set` row. A row-only probe set would resolve nowhere
382+
* and grant nothing, narrowing included, which is the one thing that makes the
383+
* persona a probe at all.
384384
*
385385
* `appSecurityPluginOptions(config)` is carried through verbatim so the app's
386386
* declared default profile still resolves exactly as it does under `bootStack`'s
@@ -441,11 +441,14 @@ export async function provisionRlsProbePersona(
441441

442442
const probeSet = rlsProbePermissionSet(config);
443443

444-
// The grant is keyed by ROW ID, and `resolveUserAuthzGrants` reads the row
445-
// only to learn its NAME — the definition then resolves from the registered
446-
// bootstrap list (`rlsProbeSecurity`), which is the copy that carries the
447-
// narrowing. Find-or-create so it works whether or not this boot already
448-
// seeded the registered set into the table.
444+
// [ADR-0131 D4] The grant holds its set BY NAME: `resolveUserAuthzGrants`
445+
// reads the grant's `permission_set` column and takes the definition from
446+
// the registry (`rlsProbeSecurity`), the copy that carries the narrowing. It
447+
// reads neither `permission_set_id` nor this row. The row is read only for
448+
// its id, because `permission_set_id` is still a required column and the
449+
// platform derives the grant's name from it, refusing a disagreement.
450+
// Find-or-create so it works whether or not this boot already seeded the
451+
// registered set into the table.
449452
const existing = rowsOf(
450453
await ql.find('sys_permission_set', { where: { name: RLS_PROBE_PERMISSION_SET }, limit: 1 }, sysCtx),
451454
);

0 commit comments

Comments
 (0)