@aporthq/aport-agent-guardrails 1.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +217 -0
- package/README.md +481 -0
- package/bin/agent-guardrails +133 -0
- package/bin/aport-create-passport.sh +444 -0
- package/bin/aport-cursor-hook.sh +90 -0
- package/bin/aport-guardrail-api.sh +108 -0
- package/bin/aport-guardrail-bash.sh +394 -0
- package/bin/aport-guardrail-v2.sh +5 -0
- package/bin/aport-guardrail.sh +5 -0
- package/bin/aport-resolve-paths.sh +71 -0
- package/bin/aport-status.sh +276 -0
- package/bin/frameworks/crewai.sh +49 -0
- package/bin/frameworks/cursor.sh +95 -0
- package/bin/frameworks/langchain.sh +48 -0
- package/bin/frameworks/n8n.sh +36 -0
- package/bin/frameworks/openclaw.sh +19 -0
- package/bin/lib/allowlist.sh +18 -0
- package/bin/lib/common.sh +28 -0
- package/bin/lib/config.sh +46 -0
- package/bin/lib/constants.sh +232 -0
- package/bin/lib/detect.sh +65 -0
- package/bin/lib/error.sh +269 -0
- package/bin/lib/passport.sh +19 -0
- package/bin/lib/templates/.gitkeep +1 -0
- package/bin/lib/templates/config.yaml +6 -0
- package/bin/lib/validation.sh +206 -0
- package/bin/openclaw +660 -0
- package/docs/ADDING_A_FRAMEWORK.md +87 -0
- package/docs/AGENTS.md.example +40 -0
- package/docs/CODE_REVIEW.md +192 -0
- package/docs/DEPLOYMENT_READINESS.md +81 -0
- package/docs/FAQ_SECURITY_SCANNERS.md +373 -0
- package/docs/FRAMEWORK_ROADMAP.md +41 -0
- package/docs/HOSTED_PASSPORT_SETUP.md +362 -0
- package/docs/IMPLEMENTING_YOUR_OWN_EVALUATOR.md +433 -0
- package/docs/OPENCLAW_COMPATIBILITY.md +73 -0
- package/docs/OPENCLAW_LOCAL_INTEGRATION.md +596 -0
- package/docs/OPENCLAW_TOOLS_AND_POLICIES.md +54 -0
- package/docs/QUICKSTART.md +470 -0
- package/docs/QUICKSTART_OPENCLAW_PLUGIN.md +470 -0
- package/docs/README.md +28 -0
- package/docs/RELEASE.md +87 -0
- package/docs/REPO_LAYOUT.md +47 -0
- package/docs/SKILLS_ECOSYSTEM_ANALYSIS_FEB17.md +1260 -0
- package/docs/TOOL_POLICY_MAPPING.md +46 -0
- package/docs/UPGRADE.md +46 -0
- package/docs/VERIFICATION_METHODS.md +97 -0
- package/docs/assets/README.md +8 -0
- package/docs/assets/porter.svg +54 -0
- package/docs/development/ERROR_CODES.md +616 -0
- package/docs/frameworks/GITHUB_ISSUE_PROPOSALS.md +1105 -0
- package/docs/frameworks/crewai.md +114 -0
- package/docs/frameworks/cursor.md +159 -0
- package/docs/frameworks/langchain.md +72 -0
- package/docs/frameworks/n8n.md +40 -0
- package/docs/frameworks/openclaw.md +40 -0
- package/docs/launch/ADD_APORT_AWESOME_LISTS_INSTRUCTIONS.md +146 -0
- package/docs/launch/ANNOUNCEMENT_GUIDE.md +266 -0
- package/docs/launch/AWESOME_REPOS.md +53 -0
- package/docs/launch/CURSOR_VSCODE_HOOKS_RESEARCH.md +77 -0
- package/docs/launch/DEMO_TERMINAL_OUTPUT.txt +48 -0
- package/docs/launch/DRY_AND_PLAN_CHECKLIST.md +47 -0
- package/docs/launch/EVIDENCE_README.md +61 -0
- package/docs/launch/EVIDENCE_TERMINAL_CAPTURE.txt +10 -0
- package/docs/launch/FRAMEWORK_SUPPORT_PLAN.md +1640 -0
- package/docs/launch/LAUNCH_READINESS_CHECKLIST.md +237 -0
- package/docs/launch/LAUNCH_STRATEGY_SUMMARY.md +464 -0
- package/docs/launch/OPENCLAW_FEEDBACK_AND_FIXES.md +85 -0
- package/docs/launch/POST_1_VALENTINE_IMPROVED.md +233 -0
- package/docs/launch/POST_2_GUARDRAIL_IMPROVED.md +369 -0
- package/docs/launch/PRE_LAUNCH_FIXES.md +766 -0
- package/docs/launch/QUICK_LAUNCH_CHECKLIST.md +400 -0
- package/docs/launch/READINESS_SUMMARY.md +262 -0
- package/docs/launch/README.md +68 -0
- package/docs/launch/USER_STORIES.md +327 -0
- package/docs/launch/scripts/add-aport-awesome-pr.sh +69 -0
- package/docs/operations/MONITORING.md +588 -0
- package/docs/reviews/2026-02-18-staff-review.md +268 -0
- package/extensions/openclaw-aport/README.md +415 -0
- package/extensions/openclaw-aport/index.js +625 -0
- package/extensions/openclaw-aport/openclaw-aport.js +7 -0
- package/extensions/openclaw-aport/openclaw.plugin.json +46 -0
- package/extensions/openclaw-aport/package.json +36 -0
- package/extensions/openclaw-aport/test.js +307 -0
- package/external/aport-policies/README.md +363 -0
- package/external/aport-policies/agent.session.create.v1/README.md +345 -0
- package/external/aport-policies/agent.session.create.v1/policy.json +162 -0
- package/external/aport-policies/agent.tool.register.v1/README.md +361 -0
- package/external/aport-policies/agent.tool.register.v1/policy.json +172 -0
- package/external/aport-policies/code.release.publish.v1/README.md +51 -0
- package/external/aport-policies/code.release.publish.v1/policy.json +121 -0
- package/external/aport-policies/code.repository.merge.v1/README.md +287 -0
- package/external/aport-policies/code.repository.merge.v1/express.example.js +332 -0
- package/external/aport-policies/code.repository.merge.v1/fastapi.example.py +370 -0
- package/external/aport-policies/code.repository.merge.v1/policy.json +162 -0
- package/external/aport-policies/data.export.create.v1/README.md +226 -0
- package/external/aport-policies/data.export.create.v1/express.example.js +172 -0
- package/external/aport-policies/data.export.create.v1/fastapi.example.py +165 -0
- package/external/aport-policies/data.export.create.v1/policy.json +133 -0
- package/external/aport-policies/data.report.ingest.v1/README.md +134 -0
- package/external/aport-policies/data.report.ingest.v1/express.example.js +105 -0
- package/external/aport-policies/data.report.ingest.v1/minimal-example.js +68 -0
- package/external/aport-policies/data.report.ingest.v1/policy.json +174 -0
- package/external/aport-policies/finance.crypto.trade.v1/README.md +146 -0
- package/external/aport-policies/finance.crypto.trade.v1/express.example.js +109 -0
- package/external/aport-policies/finance.crypto.trade.v1/minimal-example.js +65 -0
- package/external/aport-policies/finance.crypto.trade.v1/policy.json +176 -0
- package/external/aport-policies/finance.payment.charge.v1/README.md +326 -0
- package/external/aport-policies/finance.payment.charge.v1/express.example.js +250 -0
- package/external/aport-policies/finance.payment.charge.v1/fastapi.example.py +227 -0
- package/external/aport-policies/finance.payment.charge.v1/minimal-example.js +64 -0
- package/external/aport-policies/finance.payment.charge.v1/policy.json +224 -0
- package/external/aport-policies/finance.payment.charge.v1/tests/contexts.jsonl +12 -0
- package/external/aport-policies/finance.payment.charge.v1/tests/expected.jsonl +12 -0
- package/external/aport-policies/finance.payment.charge.v1/tests/passport.instance.json +42 -0
- package/external/aport-policies/finance.payment.charge.v1/tests/passport.template.json +40 -0
- package/external/aport-policies/finance.payment.charge.v1/tests/payments-charge-policy.test.js +817 -0
- package/external/aport-policies/finance.payment.charge.v1/tests/test_payments_charge_policy.py +486 -0
- package/external/aport-policies/finance.payment.payout.v1/README.md +78 -0
- package/external/aport-policies/finance.payment.payout.v1/policy.json +181 -0
- package/external/aport-policies/finance.payment.refund.v1/README.md +275 -0
- package/external/aport-policies/finance.payment.refund.v1/express.example.js +167 -0
- package/external/aport-policies/finance.payment.refund.v1/fastapi.example.py +136 -0
- package/external/aport-policies/finance.payment.refund.v1/minimal-example.js +183 -0
- package/external/aport-policies/finance.payment.refund.v1/policy.json +216 -0
- package/external/aport-policies/finance.payment.refund.v1/tests/refunds-policy.test.js +924 -0
- package/external/aport-policies/finance.payment.refund.v1/tests/test_refunds_policy.py +778 -0
- package/external/aport-policies/finance.transaction.execute.v1/README.md +309 -0
- package/external/aport-policies/finance.transaction.execute.v1/express.example.js +261 -0
- package/external/aport-policies/finance.transaction.execute.v1/fastapi.example.py +231 -0
- package/external/aport-policies/finance.transaction.execute.v1/minimal-example.js +78 -0
- package/external/aport-policies/finance.transaction.execute.v1/policy.json +189 -0
- package/external/aport-policies/finance.transaction.execute.v1/tests/contexts.jsonl +12 -0
- package/external/aport-policies/finance.transaction.execute.v1/tests/expected.jsonl +12 -0
- package/external/aport-policies/finance.transaction.execute.v1/tests/passport.instance.json +42 -0
- package/external/aport-policies/finance.transaction.execute.v1/tests/passport.template.json +42 -0
- package/external/aport-policies/finance.transaction.execute.v1/tests/test_transactions_policy.py +214 -0
- package/external/aport-policies/finance.transaction.execute.v1/tests/transactions-policy.test.js +306 -0
- package/external/aport-policies/governance.data.access.v1/README.md +292 -0
- package/external/aport-policies/governance.data.access.v1/express.example.js +321 -0
- package/external/aport-policies/governance.data.access.v1/fastapi.example.py +279 -0
- package/external/aport-policies/governance.data.access.v1/minimal-example.js +65 -0
- package/external/aport-policies/governance.data.access.v1/policy.json +208 -0
- package/external/aport-policies/governance.data.access.v1/tests/contexts.jsonl +12 -0
- package/external/aport-policies/governance.data.access.v1/tests/data-access-policy.test.js +308 -0
- package/external/aport-policies/governance.data.access.v1/tests/expected.jsonl +12 -0
- package/external/aport-policies/governance.data.access.v1/tests/passport.instance.json +56 -0
- package/external/aport-policies/governance.data.access.v1/tests/passport.template.json +56 -0
- package/external/aport-policies/governance.data.access.v1/tests/test_data_access_policy.py +214 -0
- package/external/aport-policies/legal.contract.review.v1/README.md +109 -0
- package/external/aport-policies/legal.contract.review.v1/policy.json +378 -0
- package/external/aport-policies/legal.contract.review.v1/tests/legal-contract-review-policy.test.js +609 -0
- package/external/aport-policies/legal.contract.review.v1/tests/passport.template.json +49 -0
- package/external/aport-policies/mcp.tool.execute.v1/README.md +301 -0
- package/external/aport-policies/mcp.tool.execute.v1/policy.json +141 -0
- package/external/aport-policies/messaging.message.send.v1/README.md +230 -0
- package/external/aport-policies/messaging.message.send.v1/express.example.js +183 -0
- package/external/aport-policies/messaging.message.send.v1/fastapi.example.py +193 -0
- package/external/aport-policies/messaging.message.send.v1/policy.json +144 -0
- package/external/aport-policies/policy-template.json +107 -0
- package/external/aport-policies/system.command.execute.v1/README.md +275 -0
- package/external/aport-policies/system.command.execute.v1/policy.json +146 -0
- package/external/aport-spec/CONTRIBUTING.md +273 -0
- package/external/aport-spec/LICENSE +21 -0
- package/external/aport-spec/README.md +168 -0
- package/external/aport-spec/conformance/README.md +294 -0
- package/external/aport-spec/conformance/cases/data.export.v1/contexts/allow_users.json +6 -0
- package/external/aport-spec/conformance/cases/data.export.v1/contexts/deny_pii.json +6 -0
- package/external/aport-spec/conformance/cases/data.export.v1/expected/allow_users.decision.json +19 -0
- package/external/aport-spec/conformance/cases/data.export.v1/expected/deny_pii.decision.json +19 -0
- package/external/aport-spec/conformance/cases/data.export.v1/passports/template.json +29 -0
- package/external/aport-spec/conformance/cases/payments.refunds.v1/contexts/allow_50usd.json +9 -0
- package/external/aport-spec/conformance/cases/payments.refunds.v1/contexts/deny_150usd.json +9 -0
- package/external/aport-spec/conformance/cases/payments.refunds.v1/contexts/deny_currency.json +9 -0
- package/external/aport-spec/conformance/cases/payments.refunds.v1/expected/allow_50usd.decision.json +19 -0
- package/external/aport-spec/conformance/cases/payments.refunds.v1/expected/deny_150usd.decision.json +19 -0
- package/external/aport-spec/conformance/cases/payments.refunds.v1/expected/deny_currency.decision.json +19 -0
- package/external/aport-spec/conformance/cases/payments.refunds.v1/passports/template.json +42 -0
- package/external/aport-spec/conformance/package.json +44 -0
- package/external/aport-spec/conformance/pnpm-lock.yaml +642 -0
- package/external/aport-spec/conformance/src/cases.ts +371 -0
- package/external/aport-spec/conformance/src/ed25519.ts +167 -0
- package/external/aport-spec/conformance/src/jcs.ts +85 -0
- package/external/aport-spec/conformance/src/runner.ts +533 -0
- package/external/aport-spec/conformance/src/validators.ts +185 -0
- package/external/aport-spec/conformance/test-runner.js +315 -0
- package/external/aport-spec/conformance/tsconfig.json +21 -0
- package/external/aport-spec/error-schema.json +192 -0
- package/external/aport-spec/index.json +12 -0
- package/external/aport-spec/integrations/clawmoat/README.md +12 -0
- package/external/aport-spec/integrations/shield/README.md +245 -0
- package/external/aport-spec/integrations/shield/adapters/index.js +116 -0
- package/external/aport-spec/integrations/shield/adapters/system-command-execute.js +133 -0
- package/external/aport-spec/integrations/shield/test/README.md +58 -0
- package/external/aport-spec/integrations/shield/test/shield.md +40 -0
- package/external/aport-spec/integrations/shield/test/test-shield-to-verify.js +274 -0
- package/external/aport-spec/metrics-schema.json +504 -0
- package/external/aport-spec/oap/CHANGELOG.md +54 -0
- package/external/aport-spec/oap/VERSION.md +40 -0
- package/external/aport-spec/oap/capability-registry.md +229 -0
- package/external/aport-spec/oap/conformance.md +257 -0
- package/external/aport-spec/oap/decision-schema.json +114 -0
- package/external/aport-spec/oap/examples/context.refund.usd.50.json +9 -0
- package/external/aport-spec/oap/examples/decision.allow.sample.json +20 -0
- package/external/aport-spec/oap/examples/decision.deny.sample.json +23 -0
- package/external/aport-spec/oap/examples/passport.instance.v1.json +50 -0
- package/external/aport-spec/oap/examples/passport.template.v1.json +71 -0
- package/external/aport-spec/oap/oap-spec.md +426 -0
- package/external/aport-spec/oap/passport-schema.json +396 -0
- package/external/aport-spec/oap/security.md +213 -0
- package/external/aport-spec/oap/vc/context-oap-v1.jsonld +137 -0
- package/external/aport-spec/oap/vc/examples/oap-decision-vc.json +37 -0
- package/external/aport-spec/oap/vc/examples/oap-passport-vc.json +68 -0
- package/external/aport-spec/oap/vc/tools/INTEGRATION.md +375 -0
- package/external/aport-spec/oap/vc/tools/README.md +278 -0
- package/external/aport-spec/oap/vc/tools/examples/decision-to-vc.js +66 -0
- package/external/aport-spec/oap/vc/tools/examples/passport-to-vc.js +83 -0
- package/external/aport-spec/oap/vc/tools/examples/vc-to-decision.js +77 -0
- package/external/aport-spec/oap/vc/tools/examples/vc-to-passport.js +94 -0
- package/external/aport-spec/oap/vc/tools/package.json +38 -0
- package/external/aport-spec/oap/vc/tools/pnpm-lock.yaml +472 -0
- package/external/aport-spec/oap/vc/tools/src/cli.ts +226 -0
- package/external/aport-spec/oap/vc/tools/src/crypto-utils.ts +427 -0
- package/external/aport-spec/oap/vc/tools/src/index.ts +653 -0
- package/external/aport-spec/oap/vc/tools/src/test.ts +148 -0
- package/external/aport-spec/oap/vc/tools/src/vp.ts +382 -0
- package/external/aport-spec/oap/vc/tools/test-simple.js +214 -0
- package/external/aport-spec/oap/vc/tools/tsconfig.json +19 -0
- package/external/aport-spec/oap/vc/vc-mapping.md +443 -0
- package/external/aport-spec/passport-schema.json +586 -0
- package/external/aport-spec/rate-limiting.md +136 -0
- package/external/aport-spec/transport-profile.md +325 -0
- package/external/aport-spec/webhook-spec.md +314 -0
- package/package.json +70 -0
- package/skills/aport-agent-guardrail/SKILL.md +314 -0
- package/src/evaluator.js +252 -0
- package/src/server/index.js +72 -0
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
from fastapi import FastAPI, HTTPException, Request
|
|
2
|
+
from pydantic import BaseModel
|
|
3
|
+
from aport.middleware import require_policy
|
|
4
|
+
import asyncio
|
|
5
|
+
from typing import List, Optional
|
|
6
|
+
from datetime import datetime
|
|
7
|
+
|
|
8
|
+
app = FastAPI(title="Payment Charge Service", version="1.0.0")
|
|
9
|
+
|
|
10
|
+
class ChargeItem(BaseModel):
|
|
11
|
+
sku: str
|
|
12
|
+
qty: int
|
|
13
|
+
category: Optional[str] = None
|
|
14
|
+
|
|
15
|
+
class ChargeRequest(BaseModel):
|
|
16
|
+
amount: int
|
|
17
|
+
currency: str
|
|
18
|
+
merchant_id: str
|
|
19
|
+
region: str
|
|
20
|
+
shipping_country: Optional[str] = None
|
|
21
|
+
items: List[ChargeItem]
|
|
22
|
+
risk_score: Optional[float] = None
|
|
23
|
+
idempotency_key: str
|
|
24
|
+
|
|
25
|
+
class BatchChargeRequest(BaseModel):
|
|
26
|
+
charges: List[ChargeRequest]
|
|
27
|
+
|
|
28
|
+
class RefundRequest(BaseModel):
|
|
29
|
+
amount: int
|
|
30
|
+
reason: str
|
|
31
|
+
|
|
32
|
+
class ChargeResponse(BaseModel):
|
|
33
|
+
success: bool
|
|
34
|
+
charge_id: str
|
|
35
|
+
amount: int
|
|
36
|
+
currency: str
|
|
37
|
+
status: str
|
|
38
|
+
decision_id: str
|
|
39
|
+
|
|
40
|
+
class ChargeStatus(BaseModel):
|
|
41
|
+
charge_id: str
|
|
42
|
+
status: str
|
|
43
|
+
created_at: str
|
|
44
|
+
amount: int
|
|
45
|
+
currency: str
|
|
46
|
+
merchant_id: str
|
|
47
|
+
items: List[ChargeItem]
|
|
48
|
+
|
|
49
|
+
@app.post("/payments/charge")
|
|
50
|
+
@require_policy("finance.payment.charge.v1")
|
|
51
|
+
async def process_charge(request: Request, charge_data: ChargeRequest):
|
|
52
|
+
try:
|
|
53
|
+
passport = request.state.policy_result.passport
|
|
54
|
+
|
|
55
|
+
# Additional business logic validation
|
|
56
|
+
if charge_data.amount <= 0:
|
|
57
|
+
raise HTTPException(status_code=400, detail="Invalid charge amount")
|
|
58
|
+
|
|
59
|
+
# Check if items are provided
|
|
60
|
+
if not charge_data.items or len(charge_data.items) == 0:
|
|
61
|
+
raise HTTPException(status_code=400, detail="Items are required")
|
|
62
|
+
|
|
63
|
+
# Process charge using your payment processor
|
|
64
|
+
charge_id = await process_charge_payment({
|
|
65
|
+
"amount": charge_data.amount,
|
|
66
|
+
"currency": charge_data.currency,
|
|
67
|
+
"merchant_id": charge_data.merchant_id,
|
|
68
|
+
"region": charge_data.region,
|
|
69
|
+
"shipping_country": charge_data.shipping_country,
|
|
70
|
+
"items": [item.dict() for item in charge_data.items],
|
|
71
|
+
"risk_score": charge_data.risk_score,
|
|
72
|
+
"idempotency_key": charge_data.idempotency_key,
|
|
73
|
+
"agent_id": passport.passport_id,
|
|
74
|
+
"agent_name": passport.metadata.get("template_name", "Unknown Agent") if passport.metadata else "Unknown Agent"
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
# Log the transaction
|
|
78
|
+
print(f"Charge processed: {charge_id} for {charge_data.amount} {charge_data.currency} by agent {passport.passport_id}")
|
|
79
|
+
|
|
80
|
+
return ChargeResponse(
|
|
81
|
+
success=True,
|
|
82
|
+
charge_id=charge_id,
|
|
83
|
+
amount=charge_data.amount,
|
|
84
|
+
currency=charge_data.currency,
|
|
85
|
+
status="processed",
|
|
86
|
+
decision_id=request.state.policy_result.decision_id
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
except Exception as e:
|
|
90
|
+
print(f"Charge processing error: {e}")
|
|
91
|
+
raise HTTPException(status_code=500, detail="Internal server error")
|
|
92
|
+
|
|
93
|
+
@app.post("/payments/charge/batch")
|
|
94
|
+
@require_policy("finance.payment.charge.v1")
|
|
95
|
+
async def process_batch_charges(request: Request, batch_data: BatchChargeRequest):
|
|
96
|
+
try:
|
|
97
|
+
passport = request.state.policy_result.passport
|
|
98
|
+
|
|
99
|
+
# Group charges by currency for daily cap checking
|
|
100
|
+
currency_totals = {}
|
|
101
|
+
for charge in batch_data.charges:
|
|
102
|
+
currency = charge.currency
|
|
103
|
+
currency_totals[currency] = currency_totals.get(currency, 0) + charge.amount
|
|
104
|
+
|
|
105
|
+
# Check daily caps per currency
|
|
106
|
+
for currency, total_amount in currency_totals.items():
|
|
107
|
+
currency_limits = passport.limits.get("payments", {}).get("charge", {}).get("currency_limits", {}).get(currency)
|
|
108
|
+
if currency_limits and currency_limits.get("daily_cap") and total_amount > currency_limits["daily_cap"]:
|
|
109
|
+
raise HTTPException(
|
|
110
|
+
status_code=403,
|
|
111
|
+
detail={
|
|
112
|
+
"error": "Batch total exceeds daily cap",
|
|
113
|
+
"currency": currency,
|
|
114
|
+
"total": total_amount,
|
|
115
|
+
"limit": currency_limits["daily_cap"]
|
|
116
|
+
}
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
# Process batch charges
|
|
120
|
+
results = await asyncio.gather(*[
|
|
121
|
+
process_charge_payment({
|
|
122
|
+
"amount": charge.amount,
|
|
123
|
+
"currency": charge.currency,
|
|
124
|
+
"merchant_id": charge.merchant_id,
|
|
125
|
+
"region": charge.region,
|
|
126
|
+
"shipping_country": charge.shipping_country,
|
|
127
|
+
"items": [item.dict() for item in charge.items],
|
|
128
|
+
"risk_score": charge.risk_score,
|
|
129
|
+
"idempotency_key": charge.idempotency_key,
|
|
130
|
+
"agent_id": passport.passport_id
|
|
131
|
+
})
|
|
132
|
+
for charge in batch_data.charges
|
|
133
|
+
])
|
|
134
|
+
|
|
135
|
+
return {
|
|
136
|
+
"success": True,
|
|
137
|
+
"processed": len(results),
|
|
138
|
+
"currency_totals": currency_totals,
|
|
139
|
+
"decision_id": request.state.policy_result.decision_id
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
except Exception as e:
|
|
143
|
+
print(f"Batch charge error: {e}")
|
|
144
|
+
raise HTTPException(status_code=500, detail="Internal server error")
|
|
145
|
+
|
|
146
|
+
@app.get("/payments/charge/{charge_id}")
|
|
147
|
+
@require_policy("finance.payment.charge.v1")
|
|
148
|
+
async def get_charge_status(request: Request, charge_id: str):
|
|
149
|
+
try:
|
|
150
|
+
passport = request.state.policy_result.passport
|
|
151
|
+
|
|
152
|
+
charge_info = await get_charge_status(charge_id, passport.passport_id)
|
|
153
|
+
|
|
154
|
+
if not charge_info:
|
|
155
|
+
raise HTTPException(status_code=404, detail="Charge not found")
|
|
156
|
+
|
|
157
|
+
return charge_info
|
|
158
|
+
|
|
159
|
+
except Exception as e:
|
|
160
|
+
print(f"Charge status error: {e}")
|
|
161
|
+
raise HTTPException(status_code=500, detail="Internal server error")
|
|
162
|
+
|
|
163
|
+
@app.post("/payments/charge/{charge_id}/refund")
|
|
164
|
+
@require_policy("finance.payment.charge.v1")
|
|
165
|
+
async def process_refund(request: Request, charge_id: str, refund_data: RefundRequest):
|
|
166
|
+
try:
|
|
167
|
+
passport = request.state.policy_result.passport
|
|
168
|
+
|
|
169
|
+
refund_id = await process_refund_payment({
|
|
170
|
+
"charge_id": charge_id,
|
|
171
|
+
"amount": refund_data.amount,
|
|
172
|
+
"reason": refund_data.reason,
|
|
173
|
+
"agent_id": passport.passport_id
|
|
174
|
+
})
|
|
175
|
+
|
|
176
|
+
return {
|
|
177
|
+
"success": True,
|
|
178
|
+
"refund_id": refund_id,
|
|
179
|
+
"charge_id": charge_id,
|
|
180
|
+
"amount": refund_data.amount,
|
|
181
|
+
"status": "refunded",
|
|
182
|
+
"decision_id": request.state.policy_result.decision_id
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
except Exception as e:
|
|
186
|
+
print(f"Refund processing error: {e}")
|
|
187
|
+
raise HTTPException(status_code=500, detail="Internal server error")
|
|
188
|
+
|
|
189
|
+
async def process_charge_payment(charge_data: dict) -> str:
|
|
190
|
+
"""Mock charge processing function"""
|
|
191
|
+
# Simulate payment processor call
|
|
192
|
+
await asyncio.sleep(0.1)
|
|
193
|
+
|
|
194
|
+
# Log charge details for audit
|
|
195
|
+
print(f"Processing charge: {charge_data}")
|
|
196
|
+
|
|
197
|
+
return f"chg_{asyncio.get_event_loop().time()}_{hash(str(charge_data)) % 1000000}"
|
|
198
|
+
|
|
199
|
+
async def get_charge_status(charge_id: str, agent_id: str) -> Optional[ChargeStatus]:
|
|
200
|
+
"""Mock charge status lookup"""
|
|
201
|
+
await asyncio.sleep(0.05)
|
|
202
|
+
return ChargeStatus(
|
|
203
|
+
charge_id=charge_id,
|
|
204
|
+
status="completed",
|
|
205
|
+
created_at=datetime.now().isoformat(),
|
|
206
|
+
amount=1299,
|
|
207
|
+
currency="USD",
|
|
208
|
+
merchant_id="merch_abc",
|
|
209
|
+
items=[
|
|
210
|
+
ChargeItem(sku="SKU-1", qty=1, category="electronics")
|
|
211
|
+
]
|
|
212
|
+
)
|
|
213
|
+
|
|
214
|
+
async def process_refund_payment(refund_data: dict) -> str:
|
|
215
|
+
"""Mock refund processing function"""
|
|
216
|
+
# Simulate refund processing
|
|
217
|
+
await asyncio.sleep(0.1)
|
|
218
|
+
|
|
219
|
+
print(f"Processing refund: {refund_data}")
|
|
220
|
+
|
|
221
|
+
return f"ref_{asyncio.get_event_loop().time()}_{hash(str(refund_data)) % 1000000}"
|
|
222
|
+
|
|
223
|
+
if __name__ == "__main__":
|
|
224
|
+
import uvicorn
|
|
225
|
+
print("Payment charge service starting...")
|
|
226
|
+
print("Protected by APort finance.payment.charge.v1 policy pack")
|
|
227
|
+
uvicorn.run(app, host="0.0.0.0", port=8000)
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal Example: finance.payment.charge.v1 Policy
|
|
3
|
+
*
|
|
4
|
+
* This is a quick-start example showing the basic usage of the finance.payment.charge.v1 policy.
|
|
5
|
+
* For production use, see the full express.example.js file.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const express = require("express");
|
|
9
|
+
const { requirePolicy } = require("@aporthq/middleware-express");
|
|
10
|
+
|
|
11
|
+
const app = express();
|
|
12
|
+
app.use(express.json());
|
|
13
|
+
|
|
14
|
+
// Minimal charge endpoint with policy protection
|
|
15
|
+
app.post(
|
|
16
|
+
"/charge",
|
|
17
|
+
requirePolicy("finance.payment.charge.v1"),
|
|
18
|
+
async (req, res) => {
|
|
19
|
+
try {
|
|
20
|
+
const { amount, currency, merchant_id, items } = req.body;
|
|
21
|
+
const passport = req.policyResult.passport;
|
|
22
|
+
|
|
23
|
+
// Process the charge (your business logic here)
|
|
24
|
+
const charge_id = `chg_${Date.now()}`;
|
|
25
|
+
|
|
26
|
+
console.log(`Charge processed: ${charge_id} for ${amount} ${currency}`);
|
|
27
|
+
|
|
28
|
+
res.json({
|
|
29
|
+
success: true,
|
|
30
|
+
charge_id,
|
|
31
|
+
amount,
|
|
32
|
+
currency,
|
|
33
|
+
decision_id: req.policyResult.decision_id,
|
|
34
|
+
});
|
|
35
|
+
} catch (error) {
|
|
36
|
+
console.error("Charge error:", error);
|
|
37
|
+
res.status(500).json({ error: "Internal server error" });
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
// Example client request
|
|
43
|
+
const exampleRequest = {
|
|
44
|
+
amount: 1299, // $12.99 in cents
|
|
45
|
+
currency: "USD",
|
|
46
|
+
merchant_id: "merch_abc",
|
|
47
|
+
region: "US",
|
|
48
|
+
shipping_country: "US",
|
|
49
|
+
items: [{ sku: "SKU-1", qty: 1, category: "electronics" }],
|
|
50
|
+
idempotency_key: "charge-ord-123",
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
console.log("Example request:", JSON.stringify(exampleRequest, null, 2));
|
|
54
|
+
|
|
55
|
+
const PORT = process.env.PORT || 3000;
|
|
56
|
+
app.listen(PORT, () => {
|
|
57
|
+
console.log(`Minimal charge service running on port ${PORT}`);
|
|
58
|
+
console.log("Protected by APort finance.payment.charge.v1 policy");
|
|
59
|
+
console.log(
|
|
60
|
+
`Try: curl -X POST http://localhost:${PORT}/charge -H "Content-Type: application/json" -d '${JSON.stringify(
|
|
61
|
+
exampleRequest
|
|
62
|
+
)}'`
|
|
63
|
+
);
|
|
64
|
+
});
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "finance.payment.charge.v1",
|
|
3
|
+
"name": "Payment Charge Policy",
|
|
4
|
+
"description": "Pre-action governance for agent-initiated payments. Enforces per-currency caps, merchant/region allowlists, category blocks, assurance minimums, and idempotency.",
|
|
5
|
+
"version": "1.0.0",
|
|
6
|
+
"status": "active",
|
|
7
|
+
"requires_capabilities": ["payments.charge"],
|
|
8
|
+
"min_assurance": "L2",
|
|
9
|
+
"limits_required": [
|
|
10
|
+
"currency_limits",
|
|
11
|
+
"allowed_merchant_ids",
|
|
12
|
+
"allowed_countries",
|
|
13
|
+
"blocked_categories",
|
|
14
|
+
"max_items_per_tx",
|
|
15
|
+
"require_assurance_at_least",
|
|
16
|
+
"idempotency_required",
|
|
17
|
+
"approval_required"
|
|
18
|
+
],
|
|
19
|
+
"required_fields": [
|
|
20
|
+
"amount",
|
|
21
|
+
"currency",
|
|
22
|
+
"merchant_id",
|
|
23
|
+
"region",
|
|
24
|
+
"items",
|
|
25
|
+
"idempotency_key"
|
|
26
|
+
],
|
|
27
|
+
"optional_fields": ["shipping_country", "risk_score"],
|
|
28
|
+
"enforcement": {
|
|
29
|
+
"currency_supported": true,
|
|
30
|
+
"region_in": true,
|
|
31
|
+
"idempotency_required": true,
|
|
32
|
+
"amount_lte": "limits.payments.charge.currency_limits.{currency}.max_per_tx",
|
|
33
|
+
"daily_cap_check": "limits.payments.charge.currency_limits.{currency}.daily_cap",
|
|
34
|
+
"merchant_allowlist": "limits.payments.charge.allowed_merchant_ids",
|
|
35
|
+
"country_allowlist": "limits.payments.charge.allowed_countries",
|
|
36
|
+
"category_blocklist": "limits.payments.charge.blocked_categories",
|
|
37
|
+
"item_count_cap": "limits.payments.charge.max_items_per_tx"
|
|
38
|
+
},
|
|
39
|
+
"mcp": {
|
|
40
|
+
"require_allowlisted_if_present": true
|
|
41
|
+
},
|
|
42
|
+
"advice": [
|
|
43
|
+
"Cache /verify with ETag; 60s TTL",
|
|
44
|
+
"Subscribe to status webhooks for instant suspend",
|
|
45
|
+
"Log all charge attempts for Verifiable Attestation",
|
|
46
|
+
"Implement daily spend tracking per currency to prevent abuse",
|
|
47
|
+
"Always use unique idempotency keys to prevent duplicate charges",
|
|
48
|
+
"Provide clear error messages to help agents self-remediate",
|
|
49
|
+
"Maintain merchant allowlists for trusted partners",
|
|
50
|
+
"Block high-risk categories (weapons, illicit goods)"
|
|
51
|
+
],
|
|
52
|
+
"required_context": {
|
|
53
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
54
|
+
"type": "object",
|
|
55
|
+
"required": [
|
|
56
|
+
"amount",
|
|
57
|
+
"currency",
|
|
58
|
+
"merchant_id",
|
|
59
|
+
"region",
|
|
60
|
+
"items",
|
|
61
|
+
"idempotency_key"
|
|
62
|
+
],
|
|
63
|
+
"properties": {
|
|
64
|
+
"amount": {
|
|
65
|
+
"type": "integer",
|
|
66
|
+
"minimum": 1,
|
|
67
|
+
"description": "Minor units (e.g., cents)"
|
|
68
|
+
},
|
|
69
|
+
"currency": {
|
|
70
|
+
"type": "string",
|
|
71
|
+
"pattern": "^[A-Z]{3}$",
|
|
72
|
+
"description": "ISO 4217 currency code"
|
|
73
|
+
},
|
|
74
|
+
"merchant_id": {
|
|
75
|
+
"type": "string",
|
|
76
|
+
"description": "Merchant identifier"
|
|
77
|
+
},
|
|
78
|
+
"region": {
|
|
79
|
+
"type": "string",
|
|
80
|
+
"description": "Geographic region"
|
|
81
|
+
},
|
|
82
|
+
"shipping_country": {
|
|
83
|
+
"type": "string",
|
|
84
|
+
"description": "Shipping country code"
|
|
85
|
+
},
|
|
86
|
+
"items": {
|
|
87
|
+
"type": "array",
|
|
88
|
+
"minItems": 1,
|
|
89
|
+
"description": "Array of items being purchased",
|
|
90
|
+
"items": {
|
|
91
|
+
"type": "object",
|
|
92
|
+
"required": ["sku", "qty", "price"],
|
|
93
|
+
"properties": {
|
|
94
|
+
"sku": {
|
|
95
|
+
"type": "string",
|
|
96
|
+
"description": "Stock keeping unit"
|
|
97
|
+
},
|
|
98
|
+
"qty": {
|
|
99
|
+
"type": "integer",
|
|
100
|
+
"minimum": 1,
|
|
101
|
+
"description": "Quantity"
|
|
102
|
+
},
|
|
103
|
+
"name": {
|
|
104
|
+
"type": "string",
|
|
105
|
+
"maxLength": 200,
|
|
106
|
+
"description": "Item name for audit and compliance"
|
|
107
|
+
},
|
|
108
|
+
"price": {
|
|
109
|
+
"type": "integer",
|
|
110
|
+
"minimum": 1,
|
|
111
|
+
"description": "Price in minor currency units (e.g., cents)"
|
|
112
|
+
},
|
|
113
|
+
"category": {
|
|
114
|
+
"type": "string",
|
|
115
|
+
"description": "Item category"
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
},
|
|
120
|
+
"risk_score": {
|
|
121
|
+
"type": "number",
|
|
122
|
+
"minimum": 0,
|
|
123
|
+
"maximum": 100,
|
|
124
|
+
"description": "Risk score (0-100)"
|
|
125
|
+
},
|
|
126
|
+
"idempotency_key": {
|
|
127
|
+
"type": "string",
|
|
128
|
+
"minLength": 8,
|
|
129
|
+
"description": "Idempotency key for duplicate prevention"
|
|
130
|
+
},
|
|
131
|
+
"mcp_servers": {
|
|
132
|
+
"type": "array",
|
|
133
|
+
"items": { "type": "string" },
|
|
134
|
+
"description": "MCP servers being used in this request (e.g., [\"https://mcp.stripe.com\"])"
|
|
135
|
+
},
|
|
136
|
+
"mcp_tools": {
|
|
137
|
+
"type": "array",
|
|
138
|
+
"items": { "type": "string" },
|
|
139
|
+
"description": "MCP tools being used in this request (e.g., [\"stripe.charges.create\"])"
|
|
140
|
+
},
|
|
141
|
+
"mcp_server": {
|
|
142
|
+
"type": "string",
|
|
143
|
+
"description": "Single MCP server being used (backward compatibility - use mcp_servers array for multiple)"
|
|
144
|
+
},
|
|
145
|
+
"mcp_tool": {
|
|
146
|
+
"type": "string",
|
|
147
|
+
"description": "Single MCP tool being used (backward compatibility - use mcp_tools array for multiple)"
|
|
148
|
+
},
|
|
149
|
+
"mcp_session": {
|
|
150
|
+
"type": "string",
|
|
151
|
+
"description": "MCP session identifier for audit trail (optional)"
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
},
|
|
155
|
+
"evaluation_rules": [
|
|
156
|
+
{
|
|
157
|
+
"name": "passport_status_active",
|
|
158
|
+
"condition": "passport.status == 'active'",
|
|
159
|
+
"deny_code": "oap.passport_suspended",
|
|
160
|
+
"description": "Passport must be active"
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
"name": "assurance_minimum",
|
|
164
|
+
"condition": "passport.assurance_level >= limits.payments.charge.require_assurance_at_least",
|
|
165
|
+
"deny_code": "oap.assurance_insufficient",
|
|
166
|
+
"description": "Assurance level must meet minimum requirement"
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
"name": "currency_supported",
|
|
170
|
+
"condition": "currency in limits.payments.charge.currency_limits",
|
|
171
|
+
"deny_code": "oap.currency_unsupported",
|
|
172
|
+
"description": "Currency must be supported"
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
"name": "per_tx_amount_cap",
|
|
176
|
+
"condition": "amount <= limits.payments.charge.currency_limits[currency].max_per_tx",
|
|
177
|
+
"deny_code": "oap.limit_exceeded",
|
|
178
|
+
"description": "Amount must not exceed per-transaction limit"
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
"name": "item_count_cap",
|
|
182
|
+
"condition": "items.length <= limits.payments.charge.max_items_per_tx",
|
|
183
|
+
"deny_code": "oap.limit_exceeded",
|
|
184
|
+
"description": "Item count must not exceed limit"
|
|
185
|
+
},
|
|
186
|
+
{
|
|
187
|
+
"name": "merchant_allowed",
|
|
188
|
+
"condition": "merchant_id in limits.payments.charge.allowed_merchant_ids OR limits.payments.charge.allowed_merchant_ids is empty",
|
|
189
|
+
"deny_code": "oap.merchant_forbidden",
|
|
190
|
+
"description": "Merchant must be in allowlist"
|
|
191
|
+
},
|
|
192
|
+
{
|
|
193
|
+
"name": "country_allowed",
|
|
194
|
+
"condition": "shipping_country in limits.payments.charge.allowed_countries OR limits.payments.charge.allowed_countries is empty",
|
|
195
|
+
"deny_code": "oap.region_blocked",
|
|
196
|
+
"description": "Shipping country must be allowed"
|
|
197
|
+
},
|
|
198
|
+
{
|
|
199
|
+
"name": "category_block",
|
|
200
|
+
"condition": "NOT any(item.category in limits.payments.charge.blocked_categories for item in items)",
|
|
201
|
+
"deny_code": "oap.category_blocked",
|
|
202
|
+
"description": "Items must not be in blocked categories"
|
|
203
|
+
},
|
|
204
|
+
{
|
|
205
|
+
"name": "daily_cap_check",
|
|
206
|
+
"condition": "daily_total + amount <= limits.payments.charge.currency_limits[currency].daily_cap",
|
|
207
|
+
"deny_code": "oap.limit_exceeded",
|
|
208
|
+
"description": "Daily cap must not be exceeded"
|
|
209
|
+
},
|
|
210
|
+
{
|
|
211
|
+
"name": "idempotency_check",
|
|
212
|
+
"condition": "idempotency_key not in recent_keys",
|
|
213
|
+
"deny_code": "oap.idempotency_conflict",
|
|
214
|
+
"description": "Idempotency key must be unique"
|
|
215
|
+
}
|
|
216
|
+
],
|
|
217
|
+
"cache": {
|
|
218
|
+
"default_ttl_seconds": 60,
|
|
219
|
+
"suspend_invalidate_seconds": 30
|
|
220
|
+
},
|
|
221
|
+
"deprecation": null,
|
|
222
|
+
"created_at": "2025-01-30T00:00:00Z",
|
|
223
|
+
"updated_at": "2025-01-30T00:00:00Z"
|
|
224
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{"name":"allow_usd_12_99","context":{"amount":1299,"currency":"USD","merchant_id":"merch_abc","region":"US","shipping_country":"US","items":[{"sku":"SKU-1","qty":1,"category":"electronics"}],"idempotency_key":"charge-ord-1001"}}
|
|
2
|
+
{"name":"deny_currency_unsupported","context":{"amount":1000,"currency":"GBP","merchant_id":"merch_abc","region":"US","items":[{"sku":"SKU-2","qty":1,"category":"books"}],"idempotency_key":"charge-ord-1002"}}
|
|
3
|
+
{"name":"deny_over_per_tx","context":{"amount":25000,"currency":"USD","merchant_id":"merch_abc","region":"US","items":[{"sku":"SKU-3","qty":1,"category":"electronics"}],"idempotency_key":"charge-ord-1003"}}
|
|
4
|
+
{"name":"deny_items_exceeded","context":{"amount":1500,"currency":"USD","merchant_id":"merch_abc","region":"US","items":[{"sku":"A","qty":1},{"sku":"B","qty":1},{"sku":"C","qty":1},{"sku":"D","qty":1},{"sku":"E","qty":1},{"sku":"F","qty":1}],"idempotency_key":"charge-ord-1004"}}
|
|
5
|
+
{"name":"deny_merchant_forbidden","context":{"amount":500,"currency":"USD","merchant_id":"merch_bad","region":"US","items":[{"sku":"SKU-4","qty":1}],"idempotency_key":"charge-ord-1005"}}
|
|
6
|
+
{"name":"deny_country_blocked","context":{"amount":500,"currency":"USD","merchant_id":"merch_abc","region":"US","shipping_country":"BR","items":[{"sku":"SKU-5","qty":1}],"idempotency_key":"charge-ord-1006"}}
|
|
7
|
+
{"name":"deny_category_blocked","context":{"amount":5000,"currency":"USD","merchant_id":"merch_abc","region":"US","shipping_country":"US","items":[{"sku":"SKU-6","qty":1,"category":"weapons"}],"idempotency_key":"charge-ord-1007"}}
|
|
8
|
+
{"name":"allow_eur_10","context":{"amount":1000,"currency":"EUR","merchant_id":"merch_xyz","region":"EU","shipping_country":"DE","items":[{"sku":"SKU-7","qty":1,"category":"books"}],"idempotency_key":"charge-ord-1008"}}
|
|
9
|
+
{"name":"deny_daily_cap_exceeded_step1","context":{"amount":60000,"currency":"USD","merchant_id":"merch_abc","region":"US","items":[{"sku":"SKU-8","qty":1}],"idempotency_key":"charge-ord-1009"}}
|
|
10
|
+
{"name":"deny_daily_cap_exceeded_step2","context":{"amount":50000,"currency":"USD","merchant_id":"merch_abc","region":"US","items":[{"sku":"SKU-9","qty":1}],"idempotency_key":"charge-ord-1010"}}
|
|
11
|
+
{"name":"deny_idempotency_replay","context":{"amount":1299,"currency":"USD","merchant_id":"merch_abc","region":"US","items":[{"sku":"SKU-1","qty":1}],"idempotency_key":"charge-ord-1001"}}
|
|
12
|
+
{"name":"deny_assurance_insufficient","overridePassport":{"assurance_level":"L1"},"context":{"amount":500,"currency":"USD","merchant_id":"merch_abc","region":"US","items":[{"sku":"SKU-10","qty":1}],"idempotency_key":"charge-ord-1011"}}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{"decision_id":"550e8400-e29b-41d4-a716-446655440002","policy_id":"finance.payment.charge.v1","agent_id":"550e8400-e29b-41d4-a716-446655440001","owner_id":"org_demo_co","assurance_level":"L2","allow":true,"reasons":[{"code":"oap.allowed","message":"Transaction within limits and policy requirements"}],"created_at":"2025-01-30T10:30:00Z","expires_in":3600,"passport_digest":"sha256:abcd1234efgh5678ijkl9012mnop3456qrst7890uvwx1234yzab5678cdef","signature":"ed25519:abcd1234efgh5678ijkl9012mnop3456qrst7890uvwx1234yzab5678cdef==","kid":"oap:registry:key-2025-01"}
|
|
2
|
+
{"decision_id":"550e8400-e29b-41d4-a716-446655440003","policy_id":"finance.payment.charge.v1","agent_id":"550e8400-e29b-41d4-a716-446655440001","owner_id":"org_demo_co","assurance_level":"L2","allow":false,"reasons":[{"code":"oap.currency_unsupported","message":"Currency GBP is not supported"}],"created_at":"2025-01-30T10:30:00Z","expires_in":3600,"passport_digest":"sha256:abcd1234efgh5678ijkl9012mnop3456qrst7890uvwx1234yzab5678cdef","signature":"ed25519:abcd1234efgh5678ijkl9012mnop3456qrst7890uvwx1234yzab5678cdef==","kid":"oap:registry:key-2025-01"}
|
|
3
|
+
{"decision_id":"550e8400-e29b-41d4-a716-446655440004","policy_id":"finance.payment.charge.v1","agent_id":"550e8400-e29b-41d4-a716-446655440001","owner_id":"org_demo_co","assurance_level":"L2","allow":false,"reasons":[{"code":"oap.limit_exceeded","message":"Amount exceeds per-transaction limit"}],"created_at":"2025-01-30T10:30:00Z","expires_in":3600,"passport_digest":"sha256:abcd1234efgh5678ijkl9012mnop3456qrst7890uvwx1234yzab5678cdef","signature":"ed25519:abcd1234efgh5678ijkl9012mnop3456qrst7890uvwx1234yzab5678cdef==","kid":"oap:registry:key-2025-01"}
|
|
4
|
+
{"decision_id":"550e8400-e29b-41d4-a716-446655440005","policy_id":"finance.payment.charge.v1","agent_id":"550e8400-e29b-41d4-a716-446655440001","owner_id":"org_demo_co","assurance_level":"L2","allow":false,"reasons":[{"code":"oap.limit_exceeded","message":"Item count exceeds maximum allowed"}],"created_at":"2025-01-30T10:30:00Z","expires_in":3600,"passport_digest":"sha256:abcd1234efgh5678ijkl9012mnop3456qrst7890uvwx1234yzab5678cdef","signature":"ed25519:abcd1234efgh5678ijkl9012mnop3456qrst7890uvwx1234yzab5678cdef==","kid":"oap:registry:key-2025-01"}
|
|
5
|
+
{"decision_id":"550e8400-e29b-41d4-a716-446655440006","policy_id":"finance.payment.charge.v1","agent_id":"550e8400-e29b-41d4-a716-446655440001","owner_id":"org_demo_co","assurance_level":"L2","allow":false,"reasons":[{"code":"oap.merchant_forbidden","message":"Merchant not in allowlist"}],"created_at":"2025-01-30T10:30:00Z","expires_in":3600,"passport_digest":"sha256:abcd1234efgh5678ijkl9012mnop3456qrst7890uvwx1234yzab5678cdef","signature":"ed25519:abcd1234efgh5678ijkl9012mnop3456qrst7890uvwx1234yzab5678cdef==","kid":"oap:registry:key-2025-01"}
|
|
6
|
+
{"decision_id":"550e8400-e29b-41d4-a716-446655440007","policy_id":"finance.payment.charge.v1","agent_id":"550e8400-e29b-41d4-a716-446655440001","owner_id":"org_demo_co","assurance_level":"L2","allow":false,"reasons":[{"code":"oap.region_blocked","message":"Shipping country not allowed"}],"created_at":"2025-01-30T10:30:00Z","expires_in":3600,"passport_digest":"sha256:abcd1234efgh5678ijkl9012mnop3456qrst7890uvwx1234yzab5678cdef","signature":"ed25519:abcd1234efgh5678ijkl9012mnop3456qrst7890uvwx1234yzab5678cdef==","kid":"oap:registry:key-2025-01"}
|
|
7
|
+
{"decision_id":"550e8400-e29b-41d4-a716-446655440008","policy_id":"finance.payment.charge.v1","agent_id":"550e8400-e29b-41d4-a716-446655440001","owner_id":"org_demo_co","assurance_level":"L2","allow":false,"reasons":[{"code":"oap.category_blocked","message":"Item category is blocked"}],"created_at":"2025-01-30T10:30:00Z","expires_in":3600,"passport_digest":"sha256:abcd1234efgh5678ijkl9012mnop3456qrst7890uvwx1234yzab5678cdef","signature":"ed25519:abcd1234efgh5678ijkl9012mnop3456qrst7890uvwx1234yzab5678cdef==","kid":"oap:registry:key-2025-01"}
|
|
8
|
+
{"decision_id":"550e8400-e29b-41d4-a716-446655440009","policy_id":"finance.payment.charge.v1","agent_id":"550e8400-e29b-41d4-a716-446655440001","owner_id":"org_demo_co","assurance_level":"L2","allow":true,"reasons":[{"code":"oap.allowed","message":"Transaction within limits and policy requirements"}],"created_at":"2025-01-30T10:30:00Z","expires_in":3600,"passport_digest":"sha256:abcd1234efgh5678ijkl9012mnop3456qrst7890uvwx1234yzab5678cdef","signature":"ed25519:abcd1234efgh5678ijkl9012mnop3456qrst7890uvwx1234yzab5678cdef==","kid":"oap:registry:key-2025-01"}
|
|
9
|
+
{"decision_id":"550e8400-e29b-41d4-a716-446655440010","policy_id":"finance.payment.charge.v1","agent_id":"550e8400-e29b-41d4-a716-446655440001","owner_id":"org_demo_co","assurance_level":"L2","allow":true,"reasons":[{"code":"oap.allowed","message":"Transaction within limits and policy requirements"}],"created_at":"2025-01-30T10:30:00Z","expires_in":3600,"passport_digest":"sha256:abcd1234efgh5678ijkl9012mnop3456qrst7890uvwx1234yzab5678cdef","signature":"ed25519:abcd1234efgh5678ijkl9012mnop3456qrst7890uvwx1234yzab5678cdef==","kid":"oap:registry:key-2025-01"}
|
|
10
|
+
{"decision_id":"550e8400-e29b-41d4-a716-446655440011","policy_id":"finance.payment.charge.v1","agent_id":"550e8400-e29b-41d4-a716-446655440001","owner_id":"org_demo_co","assurance_level":"L2","allow":false,"reasons":[{"code":"oap.limit_exceeded","message":"Daily cap exceeded"}],"created_at":"2025-01-30T10:30:00Z","expires_in":3600,"passport_digest":"sha256:abcd1234efgh5678ijkl9012mnop3456qrst7890uvwx1234yzab5678cdef","signature":"ed25519:abcd1234efgh5678ijkl9012mnop3456qrst7890uvwx1234yzab5678cdef==","kid":"oap:registry:key-2025-01"}
|
|
11
|
+
{"decision_id":"550e8400-e29b-41d4-a716-446655440012","policy_id":"finance.payment.charge.v1","agent_id":"550e8400-e29b-41d4-a716-446655440001","owner_id":"org_demo_co","assurance_level":"L2","allow":false,"reasons":[{"code":"oap.idempotency_conflict","message":"Idempotency key already used"}],"created_at":"2025-01-30T10:30:00Z","expires_in":3600,"passport_digest":"sha256:abcd1234efgh5678ijkl9012mnop3456qrst7890uvwx1234yzab5678cdef","signature":"ed25519:abcd1234efgh5678ijkl9012mnop3456qrst7890uvwx1234yzab5678cdef==","kid":"oap:registry:key-2025-01"}
|
|
12
|
+
{"decision_id":"550e8400-e29b-41d4-a716-446655440013","policy_id":"finance.payment.charge.v1","agent_id":"550e8400-e29b-41d4-a716-446655440001","owner_id":"org_demo_co","assurance_level":"L1","allow":false,"reasons":[{"code":"oap.assurance_insufficient","message":"Assurance level too low"}],"created_at":"2025-01-30T10:30:00Z","expires_in":3600,"passport_digest":"sha256:abcd1234efgh5678ijkl9012mnop3456qrst7890uvwx1234yzab5678cdef","signature":"ed25519:abcd1234efgh5678ijkl9012mnop3456qrst7890uvwx1234yzab5678cdef==","kid":"oap:registry:key-2025-01"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"passport_id": "550e8400-e29b-41d4-a716-446655440001",
|
|
3
|
+
"kind": "instance",
|
|
4
|
+
"spec_version": "oap/1.0",
|
|
5
|
+
"parent_agent_id": "550e8400-e29b-41d4-a716-446655440000",
|
|
6
|
+
"owner_id": "org_demo_co",
|
|
7
|
+
"owner_type": "org",
|
|
8
|
+
"assurance_level": "L2",
|
|
9
|
+
"status": "active",
|
|
10
|
+
"capabilities": [
|
|
11
|
+
{
|
|
12
|
+
"id": "payments.charge",
|
|
13
|
+
"params": {
|
|
14
|
+
"max_amount": 20000,
|
|
15
|
+
"currency": "USD"
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
],
|
|
19
|
+
"limits": {
|
|
20
|
+
"payments.charge": {
|
|
21
|
+
"currency_limits": {
|
|
22
|
+
"USD": { "max_per_tx": 20000, "daily_cap": 100000 },
|
|
23
|
+
"EUR": { "max_per_tx": 18000, "daily_cap": 90000 }
|
|
24
|
+
},
|
|
25
|
+
"allowed_countries": ["US", "CA", "DE", "FR"],
|
|
26
|
+
"blocked_categories": ["weapons", "illicit"],
|
|
27
|
+
"allowed_merchant_ids": ["merch_abc", "merch_xyz"],
|
|
28
|
+
"max_items_per_tx": 5,
|
|
29
|
+
"require_assurance_at_least": "L2",
|
|
30
|
+
"idempotency_required": true
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
"regions": ["US", "CA", "EU"],
|
|
34
|
+
"metadata": {
|
|
35
|
+
"tenant": "shop-123",
|
|
36
|
+
"deployment_id": "deploy_xyz789",
|
|
37
|
+
"environment": "production"
|
|
38
|
+
},
|
|
39
|
+
"created_at": "2025-01-30T00:00:00Z",
|
|
40
|
+
"updated_at": "2025-01-30T00:00:00Z",
|
|
41
|
+
"version": "1.0.0"
|
|
42
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"passport_id": "550e8400-e29b-41d4-a716-446655440000",
|
|
3
|
+
"kind": "template",
|
|
4
|
+
"spec_version": "oap/1.0",
|
|
5
|
+
"owner_id": "org_demo_co",
|
|
6
|
+
"owner_type": "org",
|
|
7
|
+
"assurance_level": "L2",
|
|
8
|
+
"status": "active",
|
|
9
|
+
"capabilities": [
|
|
10
|
+
{
|
|
11
|
+
"id": "payments.charge",
|
|
12
|
+
"params": {
|
|
13
|
+
"max_amount": 20000,
|
|
14
|
+
"currency": "USD"
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
],
|
|
18
|
+
"limits": {
|
|
19
|
+
"payments.charge": {
|
|
20
|
+
"currency_limits": {
|
|
21
|
+
"USD": { "max_per_tx": 20000, "daily_cap": 100000 },
|
|
22
|
+
"EUR": { "max_per_tx": 18000, "daily_cap": 90000 }
|
|
23
|
+
},
|
|
24
|
+
"allowed_countries": ["US", "CA", "DE", "FR"],
|
|
25
|
+
"blocked_categories": ["weapons", "illicit"],
|
|
26
|
+
"allowed_merchant_ids": ["merch_abc", "merch_xyz"],
|
|
27
|
+
"max_items_per_tx": 5,
|
|
28
|
+
"require_assurance_at_least": "L2",
|
|
29
|
+
"idempotency_required": true
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
"regions": ["US", "CA", "EU"],
|
|
33
|
+
"metadata": {
|
|
34
|
+
"template_name": "Demo Charge Template",
|
|
35
|
+
"description": "Template for payment charge operations"
|
|
36
|
+
},
|
|
37
|
+
"created_at": "2025-01-30T00:00:00Z",
|
|
38
|
+
"updated_at": "2025-01-30T00:00:00Z",
|
|
39
|
+
"version": "1.0.0"
|
|
40
|
+
}
|