Found while correcting the managed-object-write-denies.ts docblock for #13822
(PR #14028). Comment-only card; this is a behaviour observation deliberately
left out of that PR and filed instead. Read from source on origin/main at
c54d4d3d7; not reproduced against a running kernel.
The gap
MANAGED_DENY_TARGET_SETS is an exact-match allowlist of four names, and
applyManagedWriteDenies matches on it exactly:
const targets = new Set(MANAGED_DENY_TARGET_SETS);
...
if (!set || !targets.has((set as { name?: string }).name ?? '')) continue;
organization_admin_no_bypass is not one of the four. It nevertheless holds a
write-granting wildcard: deriveWallLessOrgAdmin (end of
objects/default-permission-sets.ts) copies organization_admin and removes
only the two superuser bits —
const { viewAllRecords: _v, modifyAllRecords: _m, ...wildcardWithoutBypass } =
(objects['*'] ?? {}) as ...; // Record cast elided: angle brackets do not
// survive GitHub's body sanitizer
objects['*'] = wildcardWithoutBypass;
— so allowCreate / allowEdit / allowDelete stay true on its '*'.
The derived variant IS in the array the injection walks: defaultPermissionSets
inserts it directly after its parent, and SecurityPlugin's
bootstrapPermissionSets defaults to that array
(options.defaultPermissionSets ?? securityDefaultPermissionSets), which is
what runBootstrap hands to applyManagedWriteDenies at kernel:ready. So the
variant is walked and skipped, not absent.
And the derivation cannot inherit the injection later: it is a shallow copy
taken at module load ({ ...(base.objects ?? {}) }), while the injection is an
in-place mutation of the parent's objects at kernel:ready. Entries injected
into organization_admin therefore never reach the variant.
Why it matters
The variant does carry the static baseline, because organization_admin's
literal spreads ...denyWritesOnManagedObjects() and the copy takes it. The gap
is exactly the one the registry-driven module exists to close: a schema that
declares managedBy: 'better-auth' but is not in the hand-maintained
BETTER_AUTH_MANAGED_OBJECTS list gets an injected deny in
organization_admin and nothing in organization_admin_no_bypass, where
the wildcard then grants create / edit / delete on it.
That is ADR-0092's drift, one posture over. And it is not an obscure posture:
auto-org-admin-grant grants this variant precisely when the deployment
enforces no organization wall, i.e. where the bits are least bounded.
There is no gap today — the static list covers the 30 managed tables the
tree currently declares. The gap opens on the next managedBy: 'better-auth'
schema that lands without an edit to that list, which is the scenario the module
was written for.
Why it reads as an oversight rather than a decision
The one set deliberately excluded from the target list is documented as such in
the MANAGED_DENY_TARGET_SETS docblock (admin_full_access keeps its
unqualified wildcard so an admin can rescue data directly). The derived variant
is named nowhere in that rationale, nor in deriveWallLessOrgAdmin's docblock,
whose stated contract is the opposite: "everything else (object grants,
managed-write denies, anti-escalation RBAC read-only rules, system
permissions, the 15 identity RLS carve-outs) is carried over verbatim" and "the
only intended delta is the superuser bits". Carried over verbatim is true of the
compile-time baseline and false of the registry union.
Nothing pins it
managed-object-write-denies.test.ts and bootstrap-platform-admin.test.ts
contain no reference to the variant (git grep -n 'ORGANIZATION_ADMIN_NO_BYPASS\|no_bypass' over both: zero hits; the same grep
over objects/default-permission-sets.test.ts returns four, so the search is
live).default-permission-sets.test.ts's managed-denies pin iterates
MANAGED_DENY_TARGET_SETS itself, so it asserts the four members and is
structurally unable to see a fifth set that should have been one.
Options, not a recommendation to apply blind
- Add
ORGANIZATION_ADMIN_NO_BYPASS to MANAGED_DENY_TARGET_SETS. One line,
matches the module's stated intent. Needs a look at whether the variant's own
sys_api_key-style explicit entries still survive (they should: the
injection skips any object the set already names). - Derive the variant AFTER the union instead of at module load, so
"carried over verbatim" becomes true again. Larger, and it moves a
module-load constant into kernel:ready ordering. - Rule it deliberate and say so in the docblock, the way
admin_full_access
is. This is the option that needs a maintainer, not a dev: it means the
wall-less variant is allowed to write identity tables the walled one cannot.
Whichever way it goes, the pin should stop iterating MANAGED_DENY_TARGET_SETS
to check membership — a list checked against itself is the reason this survived.
Filed unassigned, for triage. Behaviour-class, out of scope for #13822, which is
prose only.
Generated by Claude Code
Generated by Claude Code
Found while correcting the
managed-object-write-denies.tsdocblock for #13822(PR #14028). Comment-only card; this is a behaviour observation deliberately
left out of that PR and filed instead. Read from source on
origin/mainatc54d4d3d7; not reproduced against a running kernel.The gap
MANAGED_DENY_TARGET_SETSis an exact-match allowlist of four names, andapplyManagedWriteDeniesmatches on it exactly:organization_admin_no_bypassis not one of the four. It nevertheless holds awrite-granting wildcard:
deriveWallLessOrgAdmin(end ofobjects/default-permission-sets.ts) copiesorganization_adminand removesonly the two superuser bits —
— so
allowCreate/allowEdit/allowDeletestaytrueon its'*'.The derived variant IS in the array the injection walks:
defaultPermissionSetsinserts it directly after its parent, and
SecurityPlugin'sbootstrapPermissionSetsdefaults to that array(
options.defaultPermissionSets ?? securityDefaultPermissionSets), which iswhat
runBootstraphands toapplyManagedWriteDeniesatkernel:ready. So thevariant is walked and skipped, not absent.
And the derivation cannot inherit the injection later: it is a shallow copy
taken at module load (
{ ...(base.objects ?? {}) }), while the injection is anin-place mutation of the parent's
objectsatkernel:ready. Entries injectedinto
organization_admintherefore never reach the variant.Why it matters
The variant does carry the static baseline, because
organization_admin'sliteral spreads
...denyWritesOnManagedObjects()and the copy takes it. The gapis exactly the one the registry-driven module exists to close: a schema that
declares
managedBy: 'better-auth'but is not in the hand-maintainedBETTER_AUTH_MANAGED_OBJECTSlist gets an injected deny inorganization_adminand nothing inorganization_admin_no_bypass, wherethe wildcard then grants create / edit / delete on it.
That is ADR-0092's drift, one posture over. And it is not an obscure posture:
auto-org-admin-grantgrants this variant precisely when the deploymentenforces no organization wall, i.e. where the bits are least bounded.
There is no gap today — the static list covers the 30 managed tables the
tree currently declares. The gap opens on the next
managedBy: 'better-auth'schema that lands without an edit to that list, which is the scenario the module
was written for.
Why it reads as an oversight rather than a decision
The one set deliberately excluded from the target list is documented as such in
the
MANAGED_DENY_TARGET_SETSdocblock (admin_full_accesskeeps itsunqualified wildcard so an admin can rescue data directly). The derived variant
is named nowhere in that rationale, nor in
deriveWallLessOrgAdmin's docblock,whose stated contract is the opposite: "everything else (object grants,
managed-write denies, anti-escalation RBAC read-only rules, system
permissions, the 15 identity RLS carve-outs) is carried over verbatim" and "the
only intended delta is the superuser bits". Carried over verbatim is true of the
compile-time baseline and false of the registry union.
Nothing pins it
managed-object-write-denies.test.tsandbootstrap-platform-admin.test.tscontain no reference to the variant (
git grep -n 'ORGANIZATION_ADMIN_NO_BYPASS\|no_bypass'over both: zero hits; the same grepover
objects/default-permission-sets.test.tsreturns four, so the search islive).
default-permission-sets.test.ts's managed-denies pin iteratesMANAGED_DENY_TARGET_SETSitself, so it asserts the four members and isstructurally unable to see a fifth set that should have been one.
Options, not a recommendation to apply blind
ORGANIZATION_ADMIN_NO_BYPASStoMANAGED_DENY_TARGET_SETS. One line,matches the module's stated intent. Needs a look at whether the variant's own
sys_api_key-style explicit entries still survive (they should: theinjection skips any object the set already names).
"carried over verbatim" becomes true again. Larger, and it moves a
module-load constant into kernel:ready ordering.
admin_full_accessis. This is the option that needs a maintainer, not a dev: it means the
wall-less variant is allowed to write identity tables the walled one cannot.
Whichever way it goes, the pin should stop iterating
MANAGED_DENY_TARGET_SETSto check membership — a list checked against itself is the reason this survived.
Filed unassigned, for triage. Behaviour-class, out of scope for #13822, which is
prose only.
Generated by Claude Code
Generated by Claude Code