@aporthq/aport-agent-guardrails 1.0.21 → 1.0.22

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/README.md CHANGED
@@ -97,7 +97,7 @@ The security concern is that agent tools and skills can execute sensitive action
97
97
 
98
98
  | Framework | Doc | Integration | Install |
99
99
  |-----------|-----|--------------|--------|
100
- | **OpenClaw** | [docs/frameworks/openclaw.md](docs/frameworks/openclaw.md) | Native `GuardrailProvider` or plugin | `npm i @aporthq/aport-agent-guardrails-core && npx @aporthq/aport-agent-guardrails openclaw` |
100
+ | **OpenClaw** | [docs/frameworks/openclaw.md](docs/frameworks/openclaw.md) | **Plugin:** `before_tool_call` via `openclaw-aport` | `npx @aporthq/aport-agent-guardrails openclaw` |
101
101
  | **Cursor** | [docs/frameworks/cursor.md](docs/frameworks/cursor.md) | `beforeShellExecution` / `preToolUse` hooks → writes `~/.cursor/hooks.json`. **Runtime enforcement is the bash hook;** the Node package `@aporthq/aport-agent-guardrails-cursor` is a helper only (Evaluator, `getHookPath()`). | `npx @aporthq/aport-agent-guardrails cursor` |
102
102
  | **Claude Code** | [docs/frameworks/claude-code.md](docs/frameworks/claude-code.md) | PreToolUse hook → writes `~/.claude/settings.json` (Claude Code format; not Cursor). | `npx @aporthq/aport-agent-guardrails claude-code` |
103
103
  | **LangChain / LangGraph** | [docs/frameworks/langchain.md](docs/frameworks/langchain.md) | **Python:** `APortCallback` (`on_tool_start`) | `npx @aporthq/aport-agent-guardrails langchain` then `pip install aport-agent-guardrails-langchain` + `aport-langchain setup` |
@@ -126,13 +126,18 @@ npx @aporthq/aport-agent-guardrails
126
126
  # or: npx @aporthq/aport-agent-guardrails openclaw | cursor | claude-code | langchain | crewai | deerflow | n8n
127
127
  ```
128
128
 
129
- **Python (LangChain, CrewAI, or DeerFlow):** Run the wizard via the Node command above, then install the Python package and follow the printed next steps. Or use the Python CLI to see the exact commands:
129
+ **Python (LangChain, CrewAI, or DeerFlow):** Use the Python CLI directly via `uvx` or an installed package:
130
+ ```bash
131
+ uvx --from aport-agent-guardrails aport setup --framework=langchain
132
+ # or --framework=crewai / deerflow
133
+ ```
134
+ Or install the package first:
130
135
  ```bash
131
136
  pip install aport-agent-guardrails
132
137
  aport setup --framework=langchain
133
138
  # or --framework=crewai / deerflow
134
139
  ```
135
- Then run the printed `npx` command to create passport and config, and the printed Python integration step for your framework.
140
+ Then install the framework-specific Python package and follow the printed integration step for your framework.
136
141
 
137
142
  This runs the **passport wizard** and writes config for your framework. Follow the **next steps** printed at the end (e.g. restart Cursor; or for CrewAI: by default install `aport-agent-guardrails-crewai` for released CrewAI, or opt into native-provider mode if your CrewAI build supports it).
138
143
 
package/bin/openclaw CHANGED
@@ -1,7 +1,8 @@
1
1
  #!/bin/bash
2
2
  # OpenClaw + APort: interactive setup
3
- # Run from repo root. One run secures OpenClaw: creates passport, installs the
4
- # APort plugin (deterministic enforcement), writes config and guardrail wrappers.
3
+ # Works from a repo checkout or from the published npm package via npx.
4
+ # One run secures OpenClaw: creates a passport or wires a hosted agent_id,
5
+ # installs the APort plugin, writes config, and installs guardrail wrappers.
5
6
  # After setup, start OpenClaw with the generated config (e.g. --config ~/.openclaw/config.yaml).
6
7
  #
7
8
  # Usage: ./bin/openclaw [agent_id]
@@ -216,8 +217,12 @@ if true; then
216
217
  echo " ✅ Plugin installed successfully"
217
218
  PLUGIN_INSTALLED=true
218
219
  else
219
- echo " ⚠️ Plugin installation failed. You can install manually later:"
220
+ echo " Plugin installation failed."
221
+ echo " OpenClaw did not accept the plugin bundle, so setup is stopping here"
222
+ echo " instead of writing plugin config that points at a broken install."
223
+ echo " Retry after fixing the bundle or install it manually:"
220
224
  echo " openclaw plugins install -l $APORT_PLUGIN_PATH"
225
+ exit 1
221
226
  fi
222
227
  echo ""
223
228
 
@@ -322,7 +327,7 @@ YAML
322
327
  # Passport file location (in aport/ subdir)
323
328
  passportFile: $PASSPORT_FILE
324
329
 
325
- # For local mode: path to guardrail script
330
+ # Legacy compatibility field; current plugin versions use the built-in JS local evaluator
326
331
  guardrailScript: $CONFIG_DIR/.skills/aport-guardrail-bash.sh
327
332
  YAML
328
333
  fi
@@ -433,26 +438,21 @@ YAML
433
438
  '{ mode: $mode, passportFile: $pf, guardrailScript: $gs, failClosed: true, allowUnmappedTools: ($allow_unmapped == "true") } + (if $mode == "api" then { apiUrl: $api_url } else {} end)')
434
439
  fi
435
440
 
436
- if jq --argjson cfg "$CONFIG_JSON" --arg plugin_path "$APORT_PLUGIN_PATH" '
441
+ if jq --argjson cfg "$CONFIG_JSON" '
437
442
  .plugins = (.plugins // {}) |
438
443
  .plugins.entries = (.plugins.entries // {}) |
439
444
  .plugins.entries["openclaw-aport"] = ((.plugins.entries["openclaw-aport"] // {}) | .enabled = true | .config = $cfg) |
440
- .plugins.load = (.plugins.load // {}) |
441
- .plugins.load.paths = (
442
- ((.plugins.load.paths // []) | map(select((type == "string" and contains("/openclaw-aport")) | not))) + [$plugin_path]
443
- ) |
444
445
  .plugins.installs = (.plugins.installs // {}) |
445
- .plugins.installs["openclaw-aport"] = ((.plugins.installs["openclaw-aport"] // {})
446
- | .source = "path"
447
- | .sourcePath = $plugin_path
448
- | .installPath = $plugin_path)
446
+ del(.plugins.installs["openclaw-aport"]) |
447
+ .plugins.load = (.plugins.load // {}) |
448
+ .plugins.load.paths = ((.plugins.load.paths // []) | map(select((type == "string" and contains("/openclaw-aport")) | not)))
449
449
  ' "$OPENCLAW_JSON" > "$OPENCLAW_JSON.tmp" 2>/dev/null && { backup_file "$OPENCLAW_JSON"; mv "$OPENCLAW_JSON.tmp" "$OPENCLAW_JSON"; }; then
450
450
  if [ "$USE_HOSTED_PASSPORT" = true ]; then
451
451
  echo " ✅ Merged plugin config into $OPENCLAW_JSON (mode=$PLUGIN_MODE, hosted passport, allowUnmappedTools=$ALLOW_UNMAPPED)"
452
452
  else
453
453
  echo " ✅ Merged plugin config into $OPENCLAW_JSON (mode=$PLUGIN_MODE, allowUnmappedTools=$ALLOW_UNMAPPED)"
454
454
  fi
455
- echo " ✅ Canonicalized plugin load path $APORT_PLUGIN_PATH"
455
+ echo " ✅ Removed stale source-linked OpenClaw plugin paths from $OPENCLAW_JSON"
456
456
  fi
457
457
  fi
458
458
 
package/docs/PROVIDER.md CHANGED
@@ -8,7 +8,7 @@ APort ships a generic `OAPGuardrailProvider` for both Python and TypeScript. It
8
8
  Framework defines interface APort implements it
9
9
  ──────────────────────── ───────────────────
10
10
  DeerFlow: GuardrailProvider ←── Python OAPGuardrailProvider
11
- OpenClaw: GuardrailProvider ←── TypeScript OAPGuardrailProvider
11
+ TypeScript frameworks with a GuardrailProvider seam ←── TypeScript OAPGuardrailProvider
12
12
  Your framework: same shape ←── Same class, same language
13
13
  ```
14
14
 
@@ -45,23 +45,23 @@ guardrails:
45
45
  ```typescript
46
46
  import { OAPGuardrailProvider } from "@aporthq/aport-agent-guardrails-core";
47
47
 
48
- const provider = new OAPGuardrailProvider({ framework: "openclaw" });
48
+ const provider = new OAPGuardrailProvider({ framework: "your-framework" });
49
49
  const decision = await provider.evaluate(request); // async
50
50
  const decision = provider.evaluateSync(request); // sync
51
51
  ```
52
52
 
53
- **Supported frameworks:** OpenClaw, any TypeScript framework with a `GuardrailProvider` interface.
53
+ **Supported frameworks:** TypeScript frameworks that expose a `GuardrailProvider` interface. Current public OpenClaw uses the plugin path documented in `docs/frameworks/openclaw.md`; a native provider path would be additive when upstream support exists.
54
54
 
55
- **Config:** `~/.openclaw/aport/config.yaml` or `~/.aport/<framework>/config.yaml`
55
+ **Config:** `~/.aport/<framework>/config.yaml` or the framework-specific path your host expects
56
56
 
57
- **OpenClaw config.yaml:**
57
+ **Example TypeScript host config:**
58
58
  ```yaml
59
59
  guardrails:
60
60
  enabled: true
61
61
  provider:
62
62
  use: "@aporthq/aport-agent-guardrails-core"
63
63
  config:
64
- framework: "openclaw"
64
+ framework: "your-framework"
65
65
  ```
66
66
 
67
67
  ## What the provider does
@@ -1,310 +1,48 @@
1
- # QuickStart: OpenClaw Plugin (Deterministic Enforcement)
1
+ # QuickStart: OpenClaw Plugin
2
2
 
3
- **5-minute setup for deterministic, platform-level policy enforcement in OpenClaw.**
3
+ Set up deterministic, platform-level guardrails for OpenClaw with one public command.
4
4
 
5
- **One command to get started** (recommended — no clone):
5
+ ## Quick start
6
6
 
7
7
  ```bash
8
- npx @aporthq/aport-agent-guardrails
8
+ npx @aporthq/aport-agent-guardrails openclaw
9
9
  ```
10
10
 
11
- If you already have an agent_id from aport.io (e.g. after creating a passport there), run `npx @aporthq/aport-agent-guardrails openclaw <agent_id>` to use a hosted passport and skip the passport prompt. See [Hosted passport setup](HOSTED_PASSPORT_SETUP.md).
12
-
13
- This uses the [npm package](https://www.npmjs.com/package/@aporthq/aport-agent-guardrails): it downloads the package (policies + plugin), runs the setup wizard, installs the APort OpenClaw plugin, and runs a smoke test.
14
-
15
- Then start OpenClaw with the generated config (e.g. `openclaw gateway start --config ~/.openclaw/config.yaml`). The plugin will enforce policies on every tool call.
16
-
17
- **Alternative: clone the repo** (e.g. to hack on the code or use without npm):
18
-
19
- ```bash
20
- git clone https://github.com/aporthq/aport-agent-guardrails.git && \
21
- cd aport-agent-guardrails && \
22
- git submodule update --init --recursive && \
23
- ./bin/openclaw
24
- ```
25
-
26
- *Already have the repo?* From the repo root run: `./bin/openclaw`
27
-
28
- ---
29
-
30
- ## Why Use the Plugin?
31
-
32
- | Approach | Deterministic? | Bypass Risk | Security Level |
33
- |----------|----------------|-------------|----------------|
34
- | **OpenClaw Plugin** ✅ | Yes | None | 🟢 Secure |
35
- | AGENTS.md prompts | No | High | 🔴 Not secure |
36
-
37
- **Bottom line:** With the plugin, the platform enforces policy before every tool execution. The AI cannot bypass it.
38
-
39
- ---
40
-
41
- ## Installation (Automatic)
42
-
43
- **Recommended:** Use `npx @aporthq/aport-agent-guardrails` (see top of this doc). If you cloned the repo instead, from the repo root run:
44
-
45
- ```bash
46
- ./bin/openclaw
47
- ```
48
-
49
- The script will:
50
- 1. Ask for your OpenClaw config directory (default `~/.openclaw`)
51
- 2. Create your passport (OAP v1.0) there
52
- 3. Prompt to install the APort OpenClaw plugin
53
- 4. Ask for mode (default: **API**; or local) and generate `config.yaml` with plugin settings (passport path, guardrail script path, apiUrl for API mode)
54
- 5. Install guardrail wrappers in the config dir’s `.skills/` (including `aport-guardrail-bash.sh` used by the plugin in local mode)
55
- 6. **Update your passport** — the installer sets `allowed_commands: ["*"]` automatically so normal exec works with no manual editing. You only need to edit the passport later if you want to restrict commands more tightly.
56
- 7. Run a **self-check** (guardrail invoked the same way OpenClaw will use it); if it’s denied, the script exits with a clear message so you know the setup is incomplete.
57
- 8. Optionally install the APort skill and AGENTS.md rule, and run a smoke test
58
- 9. Verify plugin installation
59
-
60
- **That's it!** Start OpenClaw with that config (e.g. `openclaw gateway start --config ~/.openclaw/config.yaml`). The plugin will enforce policies on every tool call; no extra steps required.
61
-
62
- ---
63
-
64
- ## Installation (Manual)
65
-
66
- If you prefer manual installation:
67
-
68
- ### 1. Create Passport
69
-
70
- ```bash
71
- ./bin/aport-create-passport.sh --output ~/.openclaw/aport/passport.json
72
- ```
73
-
74
- ### 2. Install Plugin
75
-
76
- ```bash
77
- openclaw plugins install -l /path/to/aport-agent-guardrails/extensions/openclaw-aport
78
- ```
79
-
80
- ### 3. Configure Plugin
81
-
82
- Create or edit `~/.openclaw/config.yaml`:
83
-
84
- ```yaml
85
- plugins:
86
- enabled: true
87
- entries:
88
- openclaw-aport:
89
- enabled: true
90
- config:
91
- # Mode: "api" (default, recommended) or "local" (guardrail script, no network)
92
- mode: api
93
-
94
- # Passport file location
95
- passportFile: ~/.openclaw/aport/passport.json
96
-
97
- # For local mode: path to guardrail script
98
- guardrailScript: ~/.openclaw/.skills/aport-guardrail-bash.sh
99
-
100
- # Fail-closed: block on error (default: true)
101
- failClosed: true
102
- ```
103
-
104
- For **API mode (default)**, set:
105
- ```yaml
106
- mode: api
107
- apiUrl: https://api.aport.io
108
- ```
109
- Set `APORT_API_KEY` in the environment if your API requires auth. Do not put `${APORT_API_KEY}` in the config file (OpenClaw will require the var to exist at load time).
110
-
111
- ### 4. Install Guardrail Scripts (local mode only)
112
-
113
- If you **did not** run `./bin/openclaw`, you need the guardrail script for local mode. If you **did** run the setup script, it already created `CONFIG_DIR/.skills/aport-guardrail-bash.sh`; skip this step.
114
-
115
- Otherwise:
116
-
117
- ```bash
118
- mkdir -p ~/.openclaw/.skills
119
- # Create wrapper that points to this repo (replace /path/to with real path)
120
- cat > ~/.openclaw/.skills/aport-guardrail-bash.sh << 'EOF'
121
- #!/bin/bash
122
- APORT_REPO_ROOT="/path/to/aport-agent-guardrails"
123
- export OPENCLAW_PASSPORT_FILE="${OPENCLAW_PASSPORT_FILE:-$HOME/.openclaw/aport/passport.json}"
124
- export OPENCLAW_DECISION_FILE="${OPENCLAW_DECISION_FILE:-$HOME/.openclaw/aport/decision.json}"
125
- exec "$APORT_REPO_ROOT/bin/aport-guardrail-bash.sh" "$@"
126
- EOF
127
- chmod +x ~/.openclaw/.skills/aport-guardrail-bash.sh
128
- ```
129
-
130
- ### 5. Verify Installation
11
+ Hosted passport:
131
12
 
132
13
  ```bash
133
- # Check plugin is installed
134
- openclaw plugins list | grep openclaw-aport
135
-
136
- # Should show: openclaw-aport (enabled)
137
- ```
138
-
139
- ---
140
-
141
- ## How It Works
142
-
143
- ```
144
- User → AI: "Delete all log files"
145
-
146
- OpenClaw: AI wants to use tool "exec.run"
147
-
148
- Platform: Fires before_tool_call hook
149
-
150
- APort Plugin: Maps "exec.run" → "system.command.execute.v1"
151
-
152
- APort Plugin: Calls guardrail script/API
153
-
154
- Guardrail: Evaluates against passport + limits
155
-
156
- ┌──────────┴──────────┐
157
- │ │
158
- ALLOW DENY
159
- │ │
160
- ↓ ↓
161
- Tool executes Returns { block: true, blockReason }
162
-
163
- OpenClaw throws error
164
-
165
- Tool NEVER executes
14
+ npx @aporthq/aport-agent-guardrails openclaw ap_your_agent_id
166
15
  ```
167
16
 
168
- **Key:** The platform enforces policy. The AI cannot skip this check.
17
+ No repo clone is required.
169
18
 
170
- ---
19
+ ## What the setup command does
171
20
 
172
- ## Testing
21
+ 1. Prompts for your OpenClaw config directory
22
+ 2. Creates a local passport or wires a hosted `agent_id`
23
+ 3. Installs the `openclaw-aport` plugin with `openclaw plugins install -l ...`
24
+ 4. Writes plugin config into `config.yaml` and `openclaw.json`
25
+ 5. Installs `aport-*` wrappers under `CONFIG_DIR/.skills/`
26
+ 6. Runs a smoke test so you know the setup is complete
173
27
 
174
- ### 1. Start OpenClaw with Plugin
28
+ After setup, start OpenClaw with the generated config:
175
29
 
176
30
  ```bash
177
31
  openclaw gateway start --config ~/.openclaw/config.yaml
178
32
  ```
179
33
 
180
- ### 2. Test Allowed Action
181
-
182
- Try a simple command that should be allowed:
183
-
184
- ```bash
185
- # Via OpenClaw agent
186
- "Run: node --version"
187
- ```
188
-
189
- Expected: Command executes (allowed by passport limits)
190
-
191
- ### 3. Test Denied Action
192
-
193
- Try a command that exceeds your passport limits:
194
-
195
- ```bash
196
- # Via OpenClaw agent
197
- "Delete all files in /tmp"
198
- ```
199
-
200
- Expected: Tool blocked with message:
201
- ```
202
- 🛡️ APort Policy Denied
34
+ ## What gets installed
203
35
 
204
- Policy: system.command.execute.v1
205
- Reason: Command exceeds allowed scope
206
-
207
- To override, update your passport at: ~/.openclaw/aport/passport.json (or ~/.openclaw/passport.json for legacy)
208
- ```
209
-
210
- ---
36
+ - `~/.openclaw/aport/passport.json` for local passport mode
37
+ - `~/.openclaw/config.yaml` with `plugins.entries.openclaw-aport`
38
+ - `~/.openclaw/openclaw.json` with matching plugin entry
39
+ - `~/.openclaw/.skills/aport-*` wrappers for manual checks and shell tooling
211
40
 
212
41
  ## Modes
213
42
 
214
- **API mode** is still the default and recommended. **Local mode** now has full parity with API for exec mapping (fixed); both evaluate the same policies. Messaging runs at assurance L0 by default.
215
-
216
- ### API Mode (default, recommended)
217
-
218
- **Best for:** Production, full OAP policy (JSON Schema, assurance, evaluation rules), signed decisions, cloud kill switch, audit logs.
219
-
220
- ```yaml
221
- config:
222
- mode: api
223
- passportFile: ~/.openclaw/aport/passport.json
224
- apiUrl: https://api.aport.io
225
- ```
226
- Set `APORT_API_KEY` in the environment only if your API requires auth.
227
-
228
- **How it works:**
229
- - Plugin loads local passport
230
- - Sends passport + context to APort API
231
- - API evaluates (passport NOT stored, stateless)
232
- - Returns signed decision
233
- - **Network required**
234
-
235
- ### Local Mode
236
-
237
- **Best for:** Privacy, offline use, no network dependency
238
-
239
- ```yaml
240
- config:
241
- mode: local
242
- passportFile: ~/.openclaw/aport/passport.json
243
- guardrailScript: ~/.openclaw/.skills/aport-guardrail-bash.sh
244
- ```
245
-
246
- **How it works:**
247
- - Plugin calls local bash script
248
- - Script evaluates policy using local passport (subset of OAP; see [Verification methods](VERIFICATION_METHODS.md))
249
- - Returns decision (exit 0 = allow, exit 1 = deny)
250
- - **No network required**
251
-
252
- ---
253
-
254
- ## Troubleshooting
255
-
256
- ### Plugin not loading
257
-
258
- ```bash
259
- # Check plugin list
260
- openclaw plugins list
261
-
262
- # Should show: openclaw-aport (enabled)
263
- ```
264
-
265
- If not listed:
266
- 1. Verify installation: `openclaw plugins install -l /path/to/extensions/openclaw-aport`
267
- 2. Check config.yaml has `plugins.entries.openclaw-aport.enabled: true`
268
- 3. Restart OpenClaw gateway
269
-
270
- ### Tools not being blocked
271
-
272
- Check:
273
- 1. **Plugin enabled?** `openclaw plugins list` should show `openclaw-aport (enabled)`
274
- 2. **Tool mapped?** See tool-to-policy mapping in plugin README
275
- 3. **Passport allows it?** The installer sets `allowed_commands: ["*"]` by default. If you intentionally tightened the allowlist, re-add the commands you need to `limits.system.command.execute.allowed_commands` in your passport.
276
- 4. **Script working?** Test directly:
277
- ```bash
278
- ~/.openclaw/.skills/aport-guardrail-bash.sh system.command.execute '{"command":"ls"}'
279
- ```
280
-
281
- ### Error: "Failed to run guardrail script"
282
-
283
- Check:
284
- 1. Script exists: `ls -l ~/.openclaw/.skills/aport-guardrail-bash.sh`
285
- 2. Script executable: `chmod +x ~/.openclaw/.skills/aport-guardrail-bash.sh`
286
- 3. Script works: Run test command above
287
-
288
- ### Guardrail DENY / `oap.passport_version_mismatch`
289
-
290
- If the guardrail denies every call and `~/.openclaw/aport/decision.json` (or `~/.openclaw/decision.json`) shows reason `oap.passport_version_mismatch` ("Passport spec version is 'unknown', expected 'oap/1.0'"):
291
-
292
- 1. **Passport must have `spec_version: "oap/1.0"`** (OAP spec). If your passport has only `"version": "1.0.0"` in metadata and no top-level `spec_version`, it was created by an older or non–spec-compliant tool.
293
- 2. **Limits must be nested per capability.** The verifier expects e.g. `limits["system.command.execute"]` with `allowed_commands`, `blocked_patterns`, not a flat `limits.allowed_commands` at the top level.
294
-
295
- **Fix:** Re-run the installer so it can normalize the passport:
296
-
297
- ```bash
298
- npx @aporthq/aport-agent-guardrails
299
- ```
300
-
301
- Choose to overwrite the existing passport when prompted, or run the wizard with `--output` to a new file. The installer now ensures `spec_version: "oap/1.0"` and nested limits. If you prefer to fix the file manually, add `"spec_version": "oap/1.0"` at the top level and move any top-level `allowed_commands` / `blocked_patterns` under `limits["system.command.execute"]`. See [agent-passport/spec/oap](https://github.com/aporthq/agent-passport/tree/main/spec/oap) for the canonical schema.
302
-
303
- ---
304
-
305
- ## Configuration Reference
43
+ ### API mode
306
44
 
307
- ### Minimum Configuration (API mode — default)
45
+ Recommended for production.
308
46
 
309
47
  ```yaml
310
48
  plugins:
@@ -319,33 +57,11 @@ plugins:
319
57
  failClosed: true
320
58
  ```
321
59
 
322
- ### Full Configuration (API mode)
60
+ Hosted passports use `agentId` instead of `passportFile`.
323
61
 
324
- ```yaml
325
- plugins:
326
- enabled: true
327
- entries:
328
- openclaw-aport:
329
- enabled: true
330
- config:
331
- # Mode: "api" (default) or "local"
332
- mode: api
333
-
334
- # Passport file location
335
- passportFile: ~/.openclaw/aport/passport.json
336
-
337
- # For local mode: path to guardrail script
338
- guardrailScript: ~/.openclaw/.skills/aport-guardrail-bash.sh
339
-
340
- # For API mode: APort API endpoint
341
- apiUrl: https://api.aport.io # or your self-hosted API URL
342
- # Optional: set APORT_API_KEY in the environment if your API requires auth
343
-
344
- # Fail-closed: block on error (default: true)
345
- failClosed: true
346
- ```
62
+ ### Local mode
347
63
 
348
- ### Minimum Configuration (Local mode)
64
+ Best for offline or privacy-sensitive workflows.
349
65
 
350
66
  ```yaml
351
67
  plugins:
@@ -356,115 +72,33 @@ plugins:
356
72
  config:
357
73
  mode: local
358
74
  passportFile: ~/.openclaw/aport/passport.json
359
- guardrailScript: ~/.openclaw/.skills/aport-guardrail-bash.sh
360
75
  failClosed: true
361
76
  ```
362
77
 
363
- ---
78
+ Current plugin versions use a built-in JavaScript evaluator in local mode. The setup command still installs `aport-guardrail-bash.sh` for manual smoke tests and shell tooling, but the plugin does not depend on `child_process` or the bash script for local-mode enforcement.
364
79
 
365
- ## Tool-to-Policy Mapping
80
+ ## Development install
366
81
 
367
- The plugin automatically maps OpenClaw tool names to APort policy packs:
368
-
369
- | OpenClaw Tool | APort Policy |
370
- |---------------|--------------|
371
- | `git.create_pr`, `git.merge`, `git.push` | `code.repository.merge.v1` |
372
- | `exec.run`, `system.command.*`, `bash` | `system.command.execute.v1` |
373
- | `message.send`, `messaging.*` | `messaging.message.send.v1` |
374
- | `mcp.*` | `mcp.tool.execute.v1` |
375
- | `session.create` | `agent.session.create.v1` |
376
- | `tool.register` | `agent.tool.register.v1` |
377
- | `payment.refund` | `finance.payment.refund.v1` |
378
- | `payment.charge` | `finance.payment.charge.v1` |
379
- | `data.export` | `data.export.create.v1` |
380
-
381
- Unmapped tools are allowed (fail-open for flexibility).
382
-
383
- ---
384
-
385
- ## Security Considerations
386
-
387
- ### Fail-Closed by Default
388
-
389
- By default, `failClosed: true` means **any error blocks the tool**:
390
- - Script not found → BLOCK
391
- - API unreachable → BLOCK
392
- - Invalid passport → BLOCK
393
-
394
- This is secure-by-default. To fail-open (not recommended):
395
-
396
- ```yaml
397
- config:
398
- failClosed: false # Allow on error (NOT RECOMMENDED)
399
- ```
82
+ If you are developing from a local checkout:
400
83
 
401
- ### Plugin Trust
402
-
403
- Plugins run **in-process** with full access to OpenClaw. Only install from trusted sources:
404
- - Official APort plugin (this)
405
- - Your own forks/modifications
406
-
407
- Use `plugins.allow` allowlist in config.yaml:
408
-
409
- ```yaml
410
- plugins:
411
- allow:
412
- - openclaw-aport
413
- - your-other-trusted-plugin
84
+ ```bash
85
+ openclaw plugins install -l /path/to/aport-agent-guardrails/extensions/openclaw-aport
414
86
  ```
415
87
 
416
- ### Bypass Prevention
417
-
418
- **With plugin:** AI **cannot** bypass policy enforcement. The platform calls `before_tool_call` before every tool.
419
-
420
- **Without plugin (AGENTS.md only):** AI **can** bypass via:
421
- - Prompt injection
422
- - Forgetting to call guardrail
423
- - Deciding action is "safe"
424
-
425
- **Bottom line:** Plugin = deterministic. AGENTS.md = best-effort (not secure).
426
-
427
- ---
428
-
429
- ## Next Steps
430
-
431
- 1. **Run the setup (once):** From repo root: `./bin/openclaw`. Use the default config dir or choose a path.
432
- 2. **Choose "yes"** when prompted to install the plugin.
433
- 3. **Start OpenClaw** with the generated config: `openclaw gateway start --config <your-config-dir>/config.yaml` (e.g. `~/.openclaw/config.yaml`).
434
- 4. **Test enforcement:** Run the agent; try an allowed action (e.g. `node --version`) and one that should be blocked by your passport (e.g. `rm -rf /`). The plugin blocks before the tool runs.
435
- 5. **Customize passport:** Edit `<config-dir>/aport/passport.json` (or `<config-dir>/passport.json` for legacy) to adjust limits and allowed commands.
436
-
437
- ---
438
-
439
- ## Support
440
-
441
- - **Full documentation:** [`extensions/openclaw-aport/README.md`](../extensions/openclaw-aport/README.md)
442
- - **Issues:** [GitHub Issues](https://github.com/aporthq/aport-agent-guardrails/issues)
443
- - **Discord:** [discord.gg/aport](https://discord.gg/aport)
444
-
445
- ---
446
-
447
- ## Summary
448
-
449
- ✅ **One command:** Run `./bin/openclaw` from the repo root to create passport, install plugin, write config and wrappers, and verify. You only need this once per config dir.
450
- ✅ **Deterministic enforcement:** The plugin runs before every tool; the platform enforces, the AI cannot bypass.
451
- ✅ **Fail-closed:** Blocks on error by default.
452
- ✅ **API (default) or local:** Full OAP via API, or local script for offline/privacy.
453
- ✅ **Zero OpenClaw core changes:** Uses the existing OpenClaw plugin API.
88
+ Public users should prefer the `npx @aporthq/aport-agent-guardrails openclaw` path.
454
89
 
455
- **After setup, start OpenClaw with the generated config—your agent is then secured by APort policy.**
90
+ ## Runtime behavior
456
91
 
457
- ---
92
+ On every tool call:
458
93
 
459
- ## How it all fits together
94
+ 1. OpenClaw fires `before_tool_call`
95
+ 2. APort maps the OpenClaw tool to an OAP policy pack
96
+ 3. APort evaluates the passport and limits
97
+ 4. `allow` lets the tool run
98
+ 5. `deny` returns `block: true` and the tool never executes
460
99
 
461
- | Step | What happens |
462
- |------|----------------|
463
- | You run `./bin/openclaw` | Script asks for config dir, creates passport, installs plugin, writes `config.yaml`, installs wrappers in `<config-dir>/.skills/`, and **updates the passport** with default `allowed_commands` (bash, sh, ls, mkdir, npm, etc.) so normal exec works. |
464
- | `config.yaml` | Contains `passportFile` and `guardrailScript` pointing to `<config-dir>/aport/passport.json` and `<config-dir>/.skills/aport-guardrail-bash.sh`. |
465
- | Passport allowlist | The installer sets `allowed_commands: ["*"]` automatically. No manual editing needed unless you want to restrict commands. |
466
- | Wrapper script | `<config-dir>/.skills/aport-guardrail-bash.sh` is a small script that calls this repo’s `bin/aport-guardrail-bash.sh` with the same args and env (passport path, etc.). |
467
- | You start OpenClaw | `openclaw gateway start --config <config-dir>/config.yaml` (or use that config when running the agent). |
468
- | On every tool call | OpenClaw runs the plugin’s `before_tool_call` hook → plugin calls the guardrail script with tool name and params → script evaluates against passport and policy → allow = tool runs, deny = plugin returns `block: true` and the tool never runs. |
100
+ ## Notes
469
101
 
470
- **So: one run of `./bin/openclaw` is all you need.** No manual editing of config or wrapper paths if you use the default config dir.
102
+ - Current public OpenClaw integration is plugin-based
103
+ - No upstream native guardrail-provider merge is required for this path
104
+ - If setup cannot install the plugin, it now stops immediately instead of writing broken config
package/docs/RELEASE.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Release process and version policy
2
2
 
3
- **Current release:** 1.0.21 (see [CHANGELOG.md](../CHANGELOG.md)).
3
+ **Current release:** 1.0.22 (see [CHANGELOG.md](../CHANGELOG.md)).
4
4
 
5
5
  We keep **one version number** across all published packages (Node core, Python core, and every framework adapter). That avoids “core is 1.2 but CLI is 0.9” and keeps the story simple for users and support.
6
6
 
@@ -52,7 +52,8 @@ So: **root = CLI/setup**; **core = library**. We publish core so that (1) the ad
52
52
  ```
53
53
  5. **CI (`.github/workflows/release.yml`)**: on tag push `v*`:
54
54
  - **publish-npm**: publishes the **root** package `@aporthq/aport-agent-guardrails` (CLI) and workspace packages `@aporthq/aport-agent-guardrails-core`, `-langchain`, `-crewai`, `-cursor`, `-claude-code`, and `@aporthq/openclaw-aport` to npm. The **n8n** package is not published yet (coming soon). Uses `NPM_TOKEN` secret.
55
- - **publish-python**: builds and publishes `aport-agent-guardrails`, `aport-agent-guardrails-langchain`, and `aport-agent-guardrails-crewai` to PyPI (uses `PYPI_TOKEN` secret). Skips upload if aport-agent-guardrails version already exists.
55
+ - **publish-python**: builds and publishes `aport-agent-guardrails`, `aport-agent-guardrails-langchain`, and `aport-agent-guardrails-crewai` to PyPI (uses `PYPI_TOKEN` secret). Uploads use `--skip-existing`, so reruns or recovery releases can still publish any missing Python artifacts for the same version.
56
+ - **workflow_dispatch**: supports release recovery for an existing version after workflow fixes land on `main`.
56
57
  - **create-release**: creates the GitHub Release with install notes for both ecosystems.
57
58
 
58
59
  **PyPI**: In [PyPI project settings](https://pypi.org/help/#project-urls), set Repository and (if using trusted publishing) add this repo and workflow name **Release**. Otherwise configure the `PYPI_TOKEN` secret in the GitHub repo.