package proofedmesh.transformations.expense_test import data.proofedmesh.transformations.expense import rego.v1 # ------------------------------------------------------------------ # v1.0.0 — flat single-project (unchanged behaviour) # ------------------------------------------------------------------ canonical_payload := { "employee_id": "EMP-12345", "currency": "EUR", "total_amount": "428.50", } sink_payload := {"expense": { "employee_id": "EMP-12345", "currency": "EUR", "total_amount": "428.50", }} test_allow_map_to_sink if { expense.allow with input as { "agent_id": "agent-sink-mapping", "operation": "expense.map_to_sink", "input_schema": {"name": "expense.canonical", "version": "1.0.0"}, "output_schema": {"name": "sink.db.expense", "version": "1.0.0"}, "input_payload": canonical_payload, "output_payload": sink_payload, } } test_deny_unknown_agent if { not expense.allow with input as { "agent_id": "agent-rogue", "operation": "expense.map_to_sink", "input_schema": {"name": "expense.canonical", "version": "1.0.0"}, "output_schema": {"name": "sink.db.expense", "version": "1.0.0"}, "input_payload": canonical_payload, "output_payload": sink_payload, } } test_deny_schema_mismatch if { not expense.allow with input as { "agent_id": "agent-sink-mapping", "operation": "expense.map_to_sink", "input_schema": {"name": "expense.canonical", "version": "1.0.0"}, "output_schema": {"name": "sink.db.expense", "version": "2.0.0"}, "input_payload": canonical_payload, "output_payload": sink_payload, } } test_deny_total_amount_change if { tampered := {"expense": { "employee_id": "EMP-12345", "currency": "EUR", "total_amount": "999.99", }} not expense.allow with input as { "agent_id": "agent-sink-mapping", "operation": "expense.map_to_sink", "input_schema": {"name": "expense.canonical", "version": "1.0.0"}, "output_schema": {"name": "sink.db.expense", "version": "1.0.0"}, "input_payload": canonical_payload, "output_payload": tampered, } } test_deny_currency_change if { tampered := {"expense": { "employee_id": "EMP-12345", "currency": "USD", "total_amount": "428.50", }} not expense.allow with input as { "agent_id": "agent-sink-mapping", "operation": "expense.map_to_sink", "input_schema": {"name": "expense.canonical", "version": "1.0.0"}, "output_schema": {"name": "sink.db.expense", "version": "1.0.0"}, "input_payload": canonical_payload, "output_payload": tampered, } } test_deny_employee_change if { tampered := {"expense": { "employee_id": "EMP-99999", "currency": "EUR", "total_amount": "428.50", }} not expense.allow with input as { "agent_id": "agent-sink-mapping", "operation": "expense.map_to_sink", "input_schema": {"name": "expense.canonical", "version": "1.0.0"}, "output_schema": {"name": "sink.db.expense", "version": "1.0.0"}, "input_payload": canonical_payload, "output_payload": tampered, } } test_deny_posting_agent_cannot_map if { not expense.allow with input as { "agent_id": "agent-sink-posting", "operation": "expense.map_to_sink", "input_schema": {"name": "expense.canonical", "version": "1.0.0"}, "output_schema": {"name": "sink.db.expense", "version": "1.0.0"}, "input_payload": canonical_payload, "output_payload": sink_payload, } } # ------------------------------------------------------------------ # v1.1.0 — per-line allocations # ------------------------------------------------------------------ canonical_v11 := { "employee_id": "EMP-12345", "currency": "EUR", "total_amount": "428.50", } sink_v11_two_items_split := {"expense": { "employee_id": "EMP-12345", "currency": "EUR", "total_amount": "428.50", "items": [ { "amount": "328.50", "allocations": [ {"amount": "197.10"}, {"amount": "131.40"}, ], }, { "amount": "100.00", "allocations": [ {"amount": "70.00"}, {"amount": "30.00"}, ], }, ], }} test_allow_v110_map_to_sink_split if { expense.allow with input as { "agent_id": "agent-sink-mapping", "operation": "expense.map_to_sink", "input_schema": {"name": "expense.canonical", "version": "1.1.0"}, "output_schema": {"name": "sink.db.expense", "version": "1.1.0"}, "input_payload": canonical_v11, "output_payload": sink_v11_two_items_split, } } test_deny_v110_allocation_sum_mismatch if { bad_sink := {"expense": { "employee_id": "EMP-12345", "currency": "EUR", "total_amount": "428.50", "items": [ { "amount": "328.50", "allocations": [ {"amount": "197.10"}, {"amount": "131.50"}, # 328.60, nicht 328.50 ], }, { "amount": "100.00", "allocations": [ {"amount": "70.00"}, {"amount": "30.00"}, ], }, ], }} not expense.allow with input as { "agent_id": "agent-sink-mapping", "operation": "expense.map_to_sink", "input_schema": {"name": "expense.canonical", "version": "1.1.0"}, "output_schema": {"name": "sink.db.expense", "version": "1.1.0"}, "input_payload": canonical_v11, "output_payload": bad_sink, } } test_allow_v110_single_allocation if { one := {"expense": { "employee_id": "EMP-12345", "currency": "EUR", "total_amount": "428.50", "items": [ {"amount": "328.50", "allocations": [{"amount": "328.50"}]}, {"amount": "100.00", "allocations": [{"amount": "100.00"}]}, ], }} expense.allow with input as { "agent_id": "agent-sink-mapping", "operation": "expense.map_to_sink", "input_schema": {"name": "expense.canonical", "version": "1.1.0"}, "output_schema": {"name": "sink.db.expense", "version": "1.1.0"}, "input_payload": canonical_v11, "output_payload": one, } } test_v110_still_enforces_total_currency_employee if { tampered_total := {"expense": { "employee_id": "EMP-12345", "currency": "EUR", "total_amount": "999.99", "items": [{"amount": "328.50", "allocations": [{"amount": "328.50"}]}], }} not expense.allow with input as { "agent_id": "agent-sink-mapping", "operation": "expense.map_to_sink", "input_schema": {"name": "expense.canonical", "version": "1.1.0"}, "output_schema": {"name": "sink.db.expense", "version": "1.1.0"}, "input_payload": canonical_v11, "output_payload": tampered_total, } } test_allow_v110_normalize if { # normalize keeps canonical v1.1.0 shape, no sink allocation check applies. expense.allow with input as { "agent_id": "agent-travel", "operation": "expense.normalize", "input_schema": {"name": "expense.canonical", "version": "1.1.0"}, "output_schema": {"name": "expense.canonical", "version": "1.1.0"}, "input_payload": canonical_v11, "output_payload": {"expense": canonical_v11}, } } # ------------------------------------------------------------------ # v1.2.0 — allocations + receipts + per-diem items (map_to_sink) # ------------------------------------------------------------------ canonical_v12 := { "employee_id": "EMP-12345", "currency": "EUR", "total_amount": "484.50", } sink_v12_mixed := {"expense": { "employee_id": "EMP-12345", "currency": "EUR", "total_amount": "484.50", "items": [ {"amount": "328.50", "allocations": [{"amount": "328.50"}]}, {"amount": "14.00", "allocations": [{"amount": "14.00"}]}, {"amount": "28.00", "allocations": [{"amount": "28.00"}]}, {"amount": "14.00", "allocations": [{"amount": "14.00"}]}, {"amount": "100.00", "allocations": [{"amount": "100.00"}]}, ], }} test_allow_v120_map_to_sink_mixed_items if { expense.allow with input as { "agent_id": "agent-sink-mapping", "operation": "expense.map_to_sink", "input_schema": {"name": "expense.canonical", "version": "1.2.0"}, "output_schema": {"name": "sink.db.expense", "version": "1.2.0"}, "input_payload": canonical_v12, "output_payload": sink_v12_mixed, } } test_deny_v120_allocation_sum_mismatch if { bad := {"expense": { "employee_id": "EMP-12345", "currency": "EUR", "total_amount": "484.50", "items": [{"amount": "328.50", "allocations": [{"amount": "328.51"}]}], }} not expense.allow with input as { "agent_id": "agent-sink-mapping", "operation": "expense.map_to_sink", "input_schema": {"name": "expense.canonical", "version": "1.2.0"}, "output_schema": {"name": "sink.db.expense", "version": "1.2.0"}, "input_payload": canonical_v12, "output_payload": bad, } } test_allow_v120_normalize if { expense.allow with input as { "agent_id": "agent-travel", "operation": "expense.normalize", "input_schema": {"name": "expense.canonical", "version": "1.2.0"}, "output_schema": {"name": "expense.canonical", "version": "1.2.0"}, "input_payload": canonical_v12, "output_payload": {"expense": canonical_v12}, } }