@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,232 @@
1
+ #!/bin/bash
2
+ # constants.sh - Configuration constants and defaults for APort guardrails
3
+ # All magic numbers and hardcoded values should be defined here
4
+
5
+ # ============================================================================
6
+ # TIMEOUTS (seconds)
7
+ # ============================================================================
8
+
9
+ # Default timeout for subprocess guardrail script execution
10
+ readonly DEFAULT_SUBPROCESS_TIMEOUT="${APORT_SUBPROCESS_TIMEOUT:-30}"
11
+
12
+ # Default timeout for API requests
13
+ readonly DEFAULT_API_TIMEOUT="${APORT_API_TIMEOUT:-15}"
14
+
15
+ # Timeout for loading policy packs
16
+ readonly DEFAULT_POLICY_LOAD_TIMEOUT="${APORT_POLICY_LOAD_TIMEOUT:-5}"
17
+
18
+ # ============================================================================
19
+ # SIZE LIMITS
20
+ # ============================================================================
21
+
22
+ # Maximum tool name length (characters)
23
+ readonly MAX_TOOL_NAME_LENGTH="${APORT_MAX_TOOL_NAME_LENGTH:-128}"
24
+
25
+ # Maximum agent ID length (characters)
26
+ readonly MAX_AGENT_ID_LENGTH="${APORT_MAX_AGENT_ID_LENGTH:-128}"
27
+
28
+ # Maximum policy pack ID length (characters)
29
+ readonly MAX_POLICY_PACK_ID_LENGTH="${APORT_MAX_POLICY_PACK_ID_LENGTH:-128}"
30
+
31
+ # Maximum context JSON size (bytes) - default 100KB
32
+ readonly MAX_CONTEXT_SIZE_BYTES="${APORT_MAX_CONTEXT_SIZE:-102400}"
33
+
34
+ # Maximum passport file size (bytes) - default 1MB
35
+ readonly MAX_PASSPORT_SIZE_BYTES="${APORT_MAX_PASSPORT_SIZE:-1048576}"
36
+
37
+ # Maximum policy pack file size (bytes) - default 10MB
38
+ readonly MAX_POLICY_PACK_SIZE_BYTES="${APORT_MAX_POLICY_PACK_SIZE:-10485760}"
39
+
40
+ # Maximum log message length (characters)
41
+ readonly MAX_LOG_MESSAGE_LENGTH="${APORT_MAX_LOG_MESSAGE_LENGTH:-200}"
42
+
43
+ # ============================================================================
44
+ # RATE LIMITING
45
+ # ============================================================================
46
+
47
+ # Default requests per minute
48
+ readonly DEFAULT_RATE_LIMIT_RPM="${APORT_RATE_LIMIT_REQUESTS_PER_MINUTE:-60}"
49
+
50
+ # Default burst allowance
51
+ readonly DEFAULT_RATE_LIMIT_BURST="${APORT_RATE_LIMIT_BURST:-10}"
52
+
53
+ # ============================================================================
54
+ # RETRY LOGIC
55
+ # ============================================================================
56
+
57
+ # Maximum API retry attempts
58
+ readonly MAX_API_RETRIES="${APORT_MAX_API_RETRIES:-3}"
59
+
60
+ # API retry backoff (milliseconds)
61
+ readonly API_RETRY_BACKOFF_MS="${APORT_API_RETRY_BACKOFF_MS:-1000}"
62
+
63
+ # ============================================================================
64
+ # CACHING
65
+ # ============================================================================
66
+
67
+ # Passport file cache TTL (seconds)
68
+ readonly PASSPORT_CACHE_TTL_SECONDS="${APORT_PASSPORT_CACHE_TTL:-60}"
69
+
70
+ # Policy pack cache TTL (seconds)
71
+ readonly POLICY_CACHE_TTL_SECONDS="${APORT_POLICY_CACHE_TTL:-60}"
72
+
73
+ # Config file cache TTL (seconds)
74
+ readonly CONFIG_CACHE_TTL_SECONDS="${APORT_CONFIG_CACHE_TTL:-300}"
75
+
76
+ # ============================================================================
77
+ # API CONFIGURATION
78
+ # ============================================================================
79
+
80
+ # Default API URL
81
+ readonly DEFAULT_API_URL="${APORT_API_URL:-https://api.aport.io}"
82
+
83
+ # ============================================================================
84
+ # PATHS
85
+ # ============================================================================
86
+
87
+ # Allowed base directories for passport files (for validation)
88
+ readonly ALLOWED_PASSPORT_BASE_DIRS=(
89
+ "$HOME/.openclaw"
90
+ "$HOME/.aport"
91
+ "/tmp/aport-"
92
+ )
93
+
94
+ # ============================================================================
95
+ # VALIDATION PATTERNS
96
+ # ============================================================================
97
+
98
+ # Tool name validation pattern (grep -E compatible)
99
+ readonly TOOL_NAME_PATTERN='^[a-zA-Z0-9._-]+$'
100
+
101
+ # Agent ID validation pattern (grep -E compatible)
102
+ readonly AGENT_ID_PATTERN='^ap_[a-zA-Z0-9_]+$'
103
+
104
+ # Policy pack ID validation pattern (grep -E compatible)
105
+ readonly POLICY_PACK_ID_PATTERN='^[a-zA-Z0-9._-]+$'
106
+
107
+ # ============================================================================
108
+ # LOGGING
109
+ # ============================================================================
110
+
111
+ # Log level (DEBUG, INFO, WARN, ERROR)
112
+ readonly LOG_LEVEL="${APORT_LOG_LEVEL:-INFO}"
113
+
114
+ # Log format (text, json)
115
+ readonly LOG_FORMAT="${APORT_LOG_FORMAT:-text}"
116
+
117
+ # ============================================================================
118
+ # SECURITY
119
+ # ============================================================================
120
+
121
+ # Sensitive field patterns for log redaction (space-separated)
122
+ readonly SENSITIVE_FIELD_PATTERNS="password passwd pwd secret token key api bearer"
123
+
124
+ # API key prefix patterns (space-separated)
125
+ readonly API_KEY_PREFIXES="aprt_ sk_ pk_"
126
+
127
+ # ============================================================================
128
+ # PERFORMANCE
129
+ # ============================================================================
130
+
131
+ # Slow operation threshold (milliseconds)
132
+ readonly SLOW_OPERATION_THRESHOLD_MS="${APORT_SLOW_OPERATION_THRESHOLD_MS:-200}"
133
+
134
+ # ============================================================================
135
+ # FEATURE FLAGS
136
+ # ============================================================================
137
+
138
+ # Enable policy caching (1=enabled, 0=disabled)
139
+ readonly ENABLE_POLICY_CACHING="${APORT_ENABLE_POLICY_CACHING:-1}"
140
+
141
+ # Enable passport caching (1=enabled, 0=disabled)
142
+ readonly ENABLE_PASSPORT_CACHING="${APORT_ENABLE_PASSPORT_CACHING:-1}"
143
+
144
+ # ============================================================================
145
+ # VERSION
146
+ # ============================================================================
147
+
148
+ # APort specification version
149
+ readonly OAP_SPEC_VERSION="oap/1.0"
150
+
151
+ # Client library version
152
+ readonly CLIENT_VERSION="1.0.8"
153
+
154
+ # ============================================================================
155
+ # MISC
156
+ # ============================================================================
157
+
158
+ # Audit log file name
159
+ readonly AUDIT_LOG_FILENAME="audit.log"
160
+
161
+ # Chain state file name
162
+ readonly CHAIN_STATE_FILENAME="chain-state.json"
163
+
164
+ # ============================================================================
165
+ # HELPER FUNCTIONS
166
+ # ============================================================================
167
+
168
+ # Get numeric constant with validation
169
+ # Usage: get_numeric_constant "var_name" "default_value" "min" "max"
170
+ get_numeric_constant() {
171
+ local var_name="$1"
172
+ local default_value="$2"
173
+ local min_value="${3:-1}"
174
+ local max_value="${4:-999999}"
175
+
176
+ local value="${!var_name:-$default_value}"
177
+
178
+ # Validate it's a number
179
+ if ! [[ "$value" =~ ^[0-9]+$ ]]; then
180
+ echo "$default_value"
181
+ return 1
182
+ fi
183
+
184
+ # Validate range
185
+ if [ "$value" -lt "$min_value" ] || [ "$value" -gt "$max_value" ]; then
186
+ echo "$default_value"
187
+ return 1
188
+ fi
189
+
190
+ echo "$value"
191
+ return 0
192
+ }
193
+
194
+ # Check if feature is enabled
195
+ # Usage: if is_feature_enabled "ENABLE_POLICY_CACHING"; then ...
196
+ is_feature_enabled() {
197
+ local feature_var="$1"
198
+ local value="${!feature_var:-0}"
199
+
200
+ case "$value" in
201
+ 1 | true | TRUE | yes | YES | on | ON)
202
+ return 0
203
+ ;;
204
+ *)
205
+ return 1
206
+ ;;
207
+ esac
208
+ }
209
+
210
+ # Get log level priority (for filtering)
211
+ # Returns: 0=DEBUG, 1=INFO, 2=WARN, 3=ERROR
212
+ get_log_level_priority() {
213
+ local level="${1:-INFO}"
214
+
215
+ case "$level" in
216
+ DEBUG) echo 0 ;;
217
+ INFO) echo 1 ;;
218
+ WARN) echo 2 ;;
219
+ ERROR) echo 3 ;;
220
+ *) echo 1 ;; # Default to INFO
221
+ esac
222
+ }
223
+
224
+ # Check if should log at level
225
+ # Usage: if should_log "DEBUG"; then ...
226
+ should_log() {
227
+ local message_level="$1"
228
+ local current_priority=$(get_log_level_priority "$LOG_LEVEL")
229
+ local message_priority=$(get_log_level_priority "$message_level")
230
+
231
+ [ "$message_priority" -ge "$current_priority" ]
232
+ }
@@ -0,0 +1,65 @@
1
+ #!/usr/bin/env bash
2
+ # Framework detection from project directory (cwd or first arg).
3
+ # Used by bin/agent-guardrails to skip prompt when project is detectable.
4
+ # detect_framework: echoes first detected framework or empty.
5
+ # detect_frameworks_list: echoes all detected frameworks (space-separated, unique)
6
+ # so the dispatcher can show "Multiple frameworks detected: X, Y. Choose one: ...".
7
+
8
+ # shellcheck source=./common.sh
9
+ source "$(dirname "${BASH_SOURCE[0]:-.}")/common.sh"
10
+
11
+ # Collect all detected framework names (unique, order: pyproject -> package.json -> requirements)
12
+ detect_frameworks_list() {
13
+ local dir="${1:-.}"
14
+ local list=()
15
+
16
+ [[ ! -d "$dir" ]] && echo "" && return 0
17
+
18
+ # Python: pyproject.toml
19
+ if [[ -f "$dir/pyproject.toml" ]]; then
20
+ grep -qi 'langchain\|langgraph' "$dir/pyproject.toml" 2> /dev/null && list+=(langchain)
21
+ grep -qi 'crewai' "$dir/pyproject.toml" 2> /dev/null && list+=(crewai)
22
+ fi
23
+
24
+ # Node: package.json
25
+ if [[ -f "$dir/package.json" ]]; then
26
+ grep -qi 'openclaw\|open-claw\|agent-guardrails' "$dir/package.json" 2> /dev/null && list+=(openclaw)
27
+ fi
28
+
29
+ # requirements.txt fallback
30
+ if [[ -f "$dir/requirements.txt" ]]; then
31
+ grep -qi 'langchain' "$dir/requirements.txt" 2> /dev/null && list+=(langchain)
32
+ grep -qi 'crewai' "$dir/requirements.txt" 2> /dev/null && list+=(crewai)
33
+ fi
34
+
35
+ # Dedupe preserving order (first occurrence wins). Safe for set -u when list is empty.
36
+ local seen=() out=()
37
+ if [[ ${#list[@]} -gt 0 ]]; then
38
+ for fw in "${list[@]}"; do
39
+ if [[ " ${seen[*]:-} " != *" $fw "* ]]; then
40
+ seen+=("$fw")
41
+ out+=("$fw")
42
+ fi
43
+ done
44
+ fi
45
+ if [[ ${#out[@]} -gt 0 ]]; then
46
+ echo "${out[*]}"
47
+ else
48
+ echo ""
49
+ fi
50
+ return 0
51
+ }
52
+
53
+ # Return first detected framework (for single-detection behavior); empty if none.
54
+ detect_framework() {
55
+ local list
56
+ list="$(detect_frameworks_list "${1:-.}")"
57
+ if [[ -n "$list" ]]; then
58
+ echo "${list%% *}"
59
+ else
60
+ echo ""
61
+ fi
62
+ return 0
63
+ }
64
+
65
+ export -f detect_framework detect_frameworks_list
@@ -0,0 +1,269 @@
1
+ #!/bin/bash
2
+ # error.sh - Standardized error handling for APort guardrails
3
+ # Provides consistent error codes, messages, and response formatting
4
+
5
+ # Error codes (see docs/development/ERROR_CODES.md)
6
+ readonly ERROR_INVALID_TOOL_NAME="oap.invalid_input.tool_name"
7
+ readonly ERROR_CONTEXT_TOO_LARGE="oap.invalid_input.context_too_large"
8
+ readonly ERROR_INVALID_AGENT_ID="oap.invalid_input.agent_id"
9
+ readonly ERROR_PATH_NOT_ALLOWED="oap.path.not_allowed"
10
+ readonly ERROR_PATH_TRAVERSAL="oap.path.traversal_attempt"
11
+ readonly ERROR_PATH_INVALID_CHARS="oap.path.invalid_characters"
12
+ readonly ERROR_PASSPORT_NOT_FOUND="oap.passport.not_found"
13
+ readonly ERROR_PASSPORT_INVALID="oap.passport.invalid_format"
14
+ readonly ERROR_PASSPORT_EXPIRED="oap.passport.expired"
15
+ readonly ERROR_PASSPORT_REVOKED="oap.passport.revoked"
16
+ readonly ERROR_PASSPORT_MISSING_CAP="oap.passport.missing_capability"
17
+ readonly ERROR_POLICY_NOT_FOUND="oap.policy.not_found"
18
+ readonly ERROR_POLICY_INVALID="oap.policy.invalid_format"
19
+ readonly ERROR_POLICY_EVAL_FAILED="oap.policy.evaluation_failed"
20
+ readonly ERROR_POLICY_TIMEOUT="oap.policy.evaluation_timeout"
21
+ readonly ERROR_POLICY_DENIED="oap.policy.denied"
22
+ readonly ERROR_API_CONNECTION="oap.api.connection_failed"
23
+ readonly ERROR_API_AUTH="oap.api.authentication_failed"
24
+ readonly ERROR_API_RATE_LIMIT="oap.api.rate_limit_exceeded"
25
+ readonly ERROR_API_TIMEOUT="oap.api.timeout"
26
+ readonly ERROR_API_ERROR="oap.api.error"
27
+ readonly ERROR_CONFIG_NOT_FOUND="oap.config.not_found"
28
+ readonly ERROR_CONFIG_INVALID="oap.config.invalid_format"
29
+ readonly ERROR_EVALUATOR_ERROR="oap.system.evaluator_error"
30
+ readonly ERROR_COMMAND_INJECTION="oap.system.command_injection_detected"
31
+ readonly ERROR_DEPENDENCY_MISSING="oap.system.dependency_missing"
32
+ readonly ERROR_MISCONFIGURED="oap.misconfigured"
33
+
34
+ # Generate unique request ID
35
+ generate_request_id() {
36
+ local timestamp=$(date +%s%3N 2> /dev/null || date +%s)
37
+ local random=$(openssl rand -hex 3 2> /dev/null || echo "$RANDOM")
38
+ echo "req_${timestamp}_${random}"
39
+ }
40
+
41
+ # Generate ISO 8601 timestamp
42
+ generate_timestamp() {
43
+ date -u +"%Y-%m-%dT%H:%M:%S.%3NZ" 2> /dev/null || date -u +"%Y-%m-%dT%H:%M:%SZ"
44
+ }
45
+
46
+ # Format error as JSON decision
47
+ # Usage: format_error_json "error_code" "message" ["details_json"] ["resolution"]
48
+ format_error_json() {
49
+ local code="$1"
50
+ local message="$2"
51
+ local details="${3:-}"
52
+ local resolution="${4:-}"
53
+ local request_id="${5:-$(generate_request_id)}"
54
+ local timestamp=$(generate_timestamp)
55
+
56
+ local reason_json
57
+ reason_json=$(
58
+ cat << EOF
59
+ {
60
+ "code": "$code",
61
+ "message": "$message"
62
+ }
63
+ EOF
64
+ )
65
+
66
+ # Add details if provided
67
+ if [ -n "$details" ]; then
68
+ reason_json=$(echo "$reason_json" | jq -c --argjson d "$details" '. + {details: $d}')
69
+ fi
70
+
71
+ # Add resolution if provided
72
+ if [ -n "$resolution" ]; then
73
+ reason_json=$(echo "$reason_json" | jq -c --arg r "$resolution" '. + {resolution: $r}')
74
+ fi
75
+
76
+ # Create full response
77
+ cat << EOF
78
+ {
79
+ "allow": false,
80
+ "reasons": [$reason_json],
81
+ "request_id": "$request_id",
82
+ "timestamp": "$timestamp"
83
+ }
84
+ EOF
85
+ }
86
+
87
+ # Format error as plain text
88
+ # Usage: format_error_text "error_code" "message" ["details"] ["resolution"]
89
+ format_error_text() {
90
+ local code="$1"
91
+ local message="$2"
92
+ local details="${3:-}"
93
+ local resolution="${4:-}"
94
+ local request_id="${5:-$(generate_request_id)}"
95
+
96
+ echo "ERROR: $code"
97
+ echo "$message"
98
+
99
+ if [ -n "$details" ]; then
100
+ echo "Details: $details"
101
+ fi
102
+
103
+ if [ -n "$resolution" ]; then
104
+ echo ""
105
+ echo "Resolution:"
106
+ echo "$resolution"
107
+ fi
108
+
109
+ echo ""
110
+ echo "Request ID: $request_id"
111
+ }
112
+
113
+ # Write error to stderr in text format
114
+ # Usage: error_log "error_code" "message" ["details"]
115
+ error_log() {
116
+ local code="$1"
117
+ local message="$2"
118
+ local details="${3:-}"
119
+
120
+ format_error_text "$code" "$message" "$details" >&2
121
+ }
122
+
123
+ # Write deny decision to decision file
124
+ # Usage: write_deny_decision "error_code" "message" ["details"] ["resolution"]
125
+ write_deny_decision() {
126
+ local code="$1"
127
+ local message="$2"
128
+ local details="${3:-}"
129
+ local resolution="${4:-}"
130
+
131
+ if [ -z "$DECISION_FILE" ]; then
132
+ error_log "oap.system.evaluator_error" "DECISION_FILE not set"
133
+ return 1
134
+ fi
135
+
136
+ format_error_json "$code" "$message" "$details" "$resolution" > "$DECISION_FILE" 2> /dev/null || true
137
+ }
138
+
139
+ # Write allow decision to decision file
140
+ # Usage: write_allow_decision "message" ["policy_id"]
141
+ write_allow_decision() {
142
+ local message="${1:-All policy checks passed}"
143
+ local policy_id="${2:-}"
144
+ local request_id=$(generate_request_id)
145
+ local timestamp=$(generate_timestamp)
146
+
147
+ if [ -z "$DECISION_FILE" ]; then
148
+ error_log "oap.system.evaluator_error" "DECISION_FILE not set"
149
+ return 1
150
+ fi
151
+
152
+ local decision_json
153
+ decision_json=$(
154
+ cat << EOF
155
+ {
156
+ "allow": true,
157
+ "reasons": [{"message": "$message"}],
158
+ "request_id": "$request_id",
159
+ "timestamp": "$timestamp"
160
+ }
161
+ EOF
162
+ )
163
+
164
+ # Add policy_id if provided
165
+ if [ -n "$policy_id" ]; then
166
+ decision_json=$(echo "$decision_json" | jq -c --arg p "$policy_id" '. + {policy_id: $p}')
167
+ fi
168
+
169
+ echo "$decision_json" > "$DECISION_FILE" 2> /dev/null || true
170
+ }
171
+
172
+ # Get standard resolution message for error code
173
+ # Usage: resolution=$(get_resolution "error_code")
174
+ get_resolution() {
175
+ local code="$1"
176
+
177
+ case "$code" in
178
+ "$ERROR_INVALID_TOOL_NAME")
179
+ echo "Use only alphanumeric characters, dots, underscores, and hyphens in tool names. Keep tool names under 128 characters."
180
+ ;;
181
+ "$ERROR_CONTEXT_TOO_LARGE")
182
+ echo "Reduce context data size by removing unnecessary fields or summarizing large data. Default limit: 100KB."
183
+ ;;
184
+ "$ERROR_PATH_NOT_ALLOWED")
185
+ echo "Use standard APort directories: ~/.openclaw/, ~/.aport/, or /tmp/aport-*. Contact administrator to add custom allowed directories."
186
+ ;;
187
+ "$ERROR_PATH_TRAVERSAL")
188
+ echo "Use absolute paths without parent directory references (../ or /..). This is a security feature to prevent path traversal attacks."
189
+ ;;
190
+ "$ERROR_PASSPORT_NOT_FOUND")
191
+ echo "Create a passport by running: npx @aporthq/agent-guardrails openclaw. See: https://github.com/aporthq/agent-guardrails#passport-setup"
192
+ ;;
193
+ "$ERROR_PASSPORT_MISSING_CAP")
194
+ echo "Request capability be added to passport or generate new passport with required capabilities."
195
+ ;;
196
+ "$ERROR_POLICY_NOT_FOUND")
197
+ echo "Verify policy pack ID is correct and update policy submodule: git submodule update --init --recursive"
198
+ ;;
199
+ "$ERROR_API_CONNECTION")
200
+ echo "Check internet connectivity, verify API URL (APORT_API_URL), and check firewall allows outbound HTTPS."
201
+ ;;
202
+ "$ERROR_API_AUTH")
203
+ echo "Verify API key is set (APORT_API_KEY) and generate new API key if needed from APort dashboard."
204
+ ;;
205
+ "$ERROR_API_RATE_LIMIT")
206
+ echo "Wait for rate limit to reset, reduce request frequency, or use local evaluation mode instead of API mode."
207
+ ;;
208
+ "$ERROR_MISCONFIGURED")
209
+ echo "Run setup: npx @aporthq/agent-guardrails <framework>. Check passport exists at ~/.openclaw/passport.json"
210
+ ;;
211
+ *)
212
+ echo ""
213
+ ;;
214
+ esac
215
+ }
216
+
217
+ # Helper: Write error and exit
218
+ # Usage: die "error_code" "message" ["details"]
219
+ die() {
220
+ local code="$1"
221
+ local message="$2"
222
+ local details="${3:-}"
223
+ local resolution=$(get_resolution "$code")
224
+
225
+ write_deny_decision "$code" "$message" "$details" "$resolution"
226
+ error_log "$code" "$message" "$details"
227
+ exit 1
228
+ }
229
+
230
+ # Validate required command exists
231
+ # Usage: require_command "jq"
232
+ require_command() {
233
+ local cmd="$1"
234
+ local install_hint="${2:-}"
235
+
236
+ if ! command -v "$cmd" > /dev/null 2>&1; then
237
+ local details="{\"command\":\"$cmd\"}"
238
+ local message="Required command not found: $cmd"
239
+
240
+ if [ -n "$install_hint" ]; then
241
+ message="$message. Install with: $install_hint"
242
+ fi
243
+
244
+ die "$ERROR_DEPENDENCY_MISSING" "$message" "$details"
245
+ fi
246
+ }
247
+
248
+ # Check if decision file is writable
249
+ # Usage: check_decision_file_writable
250
+ check_decision_file_writable() {
251
+ if [ -z "$DECISION_FILE" ]; then
252
+ error_log "oap.system.evaluator_error" "DECISION_FILE not set"
253
+ return 1
254
+ fi
255
+
256
+ local decision_dir=$(dirname "$DECISION_FILE")
257
+
258
+ if [ ! -d "$decision_dir" ]; then
259
+ error_log "oap.system.insufficient_permissions" "Decision directory does not exist: $decision_dir"
260
+ return 1
261
+ fi
262
+
263
+ if [ ! -w "$decision_dir" ]; then
264
+ error_log "oap.system.insufficient_permissions" "Cannot write to decision directory: $decision_dir"
265
+ return 1
266
+ fi
267
+
268
+ return 0
269
+ }
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env bash
2
+ # Passport creation wizard logic (shared across frameworks)
3
+ # OAP v1.0 format; used by bin/aport-create-passport.sh and framework installers.
4
+
5
+ # shellcheck source=./common.sh
6
+ source "$(dirname "${BASH_SOURCE[0]:-.}")/common.sh"
7
+
8
+ # Placeholder: full wizard logic can be refactored from aport-create-passport.sh
9
+ run_passport_wizard() {
10
+ log_info "Running passport wizard (shared)..."
11
+ # Delegate to existing script if present
12
+ if [[ -x "$ROOT_DIR/bin/aport-create-passport.sh" ]]; then
13
+ "$ROOT_DIR/bin/aport-create-passport.sh" "$@"
14
+ else
15
+ log_warn "bin/aport-create-passport.sh not found; wizard stub only."
16
+ fi
17
+ }
18
+
19
+ export -f run_passport_wizard
@@ -0,0 +1 @@
1
+ # Config templates per framework (e.g. aport-config.yaml, config.json)
@@ -0,0 +1,6 @@
1
+ # APort agent guardrails config (shared template for langchain, crewai, n8n)
2
+ # mode: api | local
3
+ # For API: set agent_id (hosted passport). For local: set passport_path.
4
+ mode: local
5
+ # agent_id: ap_xxx
6
+ # passport_path: ~/.aport/passport.json