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
{{ message }}
Repository navigation
Gate the catalog actions with requiredPermissions — duly_catalog_apply is currently ungated #30
Sub-issue of #8, which is where the permission sets these need to name get created.
Found while implementing #5. Not fixed there: naming a capability that no permission set grants would either make the action uninvokable or leave a gate that grants nothing — and src/security/index.ts is #8's file surface, not #5's.
What is ungated
Both actions added in #5 declare no requiredPermissions:
duly_catalog_apply — creates a duly_duty for anysys_user id the caller passes, in bulk. A 26-item catalog against 40 people is 1,040 rows in one call.
duly_catalog_sync — rewrites cadence (frequency, due_anchor, due_offset_days, lead_days, grace_days) on every catalog-sourced duty in the org when position_code is omitted.
requiredPermissions is the real gate (ADR-0066 D4, enforced with a 403 on the platform action route and mirrored on the MCP bridge). visible/disabled are UI predicates and do not stop a request; neither action declares those either, and they would not help if it did.
Note this is not mitigated by object-level permissions: ctx.engine is the trusted facade — context-less and RLS/FLS-bypassing by design (#2849). The boundary for an action handler is the invoke-time capability gate, so with none declared there is nothing between a caller and a bulk write.
What to add
#8 already defines duly_admin as "catalog owners and rollout admins" — the right holder for both. Once that permission set exists:
// src/actions/catalog.actions.tsrequiredPermissions: ['<the duly_admin capability from #8>'],
on both CatalogApplyAction and CatalogSyncAction.
Worth considering as part of the same pass: whether duly_catalog_sync should require a narrower capability than apply. Applying a catalog to a new hire is routine onboarding; syncing org-wide rewrites authored cadence on duties people are already working to, and #5's PR notes it is deliberately reportable-after-the-fact for that reason.
Acceptance
both actions declare requiredPermissions naming a capability duly_admin actually grants
a test asserts the declaration (the same shape as the wiring assertions in test/catalog-instantiate.test.ts)
Activity
requiredPermissionstoo — same gap as the catalog actions #40Declare the security model, and gate all five actions