ProofedMesh/policies/data_sources/receipts.rego
CTO Agent c0472691c8
Some checks failed
validate / Rego (opa fmt + opa test) (push) Successful in 12s
validate / JSON Schema (ajv) (push) Has been cancelled
policies: add receipts + per_diem_rates data-source policies, per_diem transformation policy, extend expense.rego for v1.2.0 (54/54 tests pass)
2026-10-25 17:07:38 +00:00

79 lines
2 KiB
Rego

# METADATA
# title: Data source policy for ds:receipts
# description: |
# Governs who may upload (write) and who may read receipts.
# Receipts are PII. agent-travel uploads during the chat; downstream agents
# may only read by content_hash and only within an active user session.
# authors:
# - CTO Agent <cto@basicstack.de>
# related_resources:
# - ref: docs/architecture/v1.1.md#user-content-47-belege-receipts--upload-hashbindung-lesezugriff-entlang-der-kette
# - ref: schemas/ds/receipts/v1.0.0.json
package proofedmesh.data_sources.receipts
import rego.v1
default allow := false
allow if {
input.data_source == "ds:receipts"
input.user_sub != ""
input.session_id != ""
some rule in agent_scope_rules
rule.agent_id == input.agent_id
rule.operation == input.operation
filters_ok(rule)
}
agent_scope_rules := [
{
"agent_id": "agent-travel",
"operation": "write",
"required_filters": set(),
"allowed_filters": set(),
},
{
"agent_id": "agent-sink-mapping",
"operation": "read",
"required_filters": {"content_hash"},
"allowed_filters": {"content_hash"},
},
{
"agent_id": "agent-sink-posting",
"operation": "read",
"required_filters": {"content_hash"},
"allowed_filters": {"content_hash"},
},
]
filters_ok(rule) if {
rule.operation == "write"
}
filters_ok(rule) if {
rule.operation == "read"
provided := {k | some k; _ := input.filters[k]}
count(provided - rule.allowed_filters) == 0
count(rule.required_filters - provided) == 0
}
deny_reason contains msg if {
input.data_source != "ds:receipts"
msg := sprintf("wrong data_source: %s", [input.data_source])
}
deny_reason contains msg if {
input.user_sub == ""
msg := "missing user_sub (receipts always require an active user session)"
}
deny_reason contains msg if {
not any_rule_matches
msg := sprintf("no scope rule for agent=%s op=%s", [input.agent_id, input.operation])
}
any_rule_matches if {
some rule in agent_scope_rules
rule.agent_id == input.agent_id
rule.operation == input.operation
}