QONTO-WP-0004-T04: live flex-auth + tenant-engine authorization gate
Replaces the config-only QONTO_ASSISTANT_ENFORCE_SCOPE cached-claim check with two live-checked facts, per docs/SecurityPractice.md #4: 1. flex-auth POST /v1/check on finance.qonto.read for the calling actor/tenant (FlexAuthCheckClient, modeled on tenant-engine's own client for the same API). Registration lives in the flex-auth repo (examples/qonto-assistant/) -- rules + embedded tests verified with flex-auth test-policy/load-registry/check, and a live flex-auth serve hit by this exact client over real HTTP (not a mock). 2. tenant-engine's live capability-role lookup (GET /tenants/{id}/roles/live), denying unless the tenant currently holds one of QONTO_TENANT_ENGINE_REQUIRED_ROLES (default VEN,CUS) -- optional and additive to the flex-auth check. Both clients fail closed by construction (unreachable/malformed/non-2xx all deny, never grant), matching FlexAuthCheckClient's existing fail-closed philosophy elsewhere in the fleet. LiveAuthorizationGate combines both and is wired into CapabilityService._execute ahead of the internal policy kernel; off by default (no QONTO_FLEX_AUTH_URL set) so existing deployments are unaffected until configured. Verified beyond mocked unit tests: ran a real `flex-auth serve` loaded with the registered policy, and a real tenant-engine instance seeded with a VEN grant for tenant:friendly:binky, and exercised this repo's actual FlexAuthCheckClient/TenantEngineClient/LiveAuthorizationGate against both live processes over real HTTP -- allow for the correct tenant, live_authz_denied for a mismatched tenant. 28 new unit tests (flex_auth_client, tenant_engine_client, live_authorization_gate + CapabilityService integration). Full suite -> 80 passed; REST/MCP smokes and compileall still clean. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
parent
aa28ef353a
commit
1f0f979e36
12 changed files with 649 additions and 1 deletions
|
|
@ -207,6 +207,28 @@ That consumer-side write remains outside this repo.
|
|||
the current dogfood path remains `legacy_api_key` because that is the proven
|
||||
BINKY-WP-0005 header mode.
|
||||
|
||||
## Live authorization gate (flex-auth + tenant-engine)
|
||||
|
||||
Off by default (no `QONTO_FLEX_AUTH_URL` set). When configured, every
|
||||
capability call is gated on two live-checked facts before the internal
|
||||
policy kernel runs (docs/SecurityPractice.md §4):
|
||||
|
||||
1. **`flex-auth`**: `QONTO_FLEX_AUTH_URL` → a live `POST /v1/check` decision
|
||||
on `finance.qonto.read` for the calling actor/tenant. See
|
||||
`flex-auth/examples/qonto-assistant/` for the registered policy (rules +
|
||||
tests, verified with `flex-auth test-policy`/`load-registry`/`check` and
|
||||
a live `flex-auth serve` hit by this repo's actual `FlexAuthCheckClient`).
|
||||
2. **`tenant-engine`** (optional, additive): `QONTO_TENANT_ENGINE_URL` → a
|
||||
live `GET /tenants/{id}/roles/live` lookup, denying unless the tenant
|
||||
currently holds one of `QONTO_TENANT_ENGINE_REQUIRED_ROLES` (default
|
||||
`VEN,CUS`). Left unset, only the flex-auth check applies.
|
||||
|
||||
Both clients fail closed: an unreachable flex-auth or tenant-engine denies,
|
||||
it never grants. Deny reasons are `live_authz_denied` (flex-auth) and
|
||||
`tenant_role_denied` (tenant-engine) in the audit log — neither counts
|
||||
toward the deny-escalation lockout below, since a legitimate actor whose
|
||||
tenant simply isn't provisioned yet isn't a probing signal.
|
||||
|
||||
## Deny-escalation lockout
|
||||
|
||||
On by default (`QONTO_DENY_ESCALATION_ENABLED=true`). An actor who triggers
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue