Enforce tenant module entitlements beyond requests

This commit is contained in:
2026-08-04 09:29:36 +02:00
parent d6e7c8b0b1
commit 40c10089ab
28 changed files with 1692 additions and 286 deletions
+21
View File
@@ -1278,6 +1278,27 @@ runtime activation with the active tenant's effective entitlement. Entitlement
does not grant a permission. Access authorization must still allow every API
operation and resource.
The same boundary applies outside authenticated request handling:
- capability factories retain their owning module, and tenant-scoped capability
lookup treats a provider that is unavailable to the tenant as absent;
- workers partition scheduled scans by tenant before claiming rows;
- new work is rejected while a module is unavailable, while already accepted
durable work remains in provider-owned storage and is reported as
`operator_action_required` instead of being dropped or executed;
- Workflow, Dataflow, event consumers, reconciliation jobs, and external-effect
outboxes run inside a tenant execution context, so their optional capability
calls inherit the same provider checks;
- public signed-link modules declare a `public_tenant_resolver`; valid token
context is resolved before the route runs and the module entitlement is then
enforced without requiring an authenticated principal.
Entitlement resolution uses a bounded process-local cache. A local policy
mutation invalidates its tenant entry immediately; changes made by another node
become authoritative after `TENANT_MODULE_ENTITLEMENT_CACHE_TTL_SECONDS`
(five seconds by default). This is a bounded staleness optimization, not an
authorization grant: a cache miss or resolution failure fails closed.
Users and groups do not own another module-runtime state. Every WebUI module
already contributes a root `<module>.module` View surface, so personal and
group module visibility is expressed through Views. View policy controls who