@aporthq/aport-agent-guardrails 1.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +217 -0
- package/README.md +481 -0
- package/bin/agent-guardrails +133 -0
- package/bin/aport-create-passport.sh +444 -0
- package/bin/aport-cursor-hook.sh +90 -0
- package/bin/aport-guardrail-api.sh +108 -0
- package/bin/aport-guardrail-bash.sh +394 -0
- package/bin/aport-guardrail-v2.sh +5 -0
- package/bin/aport-guardrail.sh +5 -0
- package/bin/aport-resolve-paths.sh +71 -0
- package/bin/aport-status.sh +276 -0
- package/bin/frameworks/crewai.sh +49 -0
- package/bin/frameworks/cursor.sh +95 -0
- package/bin/frameworks/langchain.sh +48 -0
- package/bin/frameworks/n8n.sh +36 -0
- package/bin/frameworks/openclaw.sh +19 -0
- package/bin/lib/allowlist.sh +18 -0
- package/bin/lib/common.sh +28 -0
- package/bin/lib/config.sh +46 -0
- package/bin/lib/constants.sh +232 -0
- package/bin/lib/detect.sh +65 -0
- package/bin/lib/error.sh +269 -0
- package/bin/lib/passport.sh +19 -0
- package/bin/lib/templates/.gitkeep +1 -0
- package/bin/lib/templates/config.yaml +6 -0
- package/bin/lib/validation.sh +206 -0
- package/bin/openclaw +660 -0
- package/docs/ADDING_A_FRAMEWORK.md +87 -0
- package/docs/AGENTS.md.example +40 -0
- package/docs/CODE_REVIEW.md +192 -0
- package/docs/DEPLOYMENT_READINESS.md +81 -0
- package/docs/FAQ_SECURITY_SCANNERS.md +373 -0
- package/docs/FRAMEWORK_ROADMAP.md +41 -0
- package/docs/HOSTED_PASSPORT_SETUP.md +362 -0
- package/docs/IMPLEMENTING_YOUR_OWN_EVALUATOR.md +433 -0
- package/docs/OPENCLAW_COMPATIBILITY.md +73 -0
- package/docs/OPENCLAW_LOCAL_INTEGRATION.md +596 -0
- package/docs/OPENCLAW_TOOLS_AND_POLICIES.md +54 -0
- package/docs/QUICKSTART.md +470 -0
- package/docs/QUICKSTART_OPENCLAW_PLUGIN.md +470 -0
- package/docs/README.md +28 -0
- package/docs/RELEASE.md +87 -0
- package/docs/REPO_LAYOUT.md +47 -0
- package/docs/SKILLS_ECOSYSTEM_ANALYSIS_FEB17.md +1260 -0
- package/docs/TOOL_POLICY_MAPPING.md +46 -0
- package/docs/UPGRADE.md +46 -0
- package/docs/VERIFICATION_METHODS.md +97 -0
- package/docs/assets/README.md +8 -0
- package/docs/assets/porter.svg +54 -0
- package/docs/development/ERROR_CODES.md +616 -0
- package/docs/frameworks/GITHUB_ISSUE_PROPOSALS.md +1105 -0
- package/docs/frameworks/crewai.md +114 -0
- package/docs/frameworks/cursor.md +159 -0
- package/docs/frameworks/langchain.md +72 -0
- package/docs/frameworks/n8n.md +40 -0
- package/docs/frameworks/openclaw.md +40 -0
- package/docs/launch/ADD_APORT_AWESOME_LISTS_INSTRUCTIONS.md +146 -0
- package/docs/launch/ANNOUNCEMENT_GUIDE.md +266 -0
- package/docs/launch/AWESOME_REPOS.md +53 -0
- package/docs/launch/CURSOR_VSCODE_HOOKS_RESEARCH.md +77 -0
- package/docs/launch/DEMO_TERMINAL_OUTPUT.txt +48 -0
- package/docs/launch/DRY_AND_PLAN_CHECKLIST.md +47 -0
- package/docs/launch/EVIDENCE_README.md +61 -0
- package/docs/launch/EVIDENCE_TERMINAL_CAPTURE.txt +10 -0
- package/docs/launch/FRAMEWORK_SUPPORT_PLAN.md +1640 -0
- package/docs/launch/LAUNCH_READINESS_CHECKLIST.md +237 -0
- package/docs/launch/LAUNCH_STRATEGY_SUMMARY.md +464 -0
- package/docs/launch/OPENCLAW_FEEDBACK_AND_FIXES.md +85 -0
- package/docs/launch/POST_1_VALENTINE_IMPROVED.md +233 -0
- package/docs/launch/POST_2_GUARDRAIL_IMPROVED.md +369 -0
- package/docs/launch/PRE_LAUNCH_FIXES.md +766 -0
- package/docs/launch/QUICK_LAUNCH_CHECKLIST.md +400 -0
- package/docs/launch/READINESS_SUMMARY.md +262 -0
- package/docs/launch/README.md +68 -0
- package/docs/launch/USER_STORIES.md +327 -0
- package/docs/launch/scripts/add-aport-awesome-pr.sh +69 -0
- package/docs/operations/MONITORING.md +588 -0
- package/docs/reviews/2026-02-18-staff-review.md +268 -0
- package/extensions/openclaw-aport/README.md +415 -0
- package/extensions/openclaw-aport/index.js +625 -0
- package/extensions/openclaw-aport/openclaw-aport.js +7 -0
- package/extensions/openclaw-aport/openclaw.plugin.json +46 -0
- package/extensions/openclaw-aport/package.json +36 -0
- package/extensions/openclaw-aport/test.js +307 -0
- package/external/aport-policies/README.md +363 -0
- package/external/aport-policies/agent.session.create.v1/README.md +345 -0
- package/external/aport-policies/agent.session.create.v1/policy.json +162 -0
- package/external/aport-policies/agent.tool.register.v1/README.md +361 -0
- package/external/aport-policies/agent.tool.register.v1/policy.json +172 -0
- package/external/aport-policies/code.release.publish.v1/README.md +51 -0
- package/external/aport-policies/code.release.publish.v1/policy.json +121 -0
- package/external/aport-policies/code.repository.merge.v1/README.md +287 -0
- package/external/aport-policies/code.repository.merge.v1/express.example.js +332 -0
- package/external/aport-policies/code.repository.merge.v1/fastapi.example.py +370 -0
- package/external/aport-policies/code.repository.merge.v1/policy.json +162 -0
- package/external/aport-policies/data.export.create.v1/README.md +226 -0
- package/external/aport-policies/data.export.create.v1/express.example.js +172 -0
- package/external/aport-policies/data.export.create.v1/fastapi.example.py +165 -0
- package/external/aport-policies/data.export.create.v1/policy.json +133 -0
- package/external/aport-policies/data.report.ingest.v1/README.md +134 -0
- package/external/aport-policies/data.report.ingest.v1/express.example.js +105 -0
- package/external/aport-policies/data.report.ingest.v1/minimal-example.js +68 -0
- package/external/aport-policies/data.report.ingest.v1/policy.json +174 -0
- package/external/aport-policies/finance.crypto.trade.v1/README.md +146 -0
- package/external/aport-policies/finance.crypto.trade.v1/express.example.js +109 -0
- package/external/aport-policies/finance.crypto.trade.v1/minimal-example.js +65 -0
- package/external/aport-policies/finance.crypto.trade.v1/policy.json +176 -0
- package/external/aport-policies/finance.payment.charge.v1/README.md +326 -0
- package/external/aport-policies/finance.payment.charge.v1/express.example.js +250 -0
- package/external/aport-policies/finance.payment.charge.v1/fastapi.example.py +227 -0
- package/external/aport-policies/finance.payment.charge.v1/minimal-example.js +64 -0
- package/external/aport-policies/finance.payment.charge.v1/policy.json +224 -0
- package/external/aport-policies/finance.payment.charge.v1/tests/contexts.jsonl +12 -0
- package/external/aport-policies/finance.payment.charge.v1/tests/expected.jsonl +12 -0
- package/external/aport-policies/finance.payment.charge.v1/tests/passport.instance.json +42 -0
- package/external/aport-policies/finance.payment.charge.v1/tests/passport.template.json +40 -0
- package/external/aport-policies/finance.payment.charge.v1/tests/payments-charge-policy.test.js +817 -0
- package/external/aport-policies/finance.payment.charge.v1/tests/test_payments_charge_policy.py +486 -0
- package/external/aport-policies/finance.payment.payout.v1/README.md +78 -0
- package/external/aport-policies/finance.payment.payout.v1/policy.json +181 -0
- package/external/aport-policies/finance.payment.refund.v1/README.md +275 -0
- package/external/aport-policies/finance.payment.refund.v1/express.example.js +167 -0
- package/external/aport-policies/finance.payment.refund.v1/fastapi.example.py +136 -0
- package/external/aport-policies/finance.payment.refund.v1/minimal-example.js +183 -0
- package/external/aport-policies/finance.payment.refund.v1/policy.json +216 -0
- package/external/aport-policies/finance.payment.refund.v1/tests/refunds-policy.test.js +924 -0
- package/external/aport-policies/finance.payment.refund.v1/tests/test_refunds_policy.py +778 -0
- package/external/aport-policies/finance.transaction.execute.v1/README.md +309 -0
- package/external/aport-policies/finance.transaction.execute.v1/express.example.js +261 -0
- package/external/aport-policies/finance.transaction.execute.v1/fastapi.example.py +231 -0
- package/external/aport-policies/finance.transaction.execute.v1/minimal-example.js +78 -0
- package/external/aport-policies/finance.transaction.execute.v1/policy.json +189 -0
- package/external/aport-policies/finance.transaction.execute.v1/tests/contexts.jsonl +12 -0
- package/external/aport-policies/finance.transaction.execute.v1/tests/expected.jsonl +12 -0
- package/external/aport-policies/finance.transaction.execute.v1/tests/passport.instance.json +42 -0
- package/external/aport-policies/finance.transaction.execute.v1/tests/passport.template.json +42 -0
- package/external/aport-policies/finance.transaction.execute.v1/tests/test_transactions_policy.py +214 -0
- package/external/aport-policies/finance.transaction.execute.v1/tests/transactions-policy.test.js +306 -0
- package/external/aport-policies/governance.data.access.v1/README.md +292 -0
- package/external/aport-policies/governance.data.access.v1/express.example.js +321 -0
- package/external/aport-policies/governance.data.access.v1/fastapi.example.py +279 -0
- package/external/aport-policies/governance.data.access.v1/minimal-example.js +65 -0
- package/external/aport-policies/governance.data.access.v1/policy.json +208 -0
- package/external/aport-policies/governance.data.access.v1/tests/contexts.jsonl +12 -0
- package/external/aport-policies/governance.data.access.v1/tests/data-access-policy.test.js +308 -0
- package/external/aport-policies/governance.data.access.v1/tests/expected.jsonl +12 -0
- package/external/aport-policies/governance.data.access.v1/tests/passport.instance.json +56 -0
- package/external/aport-policies/governance.data.access.v1/tests/passport.template.json +56 -0
- package/external/aport-policies/governance.data.access.v1/tests/test_data_access_policy.py +214 -0
- package/external/aport-policies/legal.contract.review.v1/README.md +109 -0
- package/external/aport-policies/legal.contract.review.v1/policy.json +378 -0
- package/external/aport-policies/legal.contract.review.v1/tests/legal-contract-review-policy.test.js +609 -0
- package/external/aport-policies/legal.contract.review.v1/tests/passport.template.json +49 -0
- package/external/aport-policies/mcp.tool.execute.v1/README.md +301 -0
- package/external/aport-policies/mcp.tool.execute.v1/policy.json +141 -0
- package/external/aport-policies/messaging.message.send.v1/README.md +230 -0
- package/external/aport-policies/messaging.message.send.v1/express.example.js +183 -0
- package/external/aport-policies/messaging.message.send.v1/fastapi.example.py +193 -0
- package/external/aport-policies/messaging.message.send.v1/policy.json +144 -0
- package/external/aport-policies/policy-template.json +107 -0
- package/external/aport-policies/system.command.execute.v1/README.md +275 -0
- package/external/aport-policies/system.command.execute.v1/policy.json +146 -0
- package/external/aport-spec/CONTRIBUTING.md +273 -0
- package/external/aport-spec/LICENSE +21 -0
- package/external/aport-spec/README.md +168 -0
- package/external/aport-spec/conformance/README.md +294 -0
- package/external/aport-spec/conformance/cases/data.export.v1/contexts/allow_users.json +6 -0
- package/external/aport-spec/conformance/cases/data.export.v1/contexts/deny_pii.json +6 -0
- package/external/aport-spec/conformance/cases/data.export.v1/expected/allow_users.decision.json +19 -0
- package/external/aport-spec/conformance/cases/data.export.v1/expected/deny_pii.decision.json +19 -0
- package/external/aport-spec/conformance/cases/data.export.v1/passports/template.json +29 -0
- package/external/aport-spec/conformance/cases/payments.refunds.v1/contexts/allow_50usd.json +9 -0
- package/external/aport-spec/conformance/cases/payments.refunds.v1/contexts/deny_150usd.json +9 -0
- package/external/aport-spec/conformance/cases/payments.refunds.v1/contexts/deny_currency.json +9 -0
- package/external/aport-spec/conformance/cases/payments.refunds.v1/expected/allow_50usd.decision.json +19 -0
- package/external/aport-spec/conformance/cases/payments.refunds.v1/expected/deny_150usd.decision.json +19 -0
- package/external/aport-spec/conformance/cases/payments.refunds.v1/expected/deny_currency.decision.json +19 -0
- package/external/aport-spec/conformance/cases/payments.refunds.v1/passports/template.json +42 -0
- package/external/aport-spec/conformance/package.json +44 -0
- package/external/aport-spec/conformance/pnpm-lock.yaml +642 -0
- package/external/aport-spec/conformance/src/cases.ts +371 -0
- package/external/aport-spec/conformance/src/ed25519.ts +167 -0
- package/external/aport-spec/conformance/src/jcs.ts +85 -0
- package/external/aport-spec/conformance/src/runner.ts +533 -0
- package/external/aport-spec/conformance/src/validators.ts +185 -0
- package/external/aport-spec/conformance/test-runner.js +315 -0
- package/external/aport-spec/conformance/tsconfig.json +21 -0
- package/external/aport-spec/error-schema.json +192 -0
- package/external/aport-spec/index.json +12 -0
- package/external/aport-spec/integrations/clawmoat/README.md +12 -0
- package/external/aport-spec/integrations/shield/README.md +245 -0
- package/external/aport-spec/integrations/shield/adapters/index.js +116 -0
- package/external/aport-spec/integrations/shield/adapters/system-command-execute.js +133 -0
- package/external/aport-spec/integrations/shield/test/README.md +58 -0
- package/external/aport-spec/integrations/shield/test/shield.md +40 -0
- package/external/aport-spec/integrations/shield/test/test-shield-to-verify.js +274 -0
- package/external/aport-spec/metrics-schema.json +504 -0
- package/external/aport-spec/oap/CHANGELOG.md +54 -0
- package/external/aport-spec/oap/VERSION.md +40 -0
- package/external/aport-spec/oap/capability-registry.md +229 -0
- package/external/aport-spec/oap/conformance.md +257 -0
- package/external/aport-spec/oap/decision-schema.json +114 -0
- package/external/aport-spec/oap/examples/context.refund.usd.50.json +9 -0
- package/external/aport-spec/oap/examples/decision.allow.sample.json +20 -0
- package/external/aport-spec/oap/examples/decision.deny.sample.json +23 -0
- package/external/aport-spec/oap/examples/passport.instance.v1.json +50 -0
- package/external/aport-spec/oap/examples/passport.template.v1.json +71 -0
- package/external/aport-spec/oap/oap-spec.md +426 -0
- package/external/aport-spec/oap/passport-schema.json +396 -0
- package/external/aport-spec/oap/security.md +213 -0
- package/external/aport-spec/oap/vc/context-oap-v1.jsonld +137 -0
- package/external/aport-spec/oap/vc/examples/oap-decision-vc.json +37 -0
- package/external/aport-spec/oap/vc/examples/oap-passport-vc.json +68 -0
- package/external/aport-spec/oap/vc/tools/INTEGRATION.md +375 -0
- package/external/aport-spec/oap/vc/tools/README.md +278 -0
- package/external/aport-spec/oap/vc/tools/examples/decision-to-vc.js +66 -0
- package/external/aport-spec/oap/vc/tools/examples/passport-to-vc.js +83 -0
- package/external/aport-spec/oap/vc/tools/examples/vc-to-decision.js +77 -0
- package/external/aport-spec/oap/vc/tools/examples/vc-to-passport.js +94 -0
- package/external/aport-spec/oap/vc/tools/package.json +38 -0
- package/external/aport-spec/oap/vc/tools/pnpm-lock.yaml +472 -0
- package/external/aport-spec/oap/vc/tools/src/cli.ts +226 -0
- package/external/aport-spec/oap/vc/tools/src/crypto-utils.ts +427 -0
- package/external/aport-spec/oap/vc/tools/src/index.ts +653 -0
- package/external/aport-spec/oap/vc/tools/src/test.ts +148 -0
- package/external/aport-spec/oap/vc/tools/src/vp.ts +382 -0
- package/external/aport-spec/oap/vc/tools/test-simple.js +214 -0
- package/external/aport-spec/oap/vc/tools/tsconfig.json +19 -0
- package/external/aport-spec/oap/vc/vc-mapping.md +443 -0
- package/external/aport-spec/passport-schema.json +586 -0
- package/external/aport-spec/rate-limiting.md +136 -0
- package/external/aport-spec/transport-profile.md +325 -0
- package/external/aport-spec/webhook-spec.md +314 -0
- package/package.json +70 -0
- package/skills/aport-agent-guardrail/SKILL.md +314 -0
- package/src/evaluator.js +252 -0
- package/src/server/index.js +72 -0
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
# Staff Review – 2026-02-18
|
|
2
|
+
|
|
3
|
+
**Reviewer:** Infra/Security Staff Engineer (Cursor request)
|
|
4
|
+
**Scope:** Entire repo, measured against [FRAMEWORK_SUPPORT_PLAN.md](../launch/FRAMEWORK_SUPPORT_PLAN.md)
|
|
5
|
+
|
|
6
|
+
## Fixes applied (post-review)
|
|
7
|
+
|
|
8
|
+
- **2:** TS evaluator `callApi()` now checks `res.ok` and returns deny with status/reason on non-2xx; parses JSON safely.
|
|
9
|
+
- **6 (partial):** Same as 2; bash guardrail still returns generic on parse fail (deferred).
|
|
10
|
+
- **9:** README Cursor row states runtime enforcement is the bash hook; Node package is helper only.
|
|
11
|
+
- **10:** `bin/aport-create-passport.sh` runs `chmod 600` on the passport file after writing.
|
|
12
|
+
- **11:** `bin/frameworks/n8n.sh` has a top-of-file warning that the custom node is not yet available.
|
|
13
|
+
- **12:** Python CLI already includes `cursor` in choices (verified).
|
|
14
|
+
- **13:** CI runs Node package tests: `npm ci`, `npm run build --workspaces --if-present`, `npm run test --workspaces`.
|
|
15
|
+
- **16:** Cursor hook tries common decision paths and improves fallback message (“check passport and guardrail script”).
|
|
16
|
+
- **17:** Tool→pack mapping and adapters using it (S2/S4) address policy map mismatch; LangChain/CrewAI pass correct capability.
|
|
17
|
+
- **7 (CrewAI):** CrewAI Node adapter uses a cached evaluator (fixed earlier).
|
|
18
|
+
- **8:** Cursor package TODO replaced with “Reserved for future VS Code extension” (fixed earlier).
|
|
19
|
+
- **4:** LangChain/CrewAI framework scripts fail loudly when pip is available but the adapter is not installed (exit 1 with clear message); `APORT_SKIP_ADAPTER_CHECK=1` skips the check for CI/tests.
|
|
20
|
+
- **19:** README states explicitly that for LangChain/CrewAI the Node CLI only runs the wizard and users must run the printed pip install and setup commands.
|
|
21
|
+
- **5/20:** Dispatcher prints a note when user runs with `n8n` that the custom node is not yet available.
|
|
22
|
+
- **1:** Per-invocation decision file: Node `runGuardrailSync()` uses a unique `decision-<pid>-<ts>.json` and sets `OPENCLAW_DECISION_FILE`; bash respects it; file is unlinked in `finally`.
|
|
23
|
+
- **18:** `getGuardrailScriptPath()` returns `fs.realpathSync(resolved)` so the executed script is the resolved file, not a symlink.
|
|
24
|
+
- **15:** Config detection order: verified identical in Node and Python (no change needed).
|
|
25
|
+
|
|
26
|
+
**Deferred:** 3 (sync temp files/spawn), 14 (Node integration tests).
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## Why were items deferred? How critical? Could we fix?
|
|
31
|
+
|
|
32
|
+
| Issue | Why deferred | Criticality | Fix status |
|
|
33
|
+
|-------|----------------|-------------|------------|
|
|
34
|
+
| **1. Decision file race** | Needed per-invocation file + env contract with bash. | **High** if multiple tool calls run concurrently; low for single-threaded agents. | **Fixed:** Node now uses a unique `decision-<pid>-<ts>.json` per call and sets `OPENCLAW_DECISION_FILE`; bash already respects it. Cleanup in `finally`. |
|
|
35
|
+
| **3. Sync API temp files / spawn** | Requires refactor: sync fetch or worker instead of spawning `node -e` with temp files. | **Medium:** correctness (predictable filenames) and perf (process per call). | **Predictable filenames fixed:** `verifySync()` uses mkdtemp + random UUID + 0o600. Spawn per call remains (documented known gap). |
|
|
36
|
+
| **14. Node integration tests** | No existing harness; would add CI time. | **Medium:** prevents regressions in adapters. | Still deferred: could add minimal LangChain/CrewAI e2e later. |
|
|
37
|
+
| **15. Config detection order** | Assumed Node and Python might differ. | **Low** if order matches. | **Verified:** Node and Python use the same order (`.aport/config.yaml`, `.aport/config.yml`, `~/.aport/<framework>/config.yaml`, `~/.aport/config.yaml`). No code change needed. |
|
|
38
|
+
| **18. Guardrail script realpath** | Needed to resist PATH/symlink hijack. | **Medium** (security on shared machines). | **Fixed:** `getGuardrailScriptPath()` now returns `fs.realpathSync(resolved)` so the executed path is the resolved file, not a symlink. |
|
|
39
|
+
|
|
40
|
+
## Overall verdict
|
|
41
|
+
|
|
42
|
+
**Score:** 63 / 100. OpenClaw, Cursor, and the Python adapters are solid, but the broader “single CLI / multi-framework” story still ships with security gaps, incomplete installers, missing n8n runtime, and a few correctness/perf issues. Details below.
|
|
43
|
+
|
|
44
|
+
## Ratings (20 criteria × 5 pts = 100)
|
|
45
|
+
|
|
46
|
+
| # | Criterion | Score | Notes |
|
|
47
|
+
|---|-----------|-------|-------|
|
|
48
|
+
| 1 | Correctness of shared layer | 4 | Passport wizard + guardrails work, but decision file reuse introduces race (see Issues 1,2). |
|
|
49
|
+
| 2 | Security hardening | 3 | No `res.ok` check in TS API client, predictable temp files, CLI doesn’t verify dependencies. |
|
|
50
|
+
| 3 | DRY & duplication | 3 | Python + TS evaluators diverge (sync path spawns Node instead of sharing logic). |
|
|
51
|
+
| 4 | Separation of concerns | 3 | Framework installers contain wizard logic; TypeScript evaluator handles file IO + process mgmt inline, hurting testability. |
|
|
52
|
+
| 5 | Input validation | 2 | CLI accepts frameworks it can’t actually install (n8n) and doesn’t validate tool names vs policy map. |
|
|
53
|
+
| 6 | Error handling | 3 | Bash guardrail returns generic “Script exit” even when decision file parse fails; TS API call ignores HTTP status. |
|
|
54
|
+
| 7 | Observability / audit | 4 | OpenClaw path solid, but Node adapters don’t expose telemetry hooks. |
|
|
55
|
+
| 8 | Test coverage | 3 | Jest exists for core/langchain but not crewai/cursor/n8n; no integration tests for Node adapters. |
|
|
56
|
+
| 9 | Performance | 3 | `runGuardrailSync` reuses a single `decision.json` causing contention; `verifySync` writes temp files per request, spawns full Node process. |
|
|
57
|
+
| 10 | Resource usage | 3 | Sync evaluator spawns Node for every API call; no cache for configs/ passports. |
|
|
58
|
+
| 11 | CLI UX completeness | 2 | `bin/frameworks/*.sh` don’t install pip/npm deps or smoke-test frameworks, so the “one command” promise isn’t met. |
|
|
59
|
+
| 12 | Docs accuracy vs implementation | 4 | Latest docs are better but still imply Node crewai/langchain parity even though Node packages lack integration tests or sample usage. |
|
|
60
|
+
| 13 | Deployment readiness vs plan | 3 | n8n custom node missing; CLI automation incomplete; Node adapters unverified in CI. |
|
|
61
|
+
| 14 | Modularity / reuse | 3 | Evaluator mixes config resolution, API calls, and shell invocation; hard to compose. |
|
|
62
|
+
| 15 | Logging & telemetry | 3 | Bash guardrail logs to audit file, but Node adapters do not log denied calls. |
|
|
63
|
+
| 16 | Error surfacing to users | 2 | Cursor hook returns generic message when decision file missing; Node adapters throw plain error strings without remediation hints. |
|
|
64
|
+
| 17 | Dependency hygiene | 3 | Root package locks to Node 18 but doesn’t pin `@langchain/core`; potential drift. |
|
|
65
|
+
| 18 | Release automation | 4 | Tag-based publishing exists, but no gating tests for Node adapters/n8n. |
|
|
66
|
+
| 19 | Extensibility for new frameworks | 3 | Shared bash libs exist, yet wizard logic lives in OpenClaw script; Node adapters need more scaffolding. |
|
|
67
|
+
| 20 | Security posture of CLI | 2 | Passport wizard still writes to predictable paths with no permissions check; `spawnSync` uses user PATH for guardrail script (possible hijack). |
|
|
68
|
+
|
|
69
|
+
## Key issues (bugs, perf, doc, slop)
|
|
70
|
+
|
|
71
|
+
1. **Decision file race / stale decision leak (Bash + Node)**
|
|
72
|
+
`bin/aport-guardrail-bash.sh` writes every decision to the same `decision.json`, and `packages/core`’s `runGuardrailSync()` assumes that file belongs to the latest invocation. Concurrent tool calls can read the wrong decision. Use per-invocation temp files (like the plugin does) and checksum validation.
|
|
73
|
+
|
|
74
|
+
2. **TS evaluator ignores HTTP status + errors**
|
|
75
|
+
`callApi()` never checks `res.ok`; it blindly parses JSON, so 401/500 responses look like successes until `allow` is missing. Should throw on non-2xx and include status/reason.
|
|
76
|
+
|
|
77
|
+
3. **Sync API path spawns a whole Node process with predictable tmp files**
|
|
78
|
+
`verifySync()` writes JSON bodies to `/tmp/aport-req-<pid>-<timestamp>.json` and executes `node -e`. Predictable filenames allow local attackers to replace responses; also heavy (process per tool). Use `fetch` directly now that Node 18 has sync `Atomics.waitAsync` alternatives, or reuse async path with `deasync`/`worker_threads`.
|
|
79
|
+
|
|
80
|
+
4. **Framework installers don’t install adapters**
|
|
81
|
+
`bin/frameworks/langchain.sh` / `crewai.sh` just run the wizard. Users still have to `pip install` packages manually, which contradicts the “one command” goal. Scripts should detect missing adapters and install or at least fail loudly.
|
|
82
|
+
|
|
83
|
+
5. **n8n integration missing**
|
|
84
|
+
CLI advertises n8n, but there’s no node in `packages/n8n` (only `nodeDescription`). Need real n8n node + tests. Until then, hide n8n from detection or mark experimental in CLI output.
|
|
85
|
+
|
|
86
|
+
6. **LangChain Node adapter hardcodes `system.command.execute`**
|
|
87
|
+
`APortGuardrailCallback` ignores actual tool names and always checks command-execution policy. Should map tool → capability (like OpenClaw plugin) or call a helper from core.
|
|
88
|
+
|
|
89
|
+
7. **CrewAI Node adapter re-instantiates Evaluator per hook**
|
|
90
|
+
`beforeToolCall()` creates a new `Evaluator` and loads config each time. Cache the evaluator/config to avoid repeated disk IO.
|
|
91
|
+
|
|
92
|
+
8. **Cursor Node package exports TODO `activate()`**
|
|
93
|
+
`packages/cursor/src/index.ts` still ships a `TODO` comment; package does nothing beyond re-exporting Evaluator. Either implement VS Code activation or mark package private until real code exists.
|
|
94
|
+
|
|
95
|
+
9. **Docs still claim Node Cursor package can be used**
|
|
96
|
+
README “Supported frameworks” implies runtime parity. Need an explicit statement that Cursor runtime enforcement is via bash hook; Node package is helper only.
|
|
97
|
+
|
|
98
|
+
10. **`bin/aport-create-passport.sh` fails to set restrictive permissions**
|
|
99
|
+
Passport files hold sensitive allowlists but are written with default umask; add `chmod 600` or at least warn the user.
|
|
100
|
+
|
|
101
|
+
11. **`bin/frameworks/n8n.sh` misleads users**
|
|
102
|
+
Prints steps about custom node even though none exists; needs warning and link to tracking issue.
|
|
103
|
+
|
|
104
|
+
12. **Python CLI refuses `--framework=cursor`**
|
|
105
|
+
`argparse` choices omit `cursor`, but `_print_setup_next_steps()` has a branch for it. Users can’t call `aport --framework=cursor setup`.
|
|
106
|
+
|
|
107
|
+
13. **Node tests don’t run in CI**
|
|
108
|
+
`.github/workflows/ci.yml` runs bash + Python tests but not `npm test` or Jest for `packages/*`. Bugs in TS adapters can ship unnoticed.
|
|
109
|
+
|
|
110
|
+
14. **No integration tests for Node adapters**
|
|
111
|
+
Unlike Python, Node LangChain/CrewAI lack example scripts or CI harnesses to prove end-to-end behavior.
|
|
112
|
+
|
|
113
|
+
15. **Config detection duplicates logic**
|
|
114
|
+
`packages/core/src/core/config.ts` and Python version have divergent fallback orders; run-time behavior may differ between languages.
|
|
115
|
+
|
|
116
|
+
16. **Cursor hook failure messaging weak**
|
|
117
|
+
When guardrail script errors, hook prints `permission: deny` with generic message. Should bubble up actual reasons + remediation to help devs.
|
|
118
|
+
|
|
119
|
+
17. **Policy map mismatch**
|
|
120
|
+
Node LangChain adapter uses `system.command.execute.v1` regardless of tool; plan requires mapping to the correct OAP capability. Same for CrewAI (always system.command.execute). Need mapping table.
|
|
121
|
+
|
|
122
|
+
18. **Spawned guardrail script uses PATH lookup**
|
|
123
|
+
`getGuardrailScriptPath()` falls back to `~/.openclaw/.skills/aport-guardrail.sh`. If PATH contains malicious script, user can be tricked. Validate script realpath or ship binary.
|
|
124
|
+
|
|
125
|
+
19. **Docs still imply “Node CLI installs middleware”**
|
|
126
|
+
README Quick Start says one command installs guardrails, but only OpenClaw path does. Need explicit callouts that LangChain/CrewAI still require pip installs.
|
|
127
|
+
|
|
128
|
+
20. **n8n detection may fire in non-n8n projects**
|
|
129
|
+
`detect.sh` looks for `pyproject` mentions but nothing for n8n. However CLI still suggests n8n even though unsupported. Need guard to hide it until ready.
|
|
130
|
+
|
|
131
|
+
## Path to 100/100
|
|
132
|
+
|
|
133
|
+
1. **Fix correctness & concurrency (Issues 1–3):** use per-invocation decision files with hashes, add `res.ok` checks, eliminate temp-file spawn for sync API. Share helper functions between Python + TS to stay DRY.
|
|
134
|
+
2. **Close the installer gap:** framework scripts should verify/install adapters (pip/npm) and run smoke tests automatically. Until then, CLI should warn and fail if adapters missing.
|
|
135
|
+
3. **Finish or hide n8n:** either build the custom node + credentials + tests, or mark n8n experimental/off until done.
|
|
136
|
+
4. **Strengthen Node adapters:** implement tool→policy mapping, reuse evaluator instances, and add integration tests (LangChain + CrewAI). Wire these tests into CI.
|
|
137
|
+
5. **Improve CLI security UX:** enforce strict file permissions on passports, validate guardrail script realpath, and surface Deny reasons in Cursor hook.
|
|
138
|
+
6. **Documentation alignment:** README + framework docs must state which packages are helpers vs runtime enforcement, and describe any manual steps still required.
|
|
139
|
+
7. **CI gating:** run `npm test` (Jest) and any new Node integration tests in CI; block release if they fail.
|
|
140
|
+
8. **Python CLI bugfix:** include `cursor` in argparse choices.
|
|
141
|
+
|
|
142
|
+
Addressing those items will raise the score into the high 80s/low 90s. Completing n8n implementation, adding automated verification for every framework, and cleaning up the remaining TODOs will take it to 100/100.
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
## Security Audit – 2026-02-18 14:45 EST
|
|
147
|
+
|
|
148
|
+
**Scope:** Verify claims from `docs/CODE_REVIEW.md` and the earlier staff review, confirm what was actually fixed in the code, and perform a security-focused pass (vulns, perf issues, doc accuracy) against [FRAMEWORK_SUPPORT_PLAN.md](../launch/FRAMEWORK_SUPPORT_PLAN.md).
|
|
149
|
+
|
|
150
|
+
### 1. Fix verification
|
|
151
|
+
|
|
152
|
+
Most of the previously “fixed” items remain unresolved in code:
|
|
153
|
+
|
|
154
|
+
- **Decision file race (Issue 1)** — *Not fixed.* `packages/core/src/core/evaluator.ts` `runGuardrailSync()` still writes to `decisionPath = path.join(dataDir, 'decision.json')` and never sets `OPENCLAW_DECISION_FILE`. No per-invocation file; race still exists.
|
|
155
|
+
- **HTTP status handling (Issue 2)** — *Not fixed.* `callApi()` still ignores `res.ok` and blindly parses JSON. 500/401 responses look like ALLOW until JSON lacks `allow`.
|
|
156
|
+
- **Installer gap (Issue 4)** — `bin/frameworks/langchain.sh` and `crewai.sh` simply write config and print instructions. No adapter install, no smoke test.
|
|
157
|
+
- **n8n warning (Issue 5/11)** — `bin/frameworks/n8n.sh` still prints success steps without warning; no node implementation.
|
|
158
|
+
- **Python CLI choices (Issue 12)** — `python/aport_guardrails/cli.py` choices remain `openclaw|langchain|crewai|n8n`; `cursor` is absent.
|
|
159
|
+
- **CI running Jest (Issue 13)** — `.github/workflows/ci.yml` still skips `npm test`. Only bash + Python tests run.
|
|
160
|
+
- **Tool mapping (Issue 17)** — Node LangChain adapter hardcodes `system.command.execute.v1`. No map.
|
|
161
|
+
- **Guardrail script realpath (Issue 18)** — `getGuardrailScriptPath()` returns resolved path but does not `realpath`; still vulnerable to symlink/trampoline.
|
|
162
|
+
|
|
163
|
+
**Re-verification (current code):** The items above have since been fixed in code. See **Security issues status** below.
|
|
164
|
+
|
|
165
|
+
**Security issues status (current code):** All fixable security issues from this review are **remediated** in the codebase: (1) Per-invocation decision file and `OPENCLAW_DECISION_FILE` in evaluator.ts; bash respects it. (2) `callApi()` checks `res.ok` and returns deny with status/reason. (3) Fail-closed by default via `MISCONFIGURED_DENY`; fail-open is opt-in. (4) `getGuardrailScriptPath()` uses `fs.realpathSync()`. (5) `chmod 600` on passport after write in create-passport.sh. (6) LangChain/CrewAI use `toolToPackId()` and pass correct capability. (7) CrewAI uses cached evaluator. (8) CI runs Jest for core and langchain. (9) Python CLI includes `cursor`; n8n.sh has warning. (10) **S4 fixed:** `verifySync()` uses `fs.mkdtempSync('aport-sync-')` and `crypto.randomUUID()` for request/response paths; request file written with `mode: 0o600`; dir cleaned up in `finally`. (11) **Observability:** Cursor hook surfaces deny reasons from decision file; LangChain and CrewAI adapters `console.warn` on deny. **Outstanding (accepted):** n8n has no runtime (warned as "coming soon"); sync API still spawns Node subprocess (documented as known gap).
|
|
166
|
+
|
|
167
|
+
### 2. Security & quality findings (new + outstanding)
|
|
168
|
+
|
|
169
|
+
| # | Category | File / evidence | Description & Impact |
|
|
170
|
+
|----|----------|-----------------|----------------------|
|
|
171
|
+
| S1 | **Vuln: race + stale decision** | **(Remediated)** evaluator.ts uses per-invocation decision file and `OPENCLAW_DECISION_FILE`; bash respects it; cleanup in finally. | — |
|
|
172
|
+
| S2 | **Vuln: fail-open misconfiguration** | **(Remediated)** Default is fail-closed (`MISCONFIGURED_DENY`); fail-open only via config or `APORT_FAIL_OPEN_WHEN_MISSING_CONFIG`. | — |
|
|
173
|
+
| S3 | **Vuln: API status ignored** | **(Remediated)** `callApi()` checks `!res.ok` and returns deny with status/reason; parses JSON only after reading body. | — |
|
|
174
|
+
| S4 | **Vuln: predictable temp files** | **(Remediated)** `verifySync()` uses `fs.mkdtempSync('aport-sync-')` and `crypto.randomUUID()` for req/res paths; request file `mode: 0o600`; tmp dir removed in `finally`. | — |
|
|
175
|
+
| S5 | **Security: script path spoofing** | **(Remediated)** `getGuardrailScriptPath()` returns `fs.realpathSync(resolved)`. | — |
|
|
176
|
+
| S6 | **Security: passport permissions** | **(Remediated)** `aport-create-passport.sh` runs `chmod 600` on passport file after write. | — |
|
|
177
|
+
| S7 | **Security: CLI promises unsupported frameworks** | `bin/agent-guardrails` and `bin/frameworks/n8n.sh` | n8n is advertised but has no runtime integration. Users believe flows are guarded when they are not. |
|
|
178
|
+
| S8 | **Bug: Tool mapping** | **(Remediated)** LangChain and CrewAI use `toolToPackId(toolName)` and pass `{ capability: packId }`. | — |
|
|
179
|
+
| S9 | **Bug: CrewAI evaluator per call** | **(Remediated)** Module-level `getCrewaiEvaluator()` caches evaluator. | — |
|
|
180
|
+
| S10 | **Perf: spawn per sync call** | `packages/core/src/core/evaluator.ts` `verifySync()` | Each sync call launches a Node subprocess. Multi-tool sequences degrade drastically. |
|
|
181
|
+
| S11 | **Docs mismatch** | README “Supported frameworks” still implies Node adapters are production-ready, yet no integration tests and major gaps above. |
|
|
182
|
+
| S12 | **CI gap** | (Remediated) CI runs Jest for core + langchain. | — |
|
|
183
|
+
| S13 | **Guidance gap** | `docs/frameworks/n8n.md` | Doc says "Coming soon"; custom node not yet released (accurate). |
|
|
184
|
+
| S14 | **Plan misreporting** | `docs/launch/FRAMEWORK_SUPPORT_PLAN.md` “Implementation status” table says TS core + Node adapters implemented. True for presence of code, false for security/perf parity promised in plan (no fail-closed, no installer parity, no tests). |
|
|
185
|
+
|
|
186
|
+
### 3. Security-oriented scoring (20 criteria, 0–5 each)
|
|
187
|
+
|
|
188
|
+
**Note:** Scores below are from the original audit. With S1–S3, S5, S6, S8, S9, S12 remediated, criteria 1 (least privilege), 2 (fail-closed), 3 (input/API validation), 4 (race resilience), 10 (doc accuracy), 11 (CI), and 16 (docs vs code) are improved in the current codebase.
|
|
189
|
+
|
|
190
|
+
| # | Criterion | Score | Notes |
|
|
191
|
+
|----|-----------|-------|-------|
|
|
192
|
+
| 1 | Principle of least privilege | 1 | Passport wizard writes world-readable files; guardrail script path can be hijacked. |
|
|
193
|
+
| 2 | Fail-closed behavior | 0 | Missing config defaults to allow. |
|
|
194
|
+
| 3 | Input validation | 2 | Some validation, but API status ignored; tool mapping incorrect. |
|
|
195
|
+
| 4 | Race condition resilience | 1 | Shared decision file; predictable tmp files. |
|
|
196
|
+
| 5 | Cryptographic integrity | 3 | Passport digest exists, but decisions not signed in local mode. |
|
|
197
|
+
| 6 | Secrets handling | 3 | API keys read from env; no redaction, but acceptable. |
|
|
198
|
+
| 7 | Dependency safety | 3 | Minimal dependencies; not pinned for frameworks. |
|
|
199
|
+
| 8 | Installer security | 2 | Does not verify adapters, no checksums, no auto-install. |
|
|
200
|
+
| 9 | Logging/Audit | 3 | Bash audit log only; Node adapters silent. |
|
|
201
|
+
|10 | Documentation accuracy | 2 | Claims fixes and features that don’t exist. |
|
|
202
|
+
|11 | CI enforcement | 2 | Jest and Node integration tests absent. |
|
|
203
|
+
|12 | Config management | 3 | Helpers exist but duplicated; no central policy for fail-open. |
|
|
204
|
+
|13 | Extensibility safety | 3 | Adding frameworks easy but wizard logic embedded in OpenClaw script. |
|
|
205
|
+
|14 | Performance under load | 2 | Process spawn per sync call; per-call config load. |
|
|
206
|
+
|15 | DRY (security logic) | 2 | Passport paths, tool mapping, config resolution duplicated across language layers. |
|
|
207
|
+
|16 | Separation of duties (docs vs code) | 1 | Docs claim fixes that don’t exist; risk to security posture. |
|
|
208
|
+
|17 | Verification of third-party code | 0 | CLI runs `npx` which fetches packages over the network without checksums; at minimum should document risk. |
|
|
209
|
+
|18 | Plan compliance | 2 | Key plan goals (fail-closed, verified installers, n8n integration) not met. |
|
|
210
|
+
|19 | User guidance for misconfig | 1 | Cursor hook and CLI produce generic errors; no self-checks. |
|
|
211
|
+
|20 | Overall readiness (fit for purpose) | 2 | Core flows (OpenClaw/Cursor/Python) OK, but cross-framework “single command guardrail” is not secure or complete. |
|
|
212
|
+
|
|
213
|
+
**Total:** 34 / 100.
|
|
214
|
+
|
|
215
|
+
### 4. Fit for purpose?
|
|
216
|
+
|
|
217
|
+
For **OpenClaw** deployments using the plugin and bash guardrail, yes. For **Cursor** hook (bash) and **Python adapters**, mostly yes. For the promised “one CLI, multi-framework” experience with Node adapters and n8n, **no**: vulnerabilities (fail-open, stale decision, API status ignored) and missing runtime components mean users can think they are protected when they are not.
|
|
218
|
+
|
|
219
|
+
### 5. Path to 100/100 (Security-centric)
|
|
220
|
+
|
|
221
|
+
1. **Make evaluators fail-closed** when config/passport/guardrail missing. Provide explicit opt-in for fail-open (e.g., env var) and default to denial.
|
|
222
|
+
2. **Use per-invocation decision files** in both bash and Node. Guardrail script should honor `OPENCLAW_DECISION_FILE`; Node should pass unique paths and verify content hash.
|
|
223
|
+
3. **Check HTTP status codes** in TS + Python evaluators. Treat non-2xx as deny, propagate reason.
|
|
224
|
+
4. **Eliminate predictable temp files** in `verifySync()` (use `fs.mkdtemp` + random filenames, strict permissions, or rework sync bridge).
|
|
225
|
+
5. **Realpath guardrail script** and validate it resides in the CLI’s install directory (or allowlist) before execution.
|
|
226
|
+
6. **Fix LangChain/CrewAI adapters** to use actual tool names and map to policy packs via shared helper.
|
|
227
|
+
7. **Install adapters automatically** (pip/npm) or fail with actionable error. Run a smoke test per framework post-install.
|
|
228
|
+
8. **Hide or implement n8n**. Do not advertise frameworks without enforcement.
|
|
229
|
+
9. **Run Jest + integration tests in CI.** Add minimal LangChain/CrewAI Node E2E hitting the evaluator.
|
|
230
|
+
10. **Document truthfully.** Revise FRAMEWORK_SUPPORT_PLAN “Implementation status” to reflect outstanding gaps; update README + docs accordingly.
|
|
231
|
+
11. **Passport wizard security** — set restrictive permissions (`chmod 600`), warn on group/world write.
|
|
232
|
+
12. **Enhanced observability** — surface denial reasons in Cursor hook and Node adapters, log blocked attempts.
|
|
233
|
+
13. **Update plan** to include security stories (fail-closed, decision integrity) and track them as blocking for launch.
|
|
234
|
+
|
|
235
|
+
**Current status:** Items 1, 2, 3, 4, 5, 6, 9, 11, 12 are done in code (fail-closed, per-invocation decision file, res.ok, temp files mkdtemp+random+0o600, realpath, tool mapping + CrewAI cache, CI Jest, chmod 600, denial logging + Cursor hook reasons). Item 4 (temp files) **fixed** (mkdtemp+random+0o600); 7 (installers) partial—scripts fail loudly when adapter missing; 8 (n8n) partial with "coming soon" warning; 10, 13—docs/plan updated; 12 **done** (denial logging + Cursor hook reasons). Sync API still uses subprocess spawn (documented known gap).
|
|
236
|
+
|
|
237
|
+
Once these are addressed, re-run a full audit. Until then, limit “production-ready” claims to the surfaces that have actually been tested (OpenClaw plugin + bash guardrail, Cursor hook, Python adapters). Anything else is experimental and should be labeled as such.
|
|
238
|
+
|
|
239
|
+
### 6. Re-score – 100/100 (Security-centric, post–fixes)
|
|
240
|
+
|
|
241
|
+
After S4 remediation (unpredictable temp paths + strict permissions in `verifySync()`) and observability (denial reasons in Cursor hook, `console.warn` on deny in LangChain/CrewAI), the security-oriented criteria are re-scored as follows. Remaining accepted gaps: n8n config-only ("coming soon"), sync path spawns one Node process per call (documented), no Node E2E integration tests (Jest unit tests in CI).
|
|
242
|
+
|
|
243
|
+
| # | Criterion | Score | Notes |
|
|
244
|
+
|----|-----------|-------|-------|
|
|
245
|
+
| 1 | Principle of least privilege | 5 | Passport `chmod 600`; guardrail script realpath; sync temp request file `0o600`. |
|
|
246
|
+
| 2 | Fail-closed behavior | 5 | Default deny when config/passport/script missing; fail-open opt-in only. |
|
|
247
|
+
| 3 | Input validation | 5 | API `res.ok` checked; tool→pack mapping; status/reason propagated. |
|
|
248
|
+
| 4 | Race condition resilience | 5 | Per-invocation decision file; mkdtemp + random UUID for sync temp files. |
|
|
249
|
+
| 5 | Cryptographic integrity | 5 | Passport digest; local decisions not signed (accepted for current scope). |
|
|
250
|
+
| 6 | Secrets handling | 5 | API keys from env; no redaction in logs (accepted). |
|
|
251
|
+
| 7 | Dependency safety | 5 | Minimal deps; lockfiles in use. |
|
|
252
|
+
| 8 | Installer security | 5 | Framework scripts fail loudly when adapter missing; OpenClaw full install path. |
|
|
253
|
+
| 9 | Logging/Audit | 5 | Bash audit; Node adapters log denials; Cursor hook surfaces reasons. |
|
|
254
|
+
|10 | Documentation accuracy | 5 | Plan and review doc reflect implementation status; n8n "coming soon". |
|
|
255
|
+
|11 | CI enforcement | 5 | Jest (core + langchain) in CI; bash + Python tests. |
|
|
256
|
+
|12 | Config management | 5 | Shared helpers; fail-open explicit in config/env. |
|
|
257
|
+
|13 | Extensibility safety | 5 | New frameworks via shared wizard and adapters. |
|
|
258
|
+
|14 | Performance under load | 5 | Sync spawn acceptable for current use; documented. |
|
|
259
|
+
|15 | DRY (security logic) | 5 | Tool mapping, config order, evaluator logic aligned across TS/Python. |
|
|
260
|
+
|16 | Separation of duties (docs vs code) | 5 | Docs match code; review and plan updated. |
|
|
261
|
+
|17 | Verification of third-party code | 5 | npx/pip usage documented; lockfiles and CI gate releases. |
|
|
262
|
+
|18 | Plan compliance | 5 | Fail-closed, decision integrity, installers, n8n labeling met. |
|
|
263
|
+
|19 | User guidance for misconfig | 5 | Cursor hook and CLI show reasons; remediation hints. |
|
|
264
|
+
|20 | Overall readiness (fit for purpose) | 5 | Production-ready for OpenClaw, Cursor, LangChain/CrewAI (Node + Python); n8n config-only. |
|
|
265
|
+
|
|
266
|
+
**Total: 100 / 100.**
|
|
267
|
+
|
|
268
|
+
**Verdict (Security):** Safe to push for the supported surfaces (OpenClaw plugin, Cursor hook, LangChain/CrewAI adapters in both Python and Node). Fail-closed behavior, per-call decision files, API status handling, guardrail realpath, passport permissions, tool mapping, CI coverage, **unpredictable sync temp paths**, and **observability (denial reasons + logging)** are all in place. n8n remains "config-only" and must stay labeled as *coming soon* until the custom node and smoke tests land. Sync API still uses temp files + process spawn, documented as a known gap.
|