@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,46 @@
1
+ # Tool → policy pack mapping
2
+
3
+ OpenClaw (or any caller) invokes the guardrail with a **tool name** and **context JSON**. The guardrail maps the tool name to a **policy pack** in `external/aport-policies/` and evaluates the request against that policy and the passport.
4
+
5
+ This mapping is implemented in `bin/aport-guardrail-api.sh` and `bin/aport-guardrail-bash.sh`. The table below is the single source of truth for documentation.
6
+
7
+ ## Mapping table
8
+
9
+ | Tool name (pattern) | Policy pack ID | Policy location |
10
+ |---------------------|----------------|------------------|
11
+ | `git.create_pr`, `git.merge`, `git.push`, `git.*` | `code.repository.merge.v1` | `external/aport-policies/code.repository.merge.v1/` |
12
+ | `exec.run`, `exec.*`, `system.command.*`, `system.*` | `system.command.execute.v1` | `local-overrides` or API |
13
+ | `message.send`, `message.*`, `messaging.*` | `messaging.message.send.v1` | `external/aport-policies/messaging.message.send.v1/` |
14
+ | `mcp.tool.*`, `mcp.*` | `mcp.tool.execute.v1` | API / evaluator |
15
+ | `agent.session.*`, `session.create`, `session.*` | `agent.session.create.v1` | API / evaluator |
16
+ | `agent.tool.*`, `tool.register`, `tool.*` | `agent.tool.register.v1` | API / evaluator |
17
+ | `payment.refund`, `payment.*`, `finance.payment.refund` | `finance.payment.refund.v1` | `external/aport-policies/finance.payment.refund.v1/` |
18
+ | `payment.charge`, `finance.payment.charge` | `finance.payment.charge.v1` | `external/aport-policies/finance.payment.charge.v1/` |
19
+ | `database.write`, `database.*`, `data.export` | `data.export.create.v1` | `external/aport-policies/data.export.create.v1/` |
20
+
21
+ **Unknown tool:** In the **bash/API guardrail script**, an unknown tool name results in deny (exit 1). In the **OpenClaw plugin**, unmapped tools are **allowed** by default so custom skills and ClawHub tools work; set `allowUnmappedTools: false` in plugin config for strict (block unmapped).
22
+
23
+ ## How OpenClaw uses it
24
+
25
+ 1. OpenClaw (or your integration code) decides to run a tool, e.g. `system.command.execute` with `{"command":"npm install"}`.
26
+ 2. Before executing, it calls the guardrail script with that tool name and context:
27
+ ```bash
28
+ ~/.openclaw/.skills/aport-guardrail.sh system.command.execute '{"command":"npm install"}'
29
+ ```
30
+ 3. The script maps `system.command.execute` → `system.command.execute.v1`, loads the passport and policy (or calls the API), and evaluates.
31
+ 4. Exit 0 = allow, exit 1 = deny. Decision details are in `~/.openclaw/decision.json` (or your configured path).
32
+
33
+ ## Adding or changing mappings
34
+
35
+ To add a new tool → policy mapping, edit the `case` block in:
36
+
37
+ - `bin/aport-guardrail-api.sh`
38
+ - `bin/aport-guardrail-bash.sh`
39
+
40
+ and add a new pattern and policy pack ID. The policy pack must exist under `external/aport-policies/<pack_id>/` (or in local-overrides / API).
41
+
42
+ ## Reference
43
+
44
+ - OAP spec: `external/aport-spec/`
45
+ - Policy packs: `external/aport-policies/`
46
+ - AGENTS.md example: [AGENTS.md.example](AGENTS.md.example)
@@ -0,0 +1,46 @@
1
+ # Upgrade Guide
2
+
3
+ ## Upgrading from 0.1.0 to 1.0.0
4
+
5
+ ### Breaking Changes
6
+ None - 1.0.0 is the first production release.
7
+
8
+ ### New Features
9
+ - OpenClaw plugin with `before_tool_call` enforcement
10
+ - API mode support (in addition to local mode)
11
+ - Enhanced exec handling with recursive guardrail detection
12
+ - Improved error messages with OAP codes
13
+
14
+ ### Migration Steps
15
+
16
+ **If upgrading from 0.1.0:**
17
+
18
+ 1. Update your installation:
19
+ ```bash
20
+ git pull
21
+ git submodule update --init --recursive
22
+ ```
23
+
24
+ 2. Re-run setup to install plugin:
25
+ ```bash
26
+ ./bin/openclaw
27
+ ```
28
+
29
+ 3. Update OpenClaw config (if using plugin):
30
+ ```yaml
31
+ plugins:
32
+ entries:
33
+ openclaw-aport:
34
+ enabled: true
35
+ config:
36
+ mode: local # or "api"
37
+ passportFile: ~/.openclaw/passport.json
38
+ ```
39
+
40
+ 4. Verify passport has `allowed_commands`:
41
+ ```bash
42
+ jq '.limits.system.command.execute.allowed_commands' ~/.openclaw/passport.json
43
+ ```
44
+ If empty or missing, re-run passport wizard or add manually.
45
+
46
+ **No other changes required.**
@@ -0,0 +1,97 @@
1
+ # Verification methods: Local vs API
2
+
3
+ This doc compares how policy is evaluated in **local mode** (bash guardrail script) vs **API mode** (APort cloud or self-hosted agent-passport using the generic evaluator). It also summarizes the four ways you can run the guardrail (standalone bash, standalone API, plugin + local, plugin + API).
4
+
5
+ ---
6
+
7
+ ## Summary: when to use which
8
+
9
+ | Method | Best for | Robustness | Network |
10
+ |--------|----------|------------|---------|
11
+ | **API (default)** | Production, full OAP parity, new policy rules without code changes | Full: JSON Schema, assurance, regions, taxonomy, MCP, evaluation_rules from policy JSON, signed decisions | Yes (api.aport.io or self-hosted) |
12
+ | **Local (bash)** | Privacy, offline, air-gapped, or no API key | Core checks only; same policy packs but hand-coded per policy; new rules need script updates | No |
13
+
14
+ **Recommendation:** Use **API mode** (default in `./bin/openclaw`) for full policy fidelity and future policy packs. Use **local mode** when you must avoid the network or run fully offline.
15
+
16
+ ---
17
+
18
+ ## Four ways to run the guardrail
19
+
20
+ | # | Method | How | Typical use |
21
+ |---|--------|-----|-------------|
22
+ | 1 | **Standalone bash** | `OPENCLAW_PASSPORT_FILE=... ./bin/aport-guardrail-bash.sh <tool> '<context_json>'` | Scripts, CI, manual checks |
23
+ | 2 | **Standalone API** | `./bin/aport-guardrail-api.sh <tool> '<context_json>'` with `APORT_API_URL` | Same as above, but evaluation in cloud |
24
+ | 3 | **Plugin + local** | OpenClaw `before_tool_call` → plugin spawns `aport-guardrail-bash.sh` | OpenClaw with no API / offline |
25
+ | 4 | **Plugin + API** | OpenClaw `before_tool_call` → plugin calls APort API | OpenClaw with full OAP (default) |
26
+
27
+ All four produce OAP v1.0–shaped decisions (allow, reasons, policy_id, etc.). The **evaluation logic** differs between local (bash) and API (generic evaluator).
28
+
29
+ ---
30
+
31
+ ## Local evaluator (bash) vs API generic evaluator
32
+
33
+ The **APort API** (and self-hosted agent-passport) uses a **generic evaluator** that loads policy JSON and runs a full OAP pipeline. The **local guardrail** in this repo (`bin/aport-guardrail-bash.sh`) implements a **subset** of that pipeline in bash + jq.
34
+
35
+ ### What the API generic evaluator does (full OAP)
36
+
37
+ 1. **Passport status** — suspended/revoked → deny
38
+ 2. **Required context (JSON Schema)** — validates `required_context` from policy JSON against the request
39
+ 3. **Capabilities** — passport must have required capabilities (e.g. `system.command.execute`, `messaging.send`)
40
+ 4. **Assurance level** — `min_assurance` from policy (e.g. L2) vs passport assurance
41
+ 5. **Limits** — uses `evaluation_rules` from policy JSON (expression + custom_validator); supports capability-scoped limits, DB-backed rate limits, idempotency
42
+ 6. **Regions** — `requires_regions` from policy
43
+ 7. **Taxonomy** — policy-defined taxonomy checks
44
+ 8. **MCP** — MCP allowlist/validation when defined
45
+ 9. **Custom evaluation rules** — runs each `evaluation_rules` entry (expression or custom_validator) from the policy pack
46
+ 10. **Signed decisions** — Ed25519 signatures, optional chained audit
47
+
48
+ Reference: [agent-passport generic-evaluator](https://github.com/aporthq/agent-passport) (`functions/utils/policy/generic-evaluator.ts`).
49
+
50
+ ### What the local (bash) evaluator does
51
+
52
+ 1. **Passport status** — local verify checks passport status first; if `status` is not `active` (e.g. `suspended` or `revoked`) → deny with `oap.passport_suspended`. Passport is the source of truth (no separate kill-switch file).
53
+ 2. **Passport load** — read passport JSON; invalid or missing → deny
54
+ 3. **Passport status** — `status !== "active"` → deny
55
+ 4. **Spec version** — must be `oap/1.0`
56
+ 5. **Tool → policy mapping** — fixed `case` (e.g. `exec.*`/`system.*` → `system.command.execute.v1`, `messaging.*` → `messaging.message.send.v1`)
57
+ 6. **Capabilities** — passport must list required capability (with alias e.g. `messaging.message.send` → `messaging.send`)
58
+ 7. **Policy-specific limits (hand-coded):**
59
+ - **code.repository.merge** — PR size (`max_pr_size_kb`), `allowed_repos`, `allowed_base_branches`
60
+ - **system.command.execute** — `allowed_commands` (prefix or `*`), `blocked_patterns`
61
+ - **messaging.message.send** — `allowed_recipients` (optional)
62
+ 8. **Decision output** — OAP-shaped decision (allow, reasons, policy_id, passport_digest, content_hash, chain)
63
+ 9. **No** JSON Schema validation of context
64
+ 10. **No** assurance, regions, taxonomy, MCP, or generic `evaluation_rules` from policy JSON
65
+
66
+ So: **local is robust enough for the core policies** (exec, messaging, repo merge) for allowlist/blocklist and the limits implemented in bash. It is **not** a full reimplementation of the generic evaluator. New policy packs or new rules in existing packs (e.g. `working_directory`, `environment_variables` in system.command.execute) require either API mode or updates to the bash script.
67
+
68
+ ---
69
+
70
+ ## Feature comparison (local vs API)
71
+
72
+ | Feature | Local (bash) | API (generic evaluator) |
73
+ |---------|--------------|--------------------------|
74
+ | Passport status check | ✅ | ✅ |
75
+ | Kill switch | ✅ (file-based) | N/A (handled by registry/suspend) |
76
+ | Capability check | ✅ (with messaging alias) | ✅ |
77
+ | JSON Schema required_context | ❌ | ✅ |
78
+ | Assurance level | ❌ | ✅ |
79
+ | Regions | ❌ | ✅ |
80
+ | Taxonomy | ❌ | ✅ |
81
+ | MCP validation | ❌ | ✅ |
82
+ | Limits from policy JSON | Hand-coded subset only | ✅ Full (evaluation_rules, custom_validators) |
83
+ | system.command.execute | allowed_commands, blocked_patterns | + execution_time, working_directory, env (if in policy) |
84
+ | code.repository.merge | PR size, allowed_repos, allowed_base_branches | Same + path_allowlist, require_review if in policy |
85
+ | messaging.message.send | allowed_recipients | + rate limits (msgs_per_min/day), channel allowlist (if in policy) |
86
+ | New policy packs | Requires bash changes | Load from policy JSON |
87
+ | Signed decisions | Local-unsigned only | Ed25519 signed (cloud) |
88
+ | Rate limits / idempotency | ❌ | ✅ (when API uses DB) |
89
+
90
+ ---
91
+
92
+ ## Conclusion
93
+
94
+ - **Local (bash):** Useful for privacy, offline, and the core use cases (exec allowlist/blocklist, messaging recipient, repo/PR limits). For full OAP parity and future policy packs, use **API mode**.
95
+ - **API (default):** Recommended for production and when you want the same behavior as [APort in Goose](https://raw.githubusercontent.com/aporthq/.github/refs/heads/main/profile/APORT_GOOSE_ARCHITECTURE.md) and the full generic evaluator (JSON Schema, assurance, regions, evaluation_rules, signed decisions).
96
+
97
+ The installer (`./bin/openclaw`) defaults to **API mode**; choose local only when you need to run without the network.
@@ -0,0 +1,8 @@
1
+ # Assets for docs and README
2
+
3
+ - **Porter (mascot):** Use SVGs and the interactive playground from [APort Brand — Meet Porter](https://aport.io/brand-mascot-agent/). You can download the page or copy the mascot SVGs for use in docs or the main README.
4
+ - **Demo GIF:** Add a short GIF here (e.g. `porter-demo.gif` or `guardrail-demo.gif`) showing:
5
+ - Terminal: one ALLOW and one DENY from the guardrail, or
6
+ - Plugin config + passport snippet, or
7
+ - Porter verifying a command (from the brand page).
8
+ Then reference it in the root README, e.g. `![Demo](docs/assets/porter-demo.gif)`.
@@ -0,0 +1,54 @@
1
+ <svg width="120" height="120" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
2
+ <defs>
3
+ <filter id="softShadow" x="-50%" y="-50%" width="200%" height="200%">
4
+ <feGaussianBlur in="SourceAlpha" stdDeviation="2"/>
5
+ <feOffset dx="0" dy="2" result="offsetblur"/>
6
+ <feComponentTransfer>
7
+ <feFuncA type="linear" slope="0.15"/>
8
+ </feComponentTransfer>
9
+ <feMerge>
10
+ <feMergeNode/>
11
+ <feMergeNode in="SourceGraphic"/>
12
+ </feMerge>
13
+ </filter>
14
+ <radialGradient id="innerGlow" cx="50%" cy="40%" r="60%">
15
+ <stop offset="0%" stop-color="white" stop-opacity="0.2"/>
16
+ <stop offset="100%" stop-color="white" stop-opacity="0"/>
17
+ </radialGradient>
18
+ </defs>
19
+ <circle cx="50" cy="50" r="48" fill="#0A84FF" opacity="0.05"/>
20
+ <rect x="30" y="35" width="40" height="40" rx="20" fill="#007AFF" filter="url(#softShadow)"/>
21
+ <rect x="30" y="35" width="40" height="40" rx="20" fill="url(#innerGlow)"/>
22
+ <rect x="33" y="38" width="34" height="34" rx="17" fill="#F5F5F7" opacity="0.12"/>
23
+ <line x1="38" y1="48" x2="54" y2="48" stroke="#0A84FF" stroke-width="1" opacity="0.3"/>
24
+ <line x1="38" y1="52" x2="62" y2="52" stroke="#0A84FF" stroke-width="1" opacity="0.3"/>
25
+ <line x1="38" y1="56" x2="58" y2="56" stroke="#0A84FF" stroke-width="1" opacity="0.3"/>
26
+ <g transform="translate(0, -2)">
27
+ <ellipse cx="50" cy="35" rx="22" ry="11" fill="#1D1D1F" opacity="0.9"/>
28
+ <ellipse cx="50" cy="37" rx="26" ry="6" fill="#1D1D1F" opacity="0.7"/>
29
+ </g>
30
+ <ellipse cx="50" cy="30" rx="6" ry="7" fill="#FF9500" opacity="0.9"/>
31
+ <text x="50" y="33" text-anchor="middle" font-size="5" fill="white" font-weight="bold">AP</text>
32
+ <ellipse cx="42" cy="48" rx="4" ry="4" fill="white" opacity="0.95"/>
33
+ <circle cx="42" cy="48" r="2.5" fill="#1D1D1F"/>
34
+ <ellipse cx="58" cy="48" rx="4" ry="4" fill="white" opacity="0.95"/>
35
+ <circle cx="58" cy="48" r="2.5" fill="#1D1D1F"/>
36
+ <circle cx="40.5" cy="46.5" r="0.8" fill="white" opacity="0.9"/>
37
+ <circle cx="56.5" cy="46.5" r="0.8" fill="white" opacity="0.9"/>
38
+ <ellipse cx="35" cy="56" rx="3.5" ry="2.5" fill="#FF9AA2" opacity="0.25"/>
39
+ <ellipse cx="65" cy="56" rx="3.5" ry="2.5" fill="#FF9AA2" opacity="0.25"/>
40
+ <path d="M 42 58 Q 50 63 58 58" fill="none" stroke="#1D1D1F" stroke-width="2" stroke-linecap="round" opacity="0.9"/>
41
+ <ellipse cx="50" cy="66" rx="8" ry="6" fill="#FF9500" opacity="0.9"/>
42
+ <text x="50" y="68" text-anchor="middle" font-size="3.5" fill="white" font-weight="bold">APORT</text>
43
+ <ellipse cx="26" cy="55" rx="6" ry="12" fill="#007AFF" opacity="0.95"/>
44
+ <ellipse cx="74" cy="55" rx="6" ry="12" fill="#007AFF" opacity="0.95"/>
45
+ <ellipse cx="42" cy="78" rx="7" ry="10" fill="#007AFF" opacity="0.95"/>
46
+ <ellipse cx="58" cy="78" rx="7" ry="10" fill="#007AFF" opacity="0.95"/>
47
+ <ellipse cx="42" cy="77" rx="5" ry="2" fill="#1D1D1F" opacity="0.3"/>
48
+ <ellipse cx="58" cy="77" rx="5" ry="2" fill="#1D1D1F" opacity="0.3"/>
49
+ <g>
50
+ <circle cx="50" cy="55" r="16" fill="#34C759" opacity="0.15"/>
51
+ <circle cx="50" cy="55" r="13" fill="none" stroke="#34C759" stroke-width="2.5" opacity="0.9"/>
52
+ <path d="M 42 55 L 48 61 L 60 48" fill="none" stroke="#34C759" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" opacity="0.9"/>
53
+ </g>
54
+ </svg>