Auth & Security

Clearing Entitlements

The capability plane — what it gates, its report / strict / off enforcement postures, unprovisioned grace, and tenant-scoped evaluation.

RBAC answers "may this caller do this?"; entitlements answer a different question — "is this tenant provisioned for this capability?" They run as a separate plane alongside authorization, and a request must satisfy both.

Two gates, not one

A caller can be a tenant admin (passes RBAC) and still be refused a workflow publish because the tenant is not entitled to that workflow type. RBAC gates the identity; entitlements gate the tenant's plan. This page covers the auth behavior of the entitlement plane; for the plan/quota model see Concepts → Entitlements.

What the plane gates

Entitlement checks are wired at specific enforcement points where a tenant's plan should constrain behavior:

SurfaceGated operationsRequirement prefix
Workflow lifecycleStart, publish, and schedule-activation of a workflow definitionworkflow.start / workflow.publish / workflow.schedule
Routing strategySelecting a routing/pipeline strategystrategy.* / strategy.pipeline.*
Queue admissionQueue-admission governance operationsrouting.admission.<operation>
Connector executionProvider use; action, trigger, resolver, proxy, sync, and function executionconnector.action.* / connector.trigger.*

Each check builds a subject (e.g. {Kind: "workflow.definition", Key: <type>}) and a requirement key, then evaluates it against the tenant's entitlement snapshot.

Enforcement postures

The behavior when a tenant's required entitlement is missing, stale, or the evaluator is unavailable is controlled by one setting:

export DUCTOR_ENTITLEMENT_ENFORCEMENT=report   # report | strict | off
ModeBehaviorWhen to use
report (default)Evaluate and admit, but emit a loud grace-admit event for every request that would be denied under strict.Safe migration default — no outage, but not a silent fail-open.
strictFail closed on missing/stale/unavailable facts for the enforced surfaces. Explicit denies always deny.Production, once snapshots are populated.
offLegacy fail-open (deny-list only): explicit denies still deny, everything else admits. Announced once at startup.Escape hatch / legacy compatibility.

Read the table with one rule in mind: the posture only decides what happens when a fact is missing, stale, or unavailable. An explicit deny denies in every mode, including off:

explicit deny explicit allow missing / stale report off strict yes, never onboarded no request fact present? denied, all modes admitted enforcement admitted + grace-admit event unprovisioned grace?

`report` is a migration ramp, not a destination

Report mode lets you turn entitlements on and watch exactly which requests would be denied — via the grace-admit events — before flipping to strict. An invalid enforcement value is treated as a visible misconfiguration: it is logged and falls back to the safe report posture rather than crashing boot or silently fail-opening.

Unprovisioned grace

strict mode alone would instantly deny tenants that have never been onboarded to any entitlement source. The unprovisioned grace softens exactly that case:

export DUCTOR_ENTITLEMENT_GRACE_UNPROVISIONED=true   # default

When true (the default), a tenant that has no entitlement source and no snapshot at all is admitted under a loud, observable bootstrap grace — so enabling strict does not instantly lock out un-onboarded tenants. Genuine gaps still fail closed: a stale snapshot, a present-but-incomplete snapshot, or a tenant that has sources but no snapshot are all denied. Set it to false to remove the grace entirely.

Tenant-scoped evaluation

Every entitlement check is evaluated in the tenant's context — there is no global entitlement decision. A check that cannot resolve a tenant is refused rather than admitted: the enforced surfaces require tenant-scoped evaluation, and a missing tenant context yields ErrEntitlementDenied. Environment-qualified checks resolve the environment first; an archived or locked environment cannot satisfy an entitlement check.

Startup posture logging

On boot the entitlement service logs its resolved enforcement posture, so an operator can confirm from the logs whether the deployment is running in report, strict, or off — and whether unprovisioned grace is on.

Where the plan itself lives

Entitlements gate against a tenant's snapshot; how that snapshot maps to plans and quotas — including hot-path quota enforcement — is covered in Concepts → Entitlements, while the Stripe billing integration that populates plan tiers is documented in Billing & Usage → Plans.