mirror of
https://github.com/mcloh/Enterprise-MCP-Service-Bus.git
synced 2026-11-06 06:24:12 +00:00
M0 + M1 done
This commit is contained in:
4
RI/config/clients/finance-payments-agent.yaml
Normal file
4
RI/config/clients/finance-payments-agent.yaml
Normal file
@@ -0,0 +1,4 @@
|
||||
client_id: finance-payments-agent
|
||||
profile: Finance.Payments
|
||||
environment: production
|
||||
description: "Finance agent authorized to create/execute payments (R3, approval above threshold)"
|
||||
17
RI/config/clients/profiles/finance-payments.yaml
Normal file
17
RI/config/clients/profiles/finance-payments.yaml
Normal file
@@ -0,0 +1,17 @@
|
||||
# README.md §7.2, §17 (R3), §26 (payment.execute < 10k ALLOW, >= 10k REQUIRE_APPROVAL)
|
||||
name: Finance.Payments
|
||||
owner: finance-platform
|
||||
environment: production
|
||||
risk_ceiling: R3
|
||||
allowed_tools:
|
||||
- finance.invoice.get
|
||||
- finance.payment.create
|
||||
- finance.payment.execute
|
||||
restrictions:
|
||||
max_transaction_value: 10000000
|
||||
approval_threshold: 10000
|
||||
credential_policy:
|
||||
workload_identity: true
|
||||
short_lived: true
|
||||
audit:
|
||||
level: full
|
||||
12
RI/config/clients/profiles/finance-read.yaml
Normal file
12
RI/config/clients/profiles/finance-read.yaml
Normal file
@@ -0,0 +1,12 @@
|
||||
# README.md §7.2, §17 (R1)
|
||||
name: Finance.Read
|
||||
owner: finance-platform
|
||||
environment: production
|
||||
risk_ceiling: R1
|
||||
allowed_tools:
|
||||
- finance.invoice.get
|
||||
credential_policy:
|
||||
workload_identity: true
|
||||
short_lived: true
|
||||
audit:
|
||||
level: full
|
||||
18
RI/config/clients/profiles/sales-approve.yaml
Normal file
18
RI/config/clients/profiles/sales-approve.yaml
Normal file
@@ -0,0 +1,18 @@
|
||||
# README.md §7.1
|
||||
name: Sales.Approve
|
||||
owner: sales-platform
|
||||
environment: production
|
||||
risk_ceiling: R2
|
||||
allowed_tools:
|
||||
- sales.customer.search
|
||||
- sales.quote.get
|
||||
- sales.quote.approve
|
||||
- sales.discount.approve
|
||||
restrictions:
|
||||
max_transaction_value: 1000000
|
||||
allowed_regions: ["BR-SP", "BR-RJ"]
|
||||
credential_policy:
|
||||
workload_identity: true
|
||||
short_lived: true
|
||||
audit:
|
||||
level: full
|
||||
15
RI/config/clients/profiles/sales-read.yaml
Normal file
15
RI/config/clients/profiles/sales-read.yaml
Normal file
@@ -0,0 +1,15 @@
|
||||
# README.md §7.1
|
||||
name: Sales.Read
|
||||
owner: sales-platform
|
||||
environment: production
|
||||
risk_ceiling: R1
|
||||
allowed_tools:
|
||||
- sales.customer.search
|
||||
- sales.customer.get
|
||||
- sales.order.get
|
||||
- sales.inventory.check
|
||||
credential_policy:
|
||||
workload_identity: true
|
||||
short_lived: true
|
||||
audit:
|
||||
level: full
|
||||
20
RI/config/clients/profiles/sales-write.yaml
Normal file
20
RI/config/clients/profiles/sales-write.yaml
Normal file
@@ -0,0 +1,20 @@
|
||||
# README.md §7.1, §41
|
||||
name: Sales.Write
|
||||
owner: sales-platform
|
||||
environment: production
|
||||
risk_ceiling: R2
|
||||
allowed_tools:
|
||||
- sales.customer.search
|
||||
- sales.customer.get
|
||||
- sales.order.get
|
||||
- sales.inventory.check
|
||||
- sales.quote.create
|
||||
- sales.quote.update
|
||||
restrictions:
|
||||
max_transaction_value: 500000
|
||||
allowed_regions: ["BR-SP", "BR-RJ"]
|
||||
credential_policy:
|
||||
workload_identity: true
|
||||
short_lived: true
|
||||
audit:
|
||||
level: full
|
||||
4
RI/config/clients/sales-read-agent.yaml
Normal file
4
RI/config/clients/sales-read-agent.yaml
Normal file
@@ -0,0 +1,4 @@
|
||||
client_id: sales-read-agent
|
||||
profile: Sales.Read
|
||||
environment: production
|
||||
description: "Read-only Sales conversational agent"
|
||||
4
RI/config/clients/sales-write-agent.yaml
Normal file
4
RI/config/clients/sales-write-agent.yaml
Normal file
@@ -0,0 +1,4 @@
|
||||
client_id: sales-write-agent
|
||||
profile: Sales.Write
|
||||
environment: production
|
||||
description: "Sales agent authorized to create/update quotes"
|
||||
20
RI/config/policies/entitlement.rego
Normal file
20
RI/config/policies/entitlement.rego
Normal file
@@ -0,0 +1,20 @@
|
||||
# Entitlement policy (EP-03-T02, README.md §25 Passo 1, §6.5.A).
|
||||
#
|
||||
# permit if requested_tool IN entitlement(authenticated_client)
|
||||
#
|
||||
# `input.client_profile` is the client profile *name* the Gateway already
|
||||
# resolved from the authenticated client_id (EP-01-T03 -> identity/models.py
|
||||
# ClientRegistration.profile) -- never a value read from the request body.
|
||||
# `data.emcp.client_profiles` is pushed into OPA by the Entitlement Manager
|
||||
# (EP-04-T02) from the validated ClientProfile YAML (EP-04-T01); this policy
|
||||
# never parses YAML itself.
|
||||
package emcp.entitlement
|
||||
|
||||
import rego.v1
|
||||
|
||||
default allow := false
|
||||
|
||||
allow if {
|
||||
profile := data.emcp.client_profiles[input.client_profile]
|
||||
input.tool in profile.allowed_tools
|
||||
}
|
||||
21
RI/config/policies/entitlement_test.rego
Normal file
21
RI/config/policies/entitlement_test.rego
Normal file
@@ -0,0 +1,21 @@
|
||||
package emcp.entitlement_test
|
||||
|
||||
import rego.v1
|
||||
import data.emcp.entitlement
|
||||
|
||||
test_allow_when_tool_in_entitlement if {
|
||||
entitlement.allow with input as {"client_profile": "Sales.Read", "tool": "sales.customer.get"}
|
||||
with data.emcp.client_profiles as {"Sales.Read": {"allowed_tools": ["sales.customer.get"]}}
|
||||
}
|
||||
|
||||
test_deny_when_tool_not_in_entitlement if {
|
||||
# README.md §45 Teste 1/2: finance.createPayment must never be reachable
|
||||
# by a Sales.Read client, discovered or not.
|
||||
not entitlement.allow with input as {"client_profile": "Sales.Read", "tool": "finance.createPayment"}
|
||||
with data.emcp.client_profiles as {"Sales.Read": {"allowed_tools": ["sales.customer.get"]}}
|
||||
}
|
||||
|
||||
test_deny_when_client_profile_unknown if {
|
||||
not entitlement.allow with input as {"client_profile": "NoSuchProfile", "tool": "sales.customer.get"}
|
||||
with data.emcp.client_profiles as {"Sales.Read": {"allowed_tools": ["sales.customer.get"]}}
|
||||
}
|
||||
68
RI/config/policies/transaction.rego
Normal file
68
RI/config/policies/transaction.rego
Normal file
@@ -0,0 +1,68 @@
|
||||
# Transaction policy (EP-03-T03, README.md §25 Passo 2, §6.5.B, §26).
|
||||
#
|
||||
# permit quote.create if
|
||||
# amount <= client.transaction_limit
|
||||
# AND region IN client.allowed_regions
|
||||
# AND customer.classification != "restricted"
|
||||
#
|
||||
# Restricts a tool *already granted* by entitlement.rego -- this policy never
|
||||
# adds a tool absent from the client's entitlement (README.md §25, "A
|
||||
# Transaction Policy pode negar ou restringir. Ela não pode adicionar uma
|
||||
# tool inexistente no Client Entitlement."). `allow` here is meaningless on
|
||||
# its own; the PDP client (EP-03-T04) only consults it after entitlement.rego
|
||||
# already allowed the same (client_profile, tool) pair.
|
||||
#
|
||||
# input: {
|
||||
# "client_profile": "Sales.Write",
|
||||
# "tool": "sales.quote.create",
|
||||
# "arguments": {"amount": 100000, "region": "BR-SP"},
|
||||
# "customer_classification": "standard"
|
||||
# }
|
||||
package emcp.transaction
|
||||
|
||||
import rego.v1
|
||||
|
||||
default allow := false
|
||||
|
||||
default require_approval := false
|
||||
|
||||
allow if {
|
||||
profile := data.emcp.client_profiles[input.client_profile]
|
||||
within_transaction_limit(profile)
|
||||
within_allowed_regions(profile)
|
||||
not restricted_customer
|
||||
}
|
||||
|
||||
# README.md §26: above the profile's approval_threshold, a transaction that
|
||||
# would otherwise be allowed instead requires human approval (EP-14) -- it is
|
||||
# never silently allowed, and never silently upgraded to a hard deny either.
|
||||
require_approval if {
|
||||
allow
|
||||
profile := data.emcp.client_profiles[input.client_profile]
|
||||
threshold := profile.restrictions.approval_threshold
|
||||
amount := object.get(input.arguments, "amount", 0)
|
||||
amount > threshold
|
||||
}
|
||||
|
||||
within_transaction_limit(profile) if {
|
||||
not profile.restrictions.max_transaction_value
|
||||
}
|
||||
|
||||
within_transaction_limit(profile) if {
|
||||
limit := profile.restrictions.max_transaction_value
|
||||
amount := object.get(input.arguments, "amount", 0)
|
||||
amount <= limit
|
||||
}
|
||||
|
||||
within_allowed_regions(profile) if {
|
||||
not profile.restrictions.allowed_regions
|
||||
}
|
||||
|
||||
within_allowed_regions(profile) if {
|
||||
region := object.get(input.arguments, "region", "")
|
||||
region in profile.restrictions.allowed_regions
|
||||
}
|
||||
|
||||
restricted_customer if {
|
||||
input.customer_classification == "restricted"
|
||||
}
|
||||
72
RI/config/policies/transaction_test.rego
Normal file
72
RI/config/policies/transaction_test.rego
Normal file
@@ -0,0 +1,72 @@
|
||||
package emcp.transaction_test
|
||||
|
||||
import rego.v1
|
||||
import data.emcp.transaction
|
||||
|
||||
sales_write_profile := {"restrictions": {
|
||||
"max_transaction_value": 500000,
|
||||
"allowed_regions": ["BR-SP", "BR-RJ"],
|
||||
"approval_threshold": 100000,
|
||||
}}
|
||||
|
||||
test_allow_within_limit_and_region if {
|
||||
transaction.allow with input as {
|
||||
"client_profile": "Sales.Write",
|
||||
"tool": "sales.quote.create",
|
||||
"arguments": {"amount": 50000, "region": "BR-SP"},
|
||||
"customer_classification": "standard",
|
||||
} with data.emcp.client_profiles as {"Sales.Write": sales_write_profile}
|
||||
}
|
||||
|
||||
test_deny_above_transaction_limit if {
|
||||
not transaction.allow with input as {
|
||||
"client_profile": "Sales.Write",
|
||||
"tool": "sales.quote.create",
|
||||
"arguments": {"amount": 600000, "region": "BR-SP"},
|
||||
"customer_classification": "standard",
|
||||
} with data.emcp.client_profiles as {"Sales.Write": sales_write_profile}
|
||||
}
|
||||
|
||||
test_deny_outside_allowed_region if {
|
||||
not transaction.allow with input as {
|
||||
"client_profile": "Sales.Write",
|
||||
"tool": "sales.quote.create",
|
||||
"arguments": {"amount": 50000, "region": "BR-MG"},
|
||||
"customer_classification": "standard",
|
||||
} with data.emcp.client_profiles as {"Sales.Write": sales_write_profile}
|
||||
}
|
||||
|
||||
test_deny_restricted_customer if {
|
||||
not transaction.allow with input as {
|
||||
"client_profile": "Sales.Write",
|
||||
"tool": "sales.quote.create",
|
||||
"arguments": {"amount": 50000, "region": "BR-SP"},
|
||||
"customer_classification": "restricted",
|
||||
} with data.emcp.client_profiles as {"Sales.Write": sales_write_profile}
|
||||
}
|
||||
|
||||
test_require_approval_above_threshold if {
|
||||
# README.md §26: allowed, but only with human approval, above threshold.
|
||||
transaction.allow with input as {
|
||||
"client_profile": "Sales.Write",
|
||||
"tool": "sales.quote.create",
|
||||
"arguments": {"amount": 150000, "region": "BR-SP"},
|
||||
"customer_classification": "standard",
|
||||
} with data.emcp.client_profiles as {"Sales.Write": sales_write_profile}
|
||||
|
||||
transaction.require_approval with input as {
|
||||
"client_profile": "Sales.Write",
|
||||
"tool": "sales.quote.create",
|
||||
"arguments": {"amount": 150000, "region": "BR-SP"},
|
||||
"customer_classification": "standard",
|
||||
} with data.emcp.client_profiles as {"Sales.Write": sales_write_profile}
|
||||
}
|
||||
|
||||
test_no_approval_required_below_threshold if {
|
||||
not transaction.require_approval with input as {
|
||||
"client_profile": "Sales.Write",
|
||||
"tool": "sales.quote.create",
|
||||
"arguments": {"amount": 50000, "region": "BR-SP"},
|
||||
"customer_classification": "standard",
|
||||
} with data.emcp.client_profiles as {"Sales.Write": sales_write_profile}
|
||||
}
|
||||
Reference in New Issue
Block a user