You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Found while implementing #8617 (per-organization audience-binding-suggestion reconciler). Filed as an observation, not a defect claim — the harm is unmeasured and the contract question underneath it is a maintainer call, not mine. Recording it so the next author does not have to re-derive it.
What is there
packages/plugins/plugin-security/src/permission-set-projection.ts exports the shared engine helpers used by the permission-set seeder and the package-door publish materializer:
SYSTEM_CTX there is { isSystem: true } with no tenantId, and upsertPackagePermissionSet in bootstrap-declared-permissions.ts writes sys_permission_set through those helpers — at boot, on a package-door permission publish, and from confirmAudienceBindingSuggestion when a suggestion's set is not yet materialized.
sys_permission_set declares no tenancy opt-out, so its organization_id is injected like any other tenant column. Measured on a real ObjectQL + SqlDriver engine under OS_TENANCY_POSTURE=isolated (the same rig as #8617):
call
result
insert under { isSystem: true }
stores organization_id NULL
find under { isSystem: true, tenantId: X }
sees X's rows and the NULL ones
So a package-declared permission set lands in the platform bucket (ADR-0120 D3) and is read by every tenant.
Why this is an observation and not a fix
Unlike sys_audience_binding_suggestion — whose header says rows are "resolved when a tenant admin confirms", which is what made #8617 a straightforward per-organization repair — a permission SET plausibly is installation-wide by design: the package ships one definition, and the per-tenant decision is the BINDING (sys_position_permission_set), not the set. On that reading an organization-less row is exactly right and nothing needs changing.
whether a tenant can create its own sys_permission_set row through the admin door, and how that row's organization_id interacts with the org-less package row of the same name — upsertPackagePermissionSet's provenance branches (managed_byplatform/user/absent ⇒ "env-authored, never clobbered") resolve ownership by provenance, never by organization.
Found while implementing #8617 (per-organization audience-binding-suggestion reconciler). Filed as an observation, not a defect claim — the harm is unmeasured and the contract question underneath it is a maintainer call, not mine. Recording it so the next author does not have to re-derive it.
What is there
packages/plugins/plugin-security/src/permission-set-projection.tsexports the shared engine helpers used by the permission-set seeder and the package-door publish materializer:SYSTEM_CTXthere is{ isSystem: true }with notenantId, andupsertPackagePermissionSetinbootstrap-declared-permissions.tswritessys_permission_setthrough those helpers — at boot, on a package-doorpermissionpublish, and fromconfirmAudienceBindingSuggestionwhen a suggestion's set is not yet materialized.sys_permission_setdeclares no tenancy opt-out, so itsorganization_idis injected like any other tenant column. Measured on a realObjectQL+SqlDriverengine underOS_TENANCY_POSTURE=isolated(the same rig as #8617):{ isSystem: true }organization_idNULL{ isSystem: true, tenantId: X }So a package-declared permission set lands in the platform bucket (ADR-0120 D3) and is read by every tenant.
Why this is an observation and not a fix
Unlike
sys_audience_binding_suggestion— whose header says rows are "resolved when a tenant admin confirms", which is what made #8617 a straightforward per-organization repair — a permission SET plausibly is installation-wide by design: the package ships one definition, and the per-tenant decision is the BINDING (sys_position_permission_set), not the set. On that reading an organization-less row is exactly right and nothing needs changing.What I did not measure, and what would decide it:
sys_position.nameis the third instance of the #8323 class: an admin-authored name on a tenant-scoped RBAC object carries an installation-wide unique index #8468 / Five more instances of the #8323 class: admin- and user-authored names on tenant-scoped objects still carry installation-wide unique indexes #8554 applies here too);sys_permission_setrow through the admin door, and how that row'sorganization_idinteracts with the org-less package row of the same name —upsertPackagePermissionSet's provenance branches (managed_byplatform/user/absent ⇒ "env-authored, never clobbered") resolve ownership by provenance, never by organization.Related
sys_position.nameis the third instance of the #8323 class: an admin-authored name on a tenant-scoped RBAC object carries an installation-wide unique index #8468 / Five more instances of the #8323 class: admin- and user-authored names on tenant-scoped objects still carry installation-wide unique indexes #8554 — the tenant-scoped declared unique index class.Filed unassigned. Found by session
session_01MX1qcBzfwZb5wkRrJTNbhH(dev seat for #8617).Generated by Claude Code