flex-auth/examples/qonto-assistant/policy_package.md
tegwick ae295824bd
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 3s
Register qonto-assistant as a protected system (finance.qonto.read)
QONTO-WP-0004-T04. Modeled directly on examples/tenant-engine/: one
resource type (finance-snapshot), one action (finance.qonto.read),
two registered subjects (an agent-harness session identity and the
founder's human identity), and a Rego policy gating on
resource.system + action + subject.type + tenant match. Tenant
capability-role/plan liveness (VEN/CUS) is deliberately NOT encoded
here -- that's qonto-assistant's separate tenant-engine live-lookup
check, per this package's own scope note.

Verified: flex-auth test-policy (6 rego tests + 6 fixtures, all pass),
load-registry, and CLI check for both an allow and a deny case. Also
verified end-to-end over real HTTP: a live flex-auth serve loaded with
this exact registry+policy, hit by qonto-assistant's actual
FlexAuthCheckClient (not a mock) -- allow for tenant:friendly:binky,
deny (wrong_tenant) for a mismatched tenant.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-24 00:19:26 +02:00

5 KiB

id name namespace version status package actions owner fixtures caring activation metadata
qonto-assistant.finance-read qonto-assistant finance.qonto.read authorization qonto-assistant:finance v1 ready flexauth.qonto_assistant.finance_read
finance.qonto.read
team:platform-security
policy_fixtures.yaml
profile enforce canonical_roles organization_relations scopes planes capabilities exposure_modes conditions restrictions
caring-0.4.0-rc2 false
Operator
ServiceProvider
Customer
level id tenant
Tenant tenant:friendly:binky tenant:friendly:binky
Data
Audit
View
Audit
Masked
Logged
PrivilegeEscalationBlocked
mode
local
source flex_auth_contract
examples/qonto-assistant/policy_package.md 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

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

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"}
  }
}