@burtson-labs/bandit-stealth-cli 1.7.368 → 1.7.370

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 (3) hide show
  1. package/README.md +95 -2
  2. package/dist/cli.js +1092 -1072
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -74,7 +74,7 @@ That's it. No API keys. No cloud services. The agent reads your code, searches,
74
74
  - **Project memory** — drop a `BANDIT.md` or `CLAUDE.md` at your workspace root and it's auto-loaded into the system prompt
75
75
  - **File + image mentions** — `@path` auto-inlines files; images are either sent multimodally or OCR'd locally (Apple Vision / tesseract)
76
76
  - **Clipboard paste** — `Ctrl+V` in the REPL pastes an image straight from your clipboard
77
- - **Hooks** — `PreToolUse` / `PostToolUse` / `Stop` shell hooks via `.bandit/settings.json`
77
+ - **Hooks + security guard** — `PreToolUse` / `PostToolUse` / `Stop` shell hooks (global `~/.bandit/settings.json` or per-workspace), plus an opt-in built-in guard that blocks catastrophic commands. See [Settings file](#settings-file--hooks-permissions-security-guard)
78
78
  - **12 themes** — Stealth Light/Dark, Midnight, Onyx, Charcoal, Dracula, Nord, Tokyo Night, Solarized Dark/Light, Catppuccin Mocha, Sepia. `/theme` to pick
79
79
  - **Cross-platform** — macOS, Linux, Windows; Windows `.cmd`/`.bat` shims (npm/npx/pnpm/tsc) resolved correctly
80
80
  - **Update-aware** — fire-and-forget npm-registry check at boot; `update vX.Y.Z available` shows in the status bar when a newer CLI is published
@@ -263,8 +263,99 @@ Workspace config overrides user config. Secrets belong in the user-level file, n
263
263
  | `OLLAMA_URL` | `http://localhost:11434` | Ollama endpoint |
264
264
  | `BANDIT_MAX_ITERATIONS` | `20` | Tool-use loop cap |
265
265
  | `BANDIT_AUTO_APPROVE` | `0` | `1`/`true` to skip write-approval prompts |
266
+ | `BANDIT_TELEMETRY` | `0` | `1`/`true` to enable OTLP telemetry (opt-in) |
267
+ | `BANDIT_OTLP_ENDPOINT` | `https://otlp.burtson.ai` | OTLP/HTTP collector base URL |
268
+ | `BANDIT_OTLP_TOKEN` | — | Bearer token for the collector (defaults to your Bandit token) |
269
+ | `BANDIT_OTLP_MODE` | `metrics+traces` | `metrics-only` to drop span payloads |
266
270
  | `NO_COLOR` | — | Disable ANSI colors |
267
271
 
272
+ ### Settings file — hooks, permissions, security guard
273
+
274
+ Separate from `config.json`, a **settings** file controls what the agent is allowed to do. It's read from two places and **merged** — the global file applies to every repo, the workspace file adds project-specific rules on top:
275
+
276
+ - `~/.bandit/settings.json` — global (all workspaces)
277
+ - `<workspace>/.bandit/settings.json` (and `.bandit/settings.local.json`) — per-project
278
+
279
+ ```jsonc
280
+ {
281
+ // Built-in pre-tool security guard. OPT-IN, off by default. Blocks the
282
+ // handful of tool calls that are almost never legitimate, BEFORE they run —
283
+ // a safety net against the model footgunning (e.g. a hallucinated rm -rf /).
284
+ "security": {
285
+ "guard": {
286
+ "enabled": true,
287
+ "blockCommands": ["npm\\s+publish"], // optional: extra regex patterns to block
288
+ "protectPaths": ["/data/prod"] // optional: extra write-protected path prefixes
289
+ }
290
+ },
291
+
292
+ // Your own shell hooks around the tool loop. A non-zero exit from a
293
+ // PreToolUse hook BLOCKS the tool call. Placeholders: {{name}}, {{primary}},
294
+ // {{duration}} (PostToolUse only).
295
+ "hooks": {
296
+ "PreToolUse": [{ "match": "write_file", "command": "./scripts/guard.sh {{name}}" }],
297
+ "PostToolUse": [{ "match": ".*", "command": "echo {{name}} took {{duration}}ms" }],
298
+ "Stop": [{ "command": "./scripts/notify-done.sh" }]
299
+ },
300
+
301
+ // Per-tool permission policy (deny > allow > ask > built-in defaults).
302
+ "permissions": { "allow": ["run_command:git *"], "deny": [], "ask": ["run_command"] }
303
+ }
304
+ ```
305
+
306
+ **What the guard blocks when enabled** (high-confidence patterns only, so false positives stay rare):
307
+ catastrophic `rm -rf /` · `~` · `/*` · a remote script piped to a shell (`curl … | sh`) · raw disk writes (`dd of=/dev/sda`, `mkfs`) · fork bombs · recursive `chmod`/`chown` on `/` · writes or redirects into system/credential paths (`/etc`, `~/.ssh`, `~/.aws`, …) · reading a credential file **and** sending it over the network in one command.
308
+
309
+ The guard is **defense-in-depth against the model**, not a sandbox and not protection against a malicious user (who controls this file). It runs **before** your hooks and the approval gate, and behaves identically in the CLI and the IDE extension.
310
+
311
+ #### Hooks — any scripted step, not just guardrails
312
+
313
+ Hooks run **your own commands** at three points in the loop. Only `PreToolUse` is a gate; the rest are fire-and-forget side effects — so reach for them for version bumps, formatters, notifications, CI triggers, anything scriptable.
314
+
315
+ | Event | Fires | Blocks the tool? |
316
+ |---|---|---|
317
+ | `PreToolUse` | before a tool runs | **Yes** — a non-zero exit aborts the call (this is the guardrail path) |
318
+ | `PostToolUse` | after a tool finishes | No — runs for its side effect |
319
+ | `Stop` | when the turn ends | No |
320
+
321
+ Each rule is `{ "match": "<regex on tool name — omit to match all>", "command": "<shell>", "timeout": 10000 }`. Placeholders are substituted into `command` (shell-escaped): **`{{name}}`** (tool name), **`{{primary}}`** (first arg — path / cmd / pattern / url), **`{{duration}}`** (ms, `PostToolUse` only).
322
+
323
+ ```jsonc
324
+ "hooks": {
325
+ // guardrail: refuse edits to a generated file
326
+ "PreToolUse": [{ "match": "write_file|apply_edit", "command": "grep -q '@generated' {{primary}} && exit 1 || exit 0" }],
327
+ // housekeeping: format after every edit; bump the build number after any tool
328
+ "PostToolUse": [
329
+ { "match": "write_file|apply_edit", "command": "prettier --write {{primary}} || true" },
330
+ { "match": ".*", "command": "./scripts/bump-build-number.sh {{name}}" }
331
+ ],
332
+ // notify when a turn ends
333
+ "Stop": [{ "command": "terminal-notifier -message 'Bandit finished' || true" }]
334
+ }
335
+ ```
336
+
337
+ ### Telemetry (opt-in)
338
+
339
+ Off by default. When enabled, Bandit emits **OpenTelemetry** over OTLP/HTTP: one **trace per turn** (LLM + tool calls as spans, errors marked) plus **usage metrics** (tokens, time-to-first-token, turn duration). The wire format is standard OTLP, so **you point it at your own collector** — Grafana/Tempo, an OpenTelemetry Collector, App Insights, Datadog, anything that speaks OTLP/HTTP.
340
+
341
+ > **Where does it go?** You decide. Set `endpoint` to your collector. The example below uses `otlp.burtson.ai` — that's **Burtson's** hosted collector and only accepts Bandit Cloud accounts; if you're not a Bandit Cloud user, point `endpoint` at your own and set your own `headers`.
342
+
343
+ ```jsonc
344
+ // ~/.bandit/config.json
345
+ {
346
+ "telemetry": {
347
+ "enabled": true,
348
+ "endpoint": "https://otel.your-company.com", // YOUR OTLP collector (otlp.burtson.ai = Bandit Cloud only)
349
+ "mode": "metrics+traces", // or "metrics-only" for stricter privacy
350
+ "headers": { "Authorization": "Bearer ..." } // your collector's auth (defaults to your Bandit token)
351
+ }
352
+ }
353
+ ```
354
+
355
+ The default `endpoint` is `https://otlp.burtson.ai` only because the default audience is Bandit Cloud; **set your own** otherwise.
356
+
357
+ **Privacy:** prompt and completion **text is never sent** — only metadata (model, tool name, durations, token counts), and that metadata is run through secret redaction first. `metrics-only` drops traces entirely. Nothing is sent unless you set `enabled: true` (or `BANDIT_TELEMETRY=1`).
358
+
268
359
  ### Remote GPU
269
360
 
270
361
  Running a bigger model on a remote Ollama instance? Point `OLLAMA_URL` at the remote endpoint and set `BANDIT_MODEL` to the bigger model. Requests route to the remote node; everything else stays local.
@@ -314,7 +405,9 @@ Tear the pod down when you're done. ~$2/hr for an H100 SXM × 15-20 min agent se
314
405
  - **Local-first by default** — with `provider=ollama`, nothing leaves your machine.
315
406
  - **Approval gate** — all file writes show a unified diff before touching disk (unless `BANDIT_AUTO_APPROVE=1`).
316
407
  - **Command allowlist** — `run_command` only executes from an internal allowlist (git, gh, kubectl, helm, brew, standard *nix tools). Arbitrary shell is refused.
317
- - **Secret hygiene** — API keys are redacted in `/config` output and never logged.
408
+ - **Pre-tool security guard** (opt-in) enable `security.guard` in your [settings file](#settings-file--hooks-permissions-security-guard) to block catastrophic commands (`rm -rf /`, `curl … | sh`, disk wipes, credential exfil, writes to `/etc` or `~/.ssh`) before they run. Defense-in-depth against the model, applied in both CLI and IDE.
409
+ - **Custom hooks** — your own `PreToolUse` shell scripts can veto any tool call; configure globally (`~/.bandit/settings.json`) or per-project.
410
+ - **Secret hygiene** — API keys are redacted in `/config` output and never logged. The optional [telemetry](#telemetry-opt-in) exporter never sends prompt/response text and redacts metadata.
318
411
  - **Local sessions** — stored as JSONL under `~/.bandit/sessions/`. Inspect at any time.
319
412
 
320
413
  ---