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