Skip to content

financial.rego

Allow rules for the most common transactional and read-side actions. Unlike the other modules, financial.rego defines deny and hitl as partial sets (no default boolean) so YAML-compiled rules — which emit deny[reason] if { … } and hitl[reason] if { … } — can extend them without colliding with a boolean default.

Package: kitelogik.financial · Source: kitelogik/policies/financial.rego

Rules

ActionAllowed whenRisk-tier hint (set by main.rego)
read_customer_record, list_transactionsSession has the read_customer scopeINFORMATIONAL
approve_refund (≤ $100)Role ∈ {support_agent, manager, worker_agent} and scope approve_refund_under_100 and amount in [0, 100]TRANSACTIONAL_LOW
approve_refund (≤ $1000)Role = manager and scope approve_refund_under_1000 and amount in [0, 1000]TRANSACTIONAL_HIGH (HITL on > $100, by main.rego)
send_notificationSession has the send_notifications scope(default OPERATIONAL)
query_memoryAny active session (non-empty session_id)(default OPERATIONAL)
write_memorySession has the memory_write scope(default OPERATIONAL)
execute_codecontext.sandbox_verified == true(default OPERATIONAL) — without sandbox, security.rego hard-denies

All amount checks use is_number(...) first to close the OPA structural-ordering bypass (null < 0 would otherwise satisfy inequality silently).

Selected source

rego
# Allow low-value refunds for support agents and delegated workers
allow if {
    input.action == "approve_refund"
    input.context.user_role in {"support_agent", "manager", "worker_agent"}
    "approve_refund_under_100" in input.context.session_scopes
    is_number(input.args.amount)
    input.args.amount >= 0
    input.args.amount <= 100
}

# Allow higher-value refunds for managers with elevated scope
allow if {
    input.action == "approve_refund"
    input.context.user_role == "manager"
    "approve_refund_under_1000" in input.context.session_scopes
    is_number(input.args.amount)
    input.args.amount >= 0
    input.args.amount <= 1000
}

How main.rego uses this module

main.rego propagates this module two ways:

rego
# Allow if a sub-policy grants access AND security/delegation don't deny
allow if { not deny; financial.allow }

# Propagate financial-package hard denies (typically YAML-compiled)
deny if { some msg; financial.deny[msg] }

# Propagate financial-package HITL routes (`then: hitl` in YAML)
requires_hitl if { some msg; financial.hitl[msg] }

So extending this module via YAML — adding then: deny or then: hitl rules — automatically gets picked up by the aggregator without touching main.rego.

Extending in your own project

The intended path is YAML rather than editing the OSS rego directly:

yaml
# policies/refund_extras.yaml
version: 1
package: kitelogik.financial      # same package — extends the OSS rules
rules:
  - name: block_weekend_refunds
    when:
      action: approve_refund
      args:
        amount: { gt: 0 }
    then: deny
    reason: "Refunds disabled outside business hours"

Compile with kitelogik compile policies/refund_extras.yaml. The main.rego aggregator then sees financial.deny["Refunds disabled outside business hours"] on every refund event, which becomes a hard deny.

For more complex extensions (cross-event invariants, time-of-day rules), write Rego directly. Same package; new rules merge.

Released under the Apache 2.0 License.