# METADATA # title: Data source policy for ds:expense-db-app # description: | # Governs which agents may read which resources in whose name on the # own DB-app data source. Requires an active user session for all # current reads (requires_user_context=TRUE for every registered # agent_data_source_scope). # authors: # - CTO Agent # related_resources: # - ref: docs/architecture/v1.1.md#user-content-3b-data-source-registry # - ref: docs/architecture/v1.1.md#user-content-3c-session-scope-tokens--delegation-agent-im-auftrag-von-benutzer package proofedmesh.data_sources.expense_db_app import rego.v1 default allow := false allow if { input.data_source == "ds:expense-db-app" input.operation == "read" input.user_sub != "" input.session_id != "" some rule in agent_scope_rules rule.agent_id == input.agent_id rule.resource == input.resource filters_within_scope(rule) user_bound_filters_ok(rule) } # Rule table: who may read what, with which filter dimensions and user-binding mode. agent_scope_rules := [ { "agent_id": "agent-travel", "resource": "project_assignments", "allowed_filters": {"employee_id", "active_on"}, "required_filters": {"employee_id"}, "require_own_employee": true, }, { "agent_id": "agent-sink-mapping", "resource": "account_assignments", "allowed_filters": {"project_code", "cost_center"}, "required_filters": {"project_code"}, "require_own_employee": false, }, { "agent_id": "agent-sink-mapping", "resource": "cost_centers", "allowed_filters": {"active"}, "required_filters": set(), "require_own_employee": false, }, ] # Only the declared filter keys are allowed; required filters must be present. filters_within_scope(rule) if { provided := {k | some k; _ := input.filters[k]} count(provided - rule.allowed_filters) == 0 count(rule.required_filters - provided) == 0 } # When require_own_employee=true, the employee_id filter must map to input.user_sub. # The mapping is loaded as external data: data.employee_mapping.by_sub[user_sub] -> "EMP-...". user_bound_filters_ok(rule) if { not rule.require_own_employee } user_bound_filters_ok(rule) if { rule.require_own_employee expected := data.employee_mapping.by_sub[input.user_sub] input.filters.employee_id == expected } deny_reason contains msg if { input.data_source != "ds:expense-db-app" msg := sprintf("wrong data_source: %s", [input.data_source]) } deny_reason contains msg if { input.operation != "read" msg := sprintf("operation %s not supported", [input.operation]) } deny_reason contains msg if { input.user_sub == "" msg := "missing user_sub (requires_user_context=true for all registered scopes)" } deny_reason contains msg if { not any_scope_rule_matches msg := sprintf("no scope rule for agent=%s resource=%s", [input.agent_id, input.resource]) } any_scope_rule_matches if { some rule in agent_scope_rules rule.agent_id == input.agent_id rule.resource == input.resource }