@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.
Files changed (237) hide show
  1. package/LICENSE +217 -0
  2. package/README.md +481 -0
  3. package/bin/agent-guardrails +133 -0
  4. package/bin/aport-create-passport.sh +444 -0
  5. package/bin/aport-cursor-hook.sh +90 -0
  6. package/bin/aport-guardrail-api.sh +108 -0
  7. package/bin/aport-guardrail-bash.sh +394 -0
  8. package/bin/aport-guardrail-v2.sh +5 -0
  9. package/bin/aport-guardrail.sh +5 -0
  10. package/bin/aport-resolve-paths.sh +71 -0
  11. package/bin/aport-status.sh +276 -0
  12. package/bin/frameworks/crewai.sh +49 -0
  13. package/bin/frameworks/cursor.sh +95 -0
  14. package/bin/frameworks/langchain.sh +48 -0
  15. package/bin/frameworks/n8n.sh +36 -0
  16. package/bin/frameworks/openclaw.sh +19 -0
  17. package/bin/lib/allowlist.sh +18 -0
  18. package/bin/lib/common.sh +28 -0
  19. package/bin/lib/config.sh +46 -0
  20. package/bin/lib/constants.sh +232 -0
  21. package/bin/lib/detect.sh +65 -0
  22. package/bin/lib/error.sh +269 -0
  23. package/bin/lib/passport.sh +19 -0
  24. package/bin/lib/templates/.gitkeep +1 -0
  25. package/bin/lib/templates/config.yaml +6 -0
  26. package/bin/lib/validation.sh +206 -0
  27. package/bin/openclaw +660 -0
  28. package/docs/ADDING_A_FRAMEWORK.md +87 -0
  29. package/docs/AGENTS.md.example +40 -0
  30. package/docs/CODE_REVIEW.md +192 -0
  31. package/docs/DEPLOYMENT_READINESS.md +81 -0
  32. package/docs/FAQ_SECURITY_SCANNERS.md +373 -0
  33. package/docs/FRAMEWORK_ROADMAP.md +41 -0
  34. package/docs/HOSTED_PASSPORT_SETUP.md +362 -0
  35. package/docs/IMPLEMENTING_YOUR_OWN_EVALUATOR.md +433 -0
  36. package/docs/OPENCLAW_COMPATIBILITY.md +73 -0
  37. package/docs/OPENCLAW_LOCAL_INTEGRATION.md +596 -0
  38. package/docs/OPENCLAW_TOOLS_AND_POLICIES.md +54 -0
  39. package/docs/QUICKSTART.md +470 -0
  40. package/docs/QUICKSTART_OPENCLAW_PLUGIN.md +470 -0
  41. package/docs/README.md +28 -0
  42. package/docs/RELEASE.md +87 -0
  43. package/docs/REPO_LAYOUT.md +47 -0
  44. package/docs/SKILLS_ECOSYSTEM_ANALYSIS_FEB17.md +1260 -0
  45. package/docs/TOOL_POLICY_MAPPING.md +46 -0
  46. package/docs/UPGRADE.md +46 -0
  47. package/docs/VERIFICATION_METHODS.md +97 -0
  48. package/docs/assets/README.md +8 -0
  49. package/docs/assets/porter.svg +54 -0
  50. package/docs/development/ERROR_CODES.md +616 -0
  51. package/docs/frameworks/GITHUB_ISSUE_PROPOSALS.md +1105 -0
  52. package/docs/frameworks/crewai.md +114 -0
  53. package/docs/frameworks/cursor.md +159 -0
  54. package/docs/frameworks/langchain.md +72 -0
  55. package/docs/frameworks/n8n.md +40 -0
  56. package/docs/frameworks/openclaw.md +40 -0
  57. package/docs/launch/ADD_APORT_AWESOME_LISTS_INSTRUCTIONS.md +146 -0
  58. package/docs/launch/ANNOUNCEMENT_GUIDE.md +266 -0
  59. package/docs/launch/AWESOME_REPOS.md +53 -0
  60. package/docs/launch/CURSOR_VSCODE_HOOKS_RESEARCH.md +77 -0
  61. package/docs/launch/DEMO_TERMINAL_OUTPUT.txt +48 -0
  62. package/docs/launch/DRY_AND_PLAN_CHECKLIST.md +47 -0
  63. package/docs/launch/EVIDENCE_README.md +61 -0
  64. package/docs/launch/EVIDENCE_TERMINAL_CAPTURE.txt +10 -0
  65. package/docs/launch/FRAMEWORK_SUPPORT_PLAN.md +1640 -0
  66. package/docs/launch/LAUNCH_READINESS_CHECKLIST.md +237 -0
  67. package/docs/launch/LAUNCH_STRATEGY_SUMMARY.md +464 -0
  68. package/docs/launch/OPENCLAW_FEEDBACK_AND_FIXES.md +85 -0
  69. package/docs/launch/POST_1_VALENTINE_IMPROVED.md +233 -0
  70. package/docs/launch/POST_2_GUARDRAIL_IMPROVED.md +369 -0
  71. package/docs/launch/PRE_LAUNCH_FIXES.md +766 -0
  72. package/docs/launch/QUICK_LAUNCH_CHECKLIST.md +400 -0
  73. package/docs/launch/READINESS_SUMMARY.md +262 -0
  74. package/docs/launch/README.md +68 -0
  75. package/docs/launch/USER_STORIES.md +327 -0
  76. package/docs/launch/scripts/add-aport-awesome-pr.sh +69 -0
  77. package/docs/operations/MONITORING.md +588 -0
  78. package/docs/reviews/2026-02-18-staff-review.md +268 -0
  79. package/extensions/openclaw-aport/README.md +415 -0
  80. package/extensions/openclaw-aport/index.js +625 -0
  81. package/extensions/openclaw-aport/openclaw-aport.js +7 -0
  82. package/extensions/openclaw-aport/openclaw.plugin.json +46 -0
  83. package/extensions/openclaw-aport/package.json +36 -0
  84. package/extensions/openclaw-aport/test.js +307 -0
  85. package/external/aport-policies/README.md +363 -0
  86. package/external/aport-policies/agent.session.create.v1/README.md +345 -0
  87. package/external/aport-policies/agent.session.create.v1/policy.json +162 -0
  88. package/external/aport-policies/agent.tool.register.v1/README.md +361 -0
  89. package/external/aport-policies/agent.tool.register.v1/policy.json +172 -0
  90. package/external/aport-policies/code.release.publish.v1/README.md +51 -0
  91. package/external/aport-policies/code.release.publish.v1/policy.json +121 -0
  92. package/external/aport-policies/code.repository.merge.v1/README.md +287 -0
  93. package/external/aport-policies/code.repository.merge.v1/express.example.js +332 -0
  94. package/external/aport-policies/code.repository.merge.v1/fastapi.example.py +370 -0
  95. package/external/aport-policies/code.repository.merge.v1/policy.json +162 -0
  96. package/external/aport-policies/data.export.create.v1/README.md +226 -0
  97. package/external/aport-policies/data.export.create.v1/express.example.js +172 -0
  98. package/external/aport-policies/data.export.create.v1/fastapi.example.py +165 -0
  99. package/external/aport-policies/data.export.create.v1/policy.json +133 -0
  100. package/external/aport-policies/data.report.ingest.v1/README.md +134 -0
  101. package/external/aport-policies/data.report.ingest.v1/express.example.js +105 -0
  102. package/external/aport-policies/data.report.ingest.v1/minimal-example.js +68 -0
  103. package/external/aport-policies/data.report.ingest.v1/policy.json +174 -0
  104. package/external/aport-policies/finance.crypto.trade.v1/README.md +146 -0
  105. package/external/aport-policies/finance.crypto.trade.v1/express.example.js +109 -0
  106. package/external/aport-policies/finance.crypto.trade.v1/minimal-example.js +65 -0
  107. package/external/aport-policies/finance.crypto.trade.v1/policy.json +176 -0
  108. package/external/aport-policies/finance.payment.charge.v1/README.md +326 -0
  109. package/external/aport-policies/finance.payment.charge.v1/express.example.js +250 -0
  110. package/external/aport-policies/finance.payment.charge.v1/fastapi.example.py +227 -0
  111. package/external/aport-policies/finance.payment.charge.v1/minimal-example.js +64 -0
  112. package/external/aport-policies/finance.payment.charge.v1/policy.json +224 -0
  113. package/external/aport-policies/finance.payment.charge.v1/tests/contexts.jsonl +12 -0
  114. package/external/aport-policies/finance.payment.charge.v1/tests/expected.jsonl +12 -0
  115. package/external/aport-policies/finance.payment.charge.v1/tests/passport.instance.json +42 -0
  116. package/external/aport-policies/finance.payment.charge.v1/tests/passport.template.json +40 -0
  117. package/external/aport-policies/finance.payment.charge.v1/tests/payments-charge-policy.test.js +817 -0
  118. package/external/aport-policies/finance.payment.charge.v1/tests/test_payments_charge_policy.py +486 -0
  119. package/external/aport-policies/finance.payment.payout.v1/README.md +78 -0
  120. package/external/aport-policies/finance.payment.payout.v1/policy.json +181 -0
  121. package/external/aport-policies/finance.payment.refund.v1/README.md +275 -0
  122. package/external/aport-policies/finance.payment.refund.v1/express.example.js +167 -0
  123. package/external/aport-policies/finance.payment.refund.v1/fastapi.example.py +136 -0
  124. package/external/aport-policies/finance.payment.refund.v1/minimal-example.js +183 -0
  125. package/external/aport-policies/finance.payment.refund.v1/policy.json +216 -0
  126. package/external/aport-policies/finance.payment.refund.v1/tests/refunds-policy.test.js +924 -0
  127. package/external/aport-policies/finance.payment.refund.v1/tests/test_refunds_policy.py +778 -0
  128. package/external/aport-policies/finance.transaction.execute.v1/README.md +309 -0
  129. package/external/aport-policies/finance.transaction.execute.v1/express.example.js +261 -0
  130. package/external/aport-policies/finance.transaction.execute.v1/fastapi.example.py +231 -0
  131. package/external/aport-policies/finance.transaction.execute.v1/minimal-example.js +78 -0
  132. package/external/aport-policies/finance.transaction.execute.v1/policy.json +189 -0
  133. package/external/aport-policies/finance.transaction.execute.v1/tests/contexts.jsonl +12 -0
  134. package/external/aport-policies/finance.transaction.execute.v1/tests/expected.jsonl +12 -0
  135. package/external/aport-policies/finance.transaction.execute.v1/tests/passport.instance.json +42 -0
  136. package/external/aport-policies/finance.transaction.execute.v1/tests/passport.template.json +42 -0
  137. package/external/aport-policies/finance.transaction.execute.v1/tests/test_transactions_policy.py +214 -0
  138. package/external/aport-policies/finance.transaction.execute.v1/tests/transactions-policy.test.js +306 -0
  139. package/external/aport-policies/governance.data.access.v1/README.md +292 -0
  140. package/external/aport-policies/governance.data.access.v1/express.example.js +321 -0
  141. package/external/aport-policies/governance.data.access.v1/fastapi.example.py +279 -0
  142. package/external/aport-policies/governance.data.access.v1/minimal-example.js +65 -0
  143. package/external/aport-policies/governance.data.access.v1/policy.json +208 -0
  144. package/external/aport-policies/governance.data.access.v1/tests/contexts.jsonl +12 -0
  145. package/external/aport-policies/governance.data.access.v1/tests/data-access-policy.test.js +308 -0
  146. package/external/aport-policies/governance.data.access.v1/tests/expected.jsonl +12 -0
  147. package/external/aport-policies/governance.data.access.v1/tests/passport.instance.json +56 -0
  148. package/external/aport-policies/governance.data.access.v1/tests/passport.template.json +56 -0
  149. package/external/aport-policies/governance.data.access.v1/tests/test_data_access_policy.py +214 -0
  150. package/external/aport-policies/legal.contract.review.v1/README.md +109 -0
  151. package/external/aport-policies/legal.contract.review.v1/policy.json +378 -0
  152. package/external/aport-policies/legal.contract.review.v1/tests/legal-contract-review-policy.test.js +609 -0
  153. package/external/aport-policies/legal.contract.review.v1/tests/passport.template.json +49 -0
  154. package/external/aport-policies/mcp.tool.execute.v1/README.md +301 -0
  155. package/external/aport-policies/mcp.tool.execute.v1/policy.json +141 -0
  156. package/external/aport-policies/messaging.message.send.v1/README.md +230 -0
  157. package/external/aport-policies/messaging.message.send.v1/express.example.js +183 -0
  158. package/external/aport-policies/messaging.message.send.v1/fastapi.example.py +193 -0
  159. package/external/aport-policies/messaging.message.send.v1/policy.json +144 -0
  160. package/external/aport-policies/policy-template.json +107 -0
  161. package/external/aport-policies/system.command.execute.v1/README.md +275 -0
  162. package/external/aport-policies/system.command.execute.v1/policy.json +146 -0
  163. package/external/aport-spec/CONTRIBUTING.md +273 -0
  164. package/external/aport-spec/LICENSE +21 -0
  165. package/external/aport-spec/README.md +168 -0
  166. package/external/aport-spec/conformance/README.md +294 -0
  167. package/external/aport-spec/conformance/cases/data.export.v1/contexts/allow_users.json +6 -0
  168. package/external/aport-spec/conformance/cases/data.export.v1/contexts/deny_pii.json +6 -0
  169. package/external/aport-spec/conformance/cases/data.export.v1/expected/allow_users.decision.json +19 -0
  170. package/external/aport-spec/conformance/cases/data.export.v1/expected/deny_pii.decision.json +19 -0
  171. package/external/aport-spec/conformance/cases/data.export.v1/passports/template.json +29 -0
  172. package/external/aport-spec/conformance/cases/payments.refunds.v1/contexts/allow_50usd.json +9 -0
  173. package/external/aport-spec/conformance/cases/payments.refunds.v1/contexts/deny_150usd.json +9 -0
  174. package/external/aport-spec/conformance/cases/payments.refunds.v1/contexts/deny_currency.json +9 -0
  175. package/external/aport-spec/conformance/cases/payments.refunds.v1/expected/allow_50usd.decision.json +19 -0
  176. package/external/aport-spec/conformance/cases/payments.refunds.v1/expected/deny_150usd.decision.json +19 -0
  177. package/external/aport-spec/conformance/cases/payments.refunds.v1/expected/deny_currency.decision.json +19 -0
  178. package/external/aport-spec/conformance/cases/payments.refunds.v1/passports/template.json +42 -0
  179. package/external/aport-spec/conformance/package.json +44 -0
  180. package/external/aport-spec/conformance/pnpm-lock.yaml +642 -0
  181. package/external/aport-spec/conformance/src/cases.ts +371 -0
  182. package/external/aport-spec/conformance/src/ed25519.ts +167 -0
  183. package/external/aport-spec/conformance/src/jcs.ts +85 -0
  184. package/external/aport-spec/conformance/src/runner.ts +533 -0
  185. package/external/aport-spec/conformance/src/validators.ts +185 -0
  186. package/external/aport-spec/conformance/test-runner.js +315 -0
  187. package/external/aport-spec/conformance/tsconfig.json +21 -0
  188. package/external/aport-spec/error-schema.json +192 -0
  189. package/external/aport-spec/index.json +12 -0
  190. package/external/aport-spec/integrations/clawmoat/README.md +12 -0
  191. package/external/aport-spec/integrations/shield/README.md +245 -0
  192. package/external/aport-spec/integrations/shield/adapters/index.js +116 -0
  193. package/external/aport-spec/integrations/shield/adapters/system-command-execute.js +133 -0
  194. package/external/aport-spec/integrations/shield/test/README.md +58 -0
  195. package/external/aport-spec/integrations/shield/test/shield.md +40 -0
  196. package/external/aport-spec/integrations/shield/test/test-shield-to-verify.js +274 -0
  197. package/external/aport-spec/metrics-schema.json +504 -0
  198. package/external/aport-spec/oap/CHANGELOG.md +54 -0
  199. package/external/aport-spec/oap/VERSION.md +40 -0
  200. package/external/aport-spec/oap/capability-registry.md +229 -0
  201. package/external/aport-spec/oap/conformance.md +257 -0
  202. package/external/aport-spec/oap/decision-schema.json +114 -0
  203. package/external/aport-spec/oap/examples/context.refund.usd.50.json +9 -0
  204. package/external/aport-spec/oap/examples/decision.allow.sample.json +20 -0
  205. package/external/aport-spec/oap/examples/decision.deny.sample.json +23 -0
  206. package/external/aport-spec/oap/examples/passport.instance.v1.json +50 -0
  207. package/external/aport-spec/oap/examples/passport.template.v1.json +71 -0
  208. package/external/aport-spec/oap/oap-spec.md +426 -0
  209. package/external/aport-spec/oap/passport-schema.json +396 -0
  210. package/external/aport-spec/oap/security.md +213 -0
  211. package/external/aport-spec/oap/vc/context-oap-v1.jsonld +137 -0
  212. package/external/aport-spec/oap/vc/examples/oap-decision-vc.json +37 -0
  213. package/external/aport-spec/oap/vc/examples/oap-passport-vc.json +68 -0
  214. package/external/aport-spec/oap/vc/tools/INTEGRATION.md +375 -0
  215. package/external/aport-spec/oap/vc/tools/README.md +278 -0
  216. package/external/aport-spec/oap/vc/tools/examples/decision-to-vc.js +66 -0
  217. package/external/aport-spec/oap/vc/tools/examples/passport-to-vc.js +83 -0
  218. package/external/aport-spec/oap/vc/tools/examples/vc-to-decision.js +77 -0
  219. package/external/aport-spec/oap/vc/tools/examples/vc-to-passport.js +94 -0
  220. package/external/aport-spec/oap/vc/tools/package.json +38 -0
  221. package/external/aport-spec/oap/vc/tools/pnpm-lock.yaml +472 -0
  222. package/external/aport-spec/oap/vc/tools/src/cli.ts +226 -0
  223. package/external/aport-spec/oap/vc/tools/src/crypto-utils.ts +427 -0
  224. package/external/aport-spec/oap/vc/tools/src/index.ts +653 -0
  225. package/external/aport-spec/oap/vc/tools/src/test.ts +148 -0
  226. package/external/aport-spec/oap/vc/tools/src/vp.ts +382 -0
  227. package/external/aport-spec/oap/vc/tools/test-simple.js +214 -0
  228. package/external/aport-spec/oap/vc/tools/tsconfig.json +19 -0
  229. package/external/aport-spec/oap/vc/vc-mapping.md +443 -0
  230. package/external/aport-spec/passport-schema.json +586 -0
  231. package/external/aport-spec/rate-limiting.md +136 -0
  232. package/external/aport-spec/transport-profile.md +325 -0
  233. package/external/aport-spec/webhook-spec.md +314 -0
  234. package/package.json +70 -0
  235. package/skills/aport-agent-guardrail/SKILL.md +314 -0
  236. package/src/evaluator.js +252 -0
  237. package/src/server/index.js +72 -0
@@ -0,0 +1,165 @@
1
+ from fastapi import FastAPI, HTTPException, Request, Response
2
+ from fastapi.responses import StreamingResponse
3
+ from pydantic import BaseModel
4
+ from aport.middleware import require_policy
5
+ import asyncio
6
+ from typing import List, Optional
7
+ import io
8
+
9
+ app = FastAPI(title="Data Export Service", version="1.0.0")
10
+
11
+ class ExportRequest(BaseModel):
12
+ format: str
13
+ include_pii: bool = False
14
+ filters: dict
15
+
16
+ class ExportStatus(BaseModel):
17
+ export_id: str
18
+ status: str
19
+ created_at: str
20
+ estimated_rows: int
21
+ actual_rows: Optional[int] = None
22
+ format: str
23
+ include_pii: bool
24
+
25
+ @app.post("/exports")
26
+ @require_policy("data.export.create.v1")
27
+ async def create_export(request: Request, export_data: ExportRequest):
28
+ try:
29
+ passport = request.state.policy_result.passport
30
+
31
+ # Check PII permission
32
+ if export_data.include_pii and not passport.limits.allow_pii:
33
+ raise HTTPException(
34
+ status_code=403,
35
+ detail={
36
+ "error": "PII export not allowed",
37
+ "agent_id": passport.agent_id,
38
+ "upgrade_instructions": "Request PII export capability from your administrator"
39
+ }
40
+ )
41
+
42
+ # Estimate row count (in real app, query your database)
43
+ estimated_rows = await estimate_export_rows(export_data.filters)
44
+
45
+ # Check row limit
46
+ if estimated_rows > passport.limits.max_export_rows:
47
+ raise HTTPException(
48
+ status_code=403,
49
+ detail={
50
+ "error": "Export exceeds row limit",
51
+ "requested": estimated_rows,
52
+ "limit": passport.limits.max_export_rows,
53
+ "upgrade_instructions": "Request smaller export or upgrade limits"
54
+ }
55
+ )
56
+
57
+ # Process export
58
+ export_id = await create_export_job({
59
+ "format": export_data.format,
60
+ "include_pii": export_data.include_pii,
61
+ "filters": export_data.filters,
62
+ "agent_id": passport.agent_id,
63
+ "agent_name": passport.name,
64
+ "estimated_rows": estimated_rows
65
+ })
66
+
67
+ # Log the export request
68
+ print(f"Export created: {export_id} ({estimated_rows} rows) by agent {passport.agent_id}")
69
+
70
+ return {
71
+ "success": True,
72
+ "export_id": export_id,
73
+ "format": export_data.format,
74
+ "estimated_rows": estimated_rows,
75
+ "status": "processing"
76
+ }
77
+
78
+ except Exception as e:
79
+ print(f"Export creation error: {e}")
80
+ raise HTTPException(status_code=500, detail="Internal server error")
81
+
82
+ @app.get("/exports/{export_id}")
83
+ @require_policy("data.export.create.v1")
84
+ async def get_export_status(request: Request, export_id: str):
85
+ try:
86
+ passport = request.state.policy_result.passport
87
+
88
+ export_info = await get_export_status(export_id, passport.agent_id)
89
+
90
+ if not export_info:
91
+ raise HTTPException(status_code=404, detail="Export not found")
92
+
93
+ return export_info
94
+
95
+ except Exception as e:
96
+ print(f"Export status error: {e}")
97
+ raise HTTPException(status_code=500, detail="Internal server error")
98
+
99
+ @app.get("/exports/{export_id}/download")
100
+ @require_policy("data.export.create.v1")
101
+ async def download_export(request: Request, export_id: str):
102
+ try:
103
+ passport = request.state.policy_result.passport
104
+
105
+ export_file = await get_export_file(export_id, passport.agent_id)
106
+
107
+ if not export_file:
108
+ raise HTTPException(status_code=404, detail="Export file not found")
109
+
110
+ if export_file["status"] != "completed":
111
+ raise HTTPException(status_code=400, detail="Export not ready for download")
112
+
113
+ # Create streaming response
114
+ def generate_file():
115
+ yield export_file["data"]
116
+
117
+ return StreamingResponse(
118
+ generate_file(),
119
+ media_type=export_file["content_type"],
120
+ headers={"Content-Disposition": f"attachment; filename={export_file['filename']}"}
121
+ )
122
+
123
+ except Exception as e:
124
+ print(f"Export download error: {e}")
125
+ raise HTTPException(status_code=500, detail="Internal server error")
126
+
127
+ # Mock functions
128
+ async def estimate_export_rows(filters: dict) -> int:
129
+ """Simulate database query to estimate rows"""
130
+ await asyncio.sleep(0.05)
131
+ return (hash(str(filters)) % 10000) + 1000
132
+
133
+ async def create_export_job(export_data: dict) -> str:
134
+ """Simulate export creation"""
135
+ await asyncio.sleep(0.1)
136
+ return f"exp_{asyncio.get_event_loop().time()}_{hash(str(export_data)) % 1000000}"
137
+
138
+ async def get_export_status(export_id: str, agent_id: str) -> Optional[ExportStatus]:
139
+ """Simulate export status lookup"""
140
+ await asyncio.sleep(0.05)
141
+ return ExportStatus(
142
+ export_id=export_id,
143
+ status="completed",
144
+ created_at="2024-01-16T00:00:00Z",
145
+ estimated_rows=5000,
146
+ actual_rows=4876,
147
+ format="csv",
148
+ include_pii=False
149
+ )
150
+
151
+ async def get_export_file(export_id: str, agent_id: str) -> Optional[dict]:
152
+ """Simulate file retrieval"""
153
+ await asyncio.sleep(0.05)
154
+ return {
155
+ "data": "name,email,created_at\nJohn Doe,john@example.com,2024-01-01",
156
+ "content_type": "text/csv",
157
+ "filename": f"export_{export_id}.csv",
158
+ "status": "completed"
159
+ }
160
+
161
+ if __name__ == "__main__":
162
+ import uvicorn
163
+ print("Data export service starting...")
164
+ print("Protected by APort data.export.create.v1 policy pack")
165
+ uvicorn.run(app, host="0.0.0.0", port=8000)
@@ -0,0 +1,133 @@
1
+ {
2
+ "id": "data.export.create.v1",
3
+ "name": "Data Export Protection Policy",
4
+ "description": "Pre-action governance for data export operations. Enforces row limits, PII handling requirements, and export capability validation.",
5
+ "version": "1.0.0",
6
+ "status": "active",
7
+ "requires_capabilities": ["data.export"],
8
+ "min_assurance": "L1",
9
+ "limits_required": ["max_export_rows", "allow_pii"],
10
+ "required_fields": ["export_type", "format", "filters"],
11
+ "optional_fields": ["include_pii", "date_range", "columns"],
12
+ "enforcement": {
13
+ "rows_lte": "limits.data.export.max_export_rows",
14
+ "pii_allowed": "limits.data.export.allow_pii"
15
+ },
16
+ "mcp": {
17
+ "require_allowlisted_if_present": true
18
+ },
19
+ "advice": [
20
+ "Cache /verify with ETag; 60s TTL",
21
+ "Subscribe to status webhooks for instant suspend",
22
+ "Implement data retention policies",
23
+ "Consider Verifiable Attestation for sensitive exports",
24
+ "Log all export attempts for audit compliance",
25
+ "Implement progressive disclosure for large datasets",
26
+ "Use secure delivery methods for sensitive data"
27
+ ],
28
+ "required_context": {
29
+ "$schema": "http://json-schema.org/draft-07/schema#",
30
+ "type": "object",
31
+ "required": ["export_type", "format", "filters"],
32
+ "properties": {
33
+ "export_type": {
34
+ "type": "string",
35
+ "enum": ["users", "orders", "transactions", "analytics"],
36
+ "description": "Type of data to export"
37
+ },
38
+ "format": {
39
+ "type": "string",
40
+ "enum": ["csv", "json", "xlsx", "parquet"],
41
+ "description": "Export format"
42
+ },
43
+ "filters": {
44
+ "type": "object",
45
+ "description": "Filter criteria for the export",
46
+ "properties": {
47
+ "date_from": { "type": "string", "format": "date" },
48
+ "date_to": { "type": "string", "format": "date" },
49
+ "status": { "type": "string" },
50
+ "category": { "type": "string" }
51
+ }
52
+ },
53
+ "include_pii": {
54
+ "type": "boolean",
55
+ "description": "Whether to include personally identifiable information"
56
+ },
57
+ "date_range": {
58
+ "type": "object",
59
+ "description": "Date range for the export",
60
+ "properties": {
61
+ "start": { "type": "string", "format": "date" },
62
+ "end": { "type": "string", "format": "date" }
63
+ }
64
+ },
65
+ "columns": {
66
+ "type": "array",
67
+ "items": { "type": "string" },
68
+ "description": "Specific columns to include"
69
+ },
70
+ "mcp_servers": {
71
+ "type": "array",
72
+ "items": { "type": "string" },
73
+ "description": "MCP servers being used in this request (e.g., [\"https://mcp.notion.com\"])"
74
+ },
75
+ "mcp_tools": {
76
+ "type": "array",
77
+ "items": { "type": "string" },
78
+ "description": "MCP tools being used in this request (e.g., [\"notion.pages.export\"])"
79
+ },
80
+ "mcp_server": {
81
+ "type": "string",
82
+ "description": "Single MCP server being used (backward compatibility - use mcp_servers array for multiple)"
83
+ },
84
+ "mcp_tool": {
85
+ "type": "string",
86
+ "description": "Single MCP tool being used (backward compatibility - use mcp_tools array for multiple)"
87
+ },
88
+ "mcp_session": {
89
+ "type": "string",
90
+ "description": "MCP session identifier for audit trail (optional)"
91
+ }
92
+ }
93
+ },
94
+ "evaluation_rules": [
95
+ {
96
+ "name": "passport_status_active",
97
+ "condition": "passport.status == 'active'",
98
+ "deny_code": "oap.passport_suspended",
99
+ "description": "Passport must be active"
100
+ },
101
+ {
102
+ "name": "export_capability",
103
+ "condition": "'data.export' in passport.capabilities",
104
+ "deny_code": "oap.unknown_capability",
105
+ "description": "Agent must have data.export capability"
106
+ },
107
+ {
108
+ "name": "row_limit_check",
109
+ "condition": "estimated_rows <= limits.max_export_rows",
110
+ "deny_code": "oap.limit_exceeded",
111
+ "description": "Export size must not exceed row limit"
112
+ },
113
+ {
114
+ "name": "pii_handling",
115
+ "condition": "NOT (include_pii AND NOT limits.allow_pii)",
116
+ "deny_code": "oap.pii_not_allowed",
117
+ "description": "PII export not allowed for this agent"
118
+ },
119
+ {
120
+ "name": "format_support",
121
+ "condition": "format in ['csv', 'json', 'xlsx', 'parquet']",
122
+ "deny_code": "oap.format_unsupported",
123
+ "description": "Export format must be supported"
124
+ }
125
+ ],
126
+ "cache": {
127
+ "default_ttl_seconds": 60,
128
+ "suspend_invalidate_seconds": 30
129
+ },
130
+ "deprecation": null,
131
+ "created_at": "2025-01-16T00:00:00Z",
132
+ "updated_at": "2025-01-30T00:00:00Z"
133
+ }
@@ -0,0 +1,134 @@
1
+ # Report Data Ingestion Policy Pack v1
2
+
3
+ Protect your data ingestion endpoints with APort's standardized policy pack. This pack ensures only verified agents with proper capabilities, assurance levels, and data quality controls can ingest report data with appropriate validation and monitoring.
4
+
5
+ ## What This Pack Protects
6
+
7
+ - **Route**: `/data/report/ingest/*` (POST)
8
+ - **Risk**: Data quality issues, stale data, unauthorized sources, compliance violations
9
+ - **Impact**: Poor reporting quality, regulatory violations, audit findings, data integrity issues
10
+
11
+ ## Requirements
12
+
13
+ | Requirement | Value | Description |
14
+ |-------------|-------|-------------|
15
+ | **Capability** | `data.report.ingest` | Agent must have data ingestion capability |
16
+ | **Assurance** | `L2` or higher | Standard verification minimum |
17
+ | **Limits** | `approved_sources.{report_type}[]` | Approved data sources per report type |
18
+ | **Limits** | `max_data_age_seconds.{report_type}` | Maximum data age per report type |
19
+ | **Limits** | `max_data_size_mb.{report_type}` | Maximum data size per report type |
20
+ | **Limits** | `max_ingest_frequency_per_hour.{report_type}` | Maximum ingestion frequency |
21
+ | **Limits** | `data_quality_threshold.{report_type}` | Minimum data quality score |
22
+ | **Limits** | `required_validation_checks.{report_type}[]` | Required validation checks |
23
+ | **Regions** | Must match | Agent must be authorized in caller's region |
24
+ | **Idempotency** | Required | Prevents duplicate ingestion |
25
+
26
+ ## Implementation
27
+
28
+ ### Express.js
29
+
30
+ ```javascript
31
+ const { requirePolicy } = require('@aporthq/middleware-express');
32
+
33
+ // Option 1: Explicit agent ID (preferred)
34
+ app.post('/data/report/ingest',
35
+ requirePolicy('data.report.ingest.v1', 'ap_a2d10232c6534523812423eec8a1425c45678'),
36
+ async (req, res) => {
37
+ // Your data ingestion logic here
38
+ // req.policyResult contains the verified passport
39
+ const { report_type, data_source_id, data_timestamp } = req.body;
40
+ const passport = req.policyResult.passport;
41
+
42
+ // Process data ingestion...
43
+ res.json({ success: true, ingest_id: generateId() });
44
+ }
45
+ );
46
+ ```
47
+
48
+ **Client Request Example:**
49
+ ```javascript
50
+ fetch('/data/report/ingest', {
51
+ method: 'POST',
52
+ headers: {
53
+ 'Content-Type': 'application/json',
54
+ 'X-Agent-Passport-Id': 'ap_a2d10232c6534523812423eec8a1425c45678'
55
+ },
56
+ body: JSON.stringify({
57
+ report_type: "ESG",
58
+ data_source_id: "api.climate-data.com",
59
+ data_timestamp: "2025-01-30T10:00:00Z",
60
+ metric_type: "carbon_emissions",
61
+ data_size_mb: 5.2,
62
+ validation_checks: ["schema_validation", "range_check"],
63
+ data_quality_score: 0.95,
64
+ idempotency_key: "ingest-esg-123"
65
+ })
66
+ });
67
+ ```
68
+
69
+ ## Best Practices
70
+
71
+ 1. **Cache Verification**: Cache `/verify` responses with ETag for 300 seconds
72
+ 2. **Webhook Integration**: Subscribe to `status.changed` webhooks for instant suspension
73
+ 3. **Verifiable Attestation**: Log all data ingestion attempts for compliance
74
+ 4. **Data Quality Scoring**: Implement data quality scoring before ingestion
75
+ 5. **Data Lineage Tracking**: Use data lineage tracking for audit compliance
76
+ 6. **Progressive Validation**: Implement progressive data validation checks
77
+ 7. **Anomaly Monitoring**: Monitor for data anomalies and unusual patterns
78
+ 8. **Data Encryption**: Use data encryption for sensitive report data
79
+ 9. **Data Retention**: Implement data retention policies based on report type
80
+ 10. **Source Reputation**: Maintain data source reputation scoring
81
+ 11. **Idempotency**: Use idempotency keys to prevent duplicate ingestion
82
+ 12. **Freshness Monitoring**: Implement data freshness monitoring and alerts
83
+
84
+ ## Support
85
+
86
+ - [Documentation](https://aport.io/docs/policies/data.report.ingest.v1)
87
+ - [Community](https://github.com/aporthq/community)
88
+ - [Support](https://aport.io/support)
89
+
90
+ ---
91
+ **Last Updated**: 2025-01-30 00:00:00 UTC
92
+
93
+
94
+ ## Required Context
95
+
96
+ This policy requires the following context (JSON Schema):
97
+
98
+ ```json
99
+ {
100
+ "$schema": "http://json-schema.org/draft-07/schema#",
101
+ "type": "object",
102
+ "required": [
103
+ "report_type",
104
+ "data_source_id",
105
+ "data_timestamp"
106
+ ],
107
+ "properties": {
108
+ "report_type": {
109
+ "type": "string",
110
+ "description": "The type of report being generated (e.g., 'ESG', 'QuarterlyFinancials')."
111
+ },
112
+ "data_source_id": {
113
+ "type": "string",
114
+ "description": "A unique identifier for the source of the data being ingested (e.g., 'api.climate-data.com', 'internal-hr-db')."
115
+ },
116
+ "data_timestamp": {
117
+ "type": "string",
118
+ "format": "date-time",
119
+ "description": "The ISO 8601 timestamp of when the data was generated."
120
+ },
121
+ "metric_type": {
122
+ "type": "string",
123
+ "description": "The specific metric this data point relates to (e.g., 'carbon_emissions', 'employee_diversity')."
124
+ }
125
+ }
126
+ }
127
+ ```
128
+
129
+ You can also fetch this live via the discovery endpoint:
130
+
131
+ ```bash
132
+ curl -s "https://aport.io/api/policies/data.report.ingest.v1?format=schema"
133
+ ```
134
+
@@ -0,0 +1,105 @@
1
+ const express = require("express");
2
+ const { requirePolicy } = require("@aporthq/middleware-express");
3
+
4
+ const app = express();
5
+ app.use(express.json());
6
+
7
+ // Apply data.report.ingest policy to all data ingestion routes
8
+ app.post(
9
+ "/data/report/ingest",
10
+ requirePolicy("data.report.ingest.v1"),
11
+ async (req, res) => {
12
+ try {
13
+ const {
14
+ report_type,
15
+ data_source_id,
16
+ data_timestamp,
17
+ metric_type,
18
+ data_size_mb,
19
+ validation_checks,
20
+ data_quality_score,
21
+ ingest_reason,
22
+ idempotency_key,
23
+ } = req.body;
24
+
25
+ const passport = req.policyResult.passport;
26
+
27
+ // Additional business logic validation
28
+ if (!report_type || !data_source_id || !data_timestamp) {
29
+ return res.status(400).json({ error: "Missing required fields" });
30
+ }
31
+
32
+ // Process data ingestion using your data system
33
+ const ingest_id = await processDataIngestion({
34
+ report_type,
35
+ data_source_id,
36
+ data_timestamp,
37
+ metric_type,
38
+ data_size_mb,
39
+ validation_checks,
40
+ data_quality_score,
41
+ ingest_reason,
42
+ idempotency_key,
43
+ agent_id: passport.passport_id,
44
+ agent_name: passport.metadata?.template_name || "Unknown Agent",
45
+ });
46
+
47
+ // Log the ingestion
48
+ console.log(
49
+ `Data ingestion processed: ${ingest_id} for ${report_type} report by agent ${passport.passport_id}`
50
+ );
51
+
52
+ res.json({
53
+ success: true,
54
+ ingest_id,
55
+ report_type,
56
+ data_source_id,
57
+ data_timestamp,
58
+ status: "processed",
59
+ decision_id: req.policyResult.decision_id,
60
+ });
61
+ } catch (error) {
62
+ console.error("Data ingestion processing error:", error);
63
+ res.status(500).json({ error: "Internal server error" });
64
+ }
65
+ }
66
+ );
67
+
68
+ // Mock data ingestion processing function
69
+ async function processDataIngestion({
70
+ report_type,
71
+ data_source_id,
72
+ data_timestamp,
73
+ metric_type,
74
+ data_size_mb,
75
+ validation_checks,
76
+ data_quality_score,
77
+ ingest_reason,
78
+ idempotency_key,
79
+ agent_id,
80
+ }) {
81
+ // Simulate data system call
82
+ await new Promise((resolve) => setTimeout(resolve, 150));
83
+
84
+ // Log ingestion details for audit
85
+ console.log(`Processing data ingestion:`, {
86
+ report_type,
87
+ data_source_id,
88
+ data_timestamp,
89
+ metric_type,
90
+ data_size_mb,
91
+ validation_checks,
92
+ data_quality_score,
93
+ ingest_reason,
94
+ idempotency_key,
95
+ agent_id,
96
+ });
97
+
98
+ return `ingest_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
99
+ }
100
+
101
+ const PORT = process.env.PORT || 3000;
102
+ app.listen(PORT, () => {
103
+ console.log(`Data ingestion service running on port ${PORT}`);
104
+ console.log("Protected by APort data.report.ingest.v1 policy pack");
105
+ });
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Minimal Example: data.report.ingest.v1 Policy
3
+ *
4
+ * This is a quick-start example showing the basic usage of the data.report.ingest.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 data ingestion endpoint with policy protection
15
+ app.post(
16
+ "/data/ingest",
17
+ requirePolicy("data.report.ingest.v1"),
18
+ async (req, res) => {
19
+ try {
20
+ const { report_type, data_source_id, data_timestamp } = req.body;
21
+ const passport = req.policyResult.passport;
22
+
23
+ // Process the data ingestion (your business logic here)
24
+ const ingest_id = `ingest_${Date.now()}`;
25
+
26
+ console.log(
27
+ `Data ingestion processed: ${ingest_id} for ${report_type} report`
28
+ );
29
+
30
+ res.json({
31
+ success: true,
32
+ ingest_id,
33
+ report_type,
34
+ data_source_id,
35
+ data_timestamp,
36
+ decision_id: req.policyResult.decision_id,
37
+ });
38
+ } catch (error) {
39
+ console.error("Data ingestion error:", error);
40
+ res.status(500).json({ error: "Internal server error" });
41
+ }
42
+ }
43
+ );
44
+
45
+ // Example client request
46
+ const exampleRequest = {
47
+ report_type: "ESG",
48
+ data_source_id: "api.climate-data.com",
49
+ data_timestamp: "2025-01-30T10:00:00Z",
50
+ metric_type: "carbon_emissions",
51
+ data_size_mb: 5.2,
52
+ validation_checks: ["schema_validation", "range_check"],
53
+ data_quality_score: 0.95,
54
+ idempotency_key: "ingest-esg-123",
55
+ };
56
+
57
+ console.log("Example request:", JSON.stringify(exampleRequest, null, 2));
58
+
59
+ const PORT = process.env.PORT || 3000;
60
+ app.listen(PORT, () => {
61
+ console.log(`Minimal data ingestion service running on port ${PORT}`);
62
+ console.log("Protected by APort data.report.ingest.v1 policy");
63
+ console.log(
64
+ `Try: curl -X POST http://localhost:${PORT}/data/ingest -H "Content-Type: application/json" -d '${JSON.stringify(
65
+ exampleRequest
66
+ )}'`
67
+ );
68
+ });