--- id: qonto-assistant.finance-read name: qonto-assistant finance.qonto.read authorization namespace: qonto-assistant:finance version: v1 status: ready package: flexauth.qonto_assistant.finance_read actions: - finance.qonto.read owner: team:platform-security fixtures: - policy_fixtures.yaml caring: profile: caring-0.4.0-rc2 enforce: false canonical_roles: - Operator organization_relations: - ServiceProvider - Customer scopes: - level: Tenant id: tenant:friendly:binky tenant: tenant:friendly:binky planes: - Data - Audit capabilities: - View - Audit exposure_modes: - Masked conditions: - Logged restrictions: - PrivilegeEscalationBlocked activation: mode: local metadata: source: examples/qonto-assistant/policy_package.md flex_auth_contract: protected-system-v0 --- # qonto-assistant finance.qonto.read authorization This package authorizes `qonto-assistant`'s read surface (`QONTO-WP-0004-T04`'s live authorization gate). `qonto-assistant` keeps custody of the bank credential and its own default-deny policy kernel (spend/transfer/card/write tools are hard-denied there and never reach this policy); flex-auth decides whether a specific *actor* may use the `finance.qonto.read` capability at all. **Scope note:** this policy governs *who may call `finance.qonto.read`* (an actor/tenant question) — it does not evaluate a *tenant's* capability roles or plan status (`PLTF`/`IAM`/`VEN`/`CUS`, ADR-0014). Those are tenant state `qonto-assistant` checks separately via `tenant-engine`'s live-lookup endpoint (`GET /tenants/{id}/roles/live`); conflating the two here would authorize the wrong thing, exactly as tenant-engine's own `policy_package.md` notes for its analogous case. Single-tenant dogfood today (`tenant:friendly:binky` only); generalizing to other tenants is a policy update here, not a `qonto-assistant` code change. ## Rules ```rego import future.keywords.contains import future.keywords.if import future.keywords.in valid_actions := {"finance.qonto.read"} valid_subject_types := {"agent", "human", "service"} known_tenant := "tenant:friendly:binky" decision := {"effect": "allow", "reason": "finance_read_policy_matched"} if { allowed } else := {"effect": "deny", "reason": first_denial} if { true } allowed if { input.resource.system == "qonto-assistant" input.action in valid_actions input.subject.type in valid_subject_types input.tenant == known_tenant } default first_denial := "no_matching_rule" first_denial := "wrong_system" if { input.resource.system != "qonto-assistant" } else := "unknown_action" if { not input.action in valid_actions } else := "wrong_subject_type" if { not input.subject.type in valid_subject_types } else := "wrong_tenant" if { input.tenant != known_tenant } ``` ## Tests ```rego test package flexauth.qonto_assistant.finance_read_test import future.keywords.if import data.flexauth.qonto_assistant.finance_read base_request := { "id": "check:qonto-assistant-read", "tenant": "tenant:friendly:binky", "subject": {"id": "agent-harness-binky", "type": "agent"}, "action": "finance.qonto.read", "resource": {"id": "finance-snapshot", "type": "finance-snapshot", "system": "qonto-assistant"} } test_agent_read_allowed if { finance_read.decision.effect == "allow" with input as base_request } test_human_read_allowed if { finance_read.decision.effect == "allow" with input as { "tenant": "tenant:friendly:binky", "subject": {"id": "bernd.worsch", "type": "human"}, "action": "finance.qonto.read", "resource": {"id": "finance-snapshot", "type": "finance-snapshot", "system": "qonto-assistant"} } } test_wrong_system_denied if { finance_read.decision.reason == "wrong_system" with input as { "tenant": "tenant:friendly:binky", "subject": {"id": "agent-harness-binky", "type": "agent"}, "action": "finance.qonto.read", "resource": {"id": "x", "type": "finance-snapshot", "system": "some-other-system"} } } test_unknown_action_denied if { finance_read.decision.reason == "unknown_action" with input as { "tenant": "tenant:friendly:binky", "subject": {"id": "agent-harness-binky", "type": "agent"}, "action": "finance.qonto.transfer", "resource": {"id": "finance-snapshot", "type": "finance-snapshot", "system": "qonto-assistant"} } } test_wrong_subject_type_denied if { finance_read.decision.reason == "wrong_subject_type" with input as { "tenant": "tenant:friendly:binky", "subject": {"id": "unknown-device", "type": "device"}, "action": "finance.qonto.read", "resource": {"id": "finance-snapshot", "type": "finance-snapshot", "system": "qonto-assistant"} } } test_wrong_tenant_denied if { finance_read.decision.reason == "wrong_tenant" with input as { "tenant": "tenant:friendly:some-other-company", "subject": {"id": "agent-harness-binky", "type": "agent"}, "action": "finance.qonto.read", "resource": {"id": "finance-snapshot", "type": "finance-snapshot", "system": "qonto-assistant"} } } ```