Commit Graph

9 Commits

Author SHA1 Message Date
Flo
7645402347 Replace bash shim with Rust binary
Bash shim had shell quoting risks and depended on socat/nc. Elixir
escript would pay ~300ms BEAM boot per invocation. A second Burrito
binary would unpack on every cold call. Rust gives <1ms startup,
proper timeout handling, and is already in the toolchain for the
tree-sitter NIF.

- Add shim/ Rust crate to directory structure
- Document Rust shim rationale (vs bash, escript, Burrito)
- Update Dependencies with shim crate deps (serde_json, stdlib Unix socket)
- Update install script, README, architecture diagram

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 12:28:18 +02:00
Flo
a133271a6c Address Daria's review: tree-sitter, path matching, MCP injection
Changes based on reviewer feedback:

- Promote tree-sitter-bash to primary parser recommendation (over bash
  Hex package). Battle-tested grammar, robust against adversarial input.
- Fix path matching: directory-boundary matching instead of string prefix.
  reads_file("~/.ssh") no longer matches ~/.ssh_backup/key.
- Tilde expansion uses HOME from hook payload, not daemon environment.
  Correct for containers, remote SSH.
- MCP parameter injection: replaced regex with McpParameterInjection
  validator that runs string values through BashAnalyzer for consistency.
- Regex safety: add 1ms evaluation timeout to prevent catastrophic
  backtracking. Timed-out regex falls through to AST pass.
- Document that regex rules can only deny/suspect, never allow.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 10:31:44 +02:00
Flo
8be22dac33 Add multi-tool support: Claude Code, Gemini CLI, Codex
- Add adapter layer with normalize_input/format_output per tool
- Define common internal payload and verdict formats
- Map event names across tools (PreToolUse/BeforeTool)
- Map payload fields across tools (tool_name, tool_input, cwd)
- Adapter-specific response formatting:
  - Claude: hookSpecificOutput.permissionDecision
  - Gemini: flat decision field
  - Codex: exit code 2 + stderr for deny
- Shell shim takes --adapter flag to select tool
- install.sh auto-detects all installed tools and registers hooks
- Hook registration examples for all three tools
- Add adapters/ directory to daemon source tree

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 10:11:08 +02:00
Flo
4c2226ae57 Address spec review iteration 4: config keys, match targets, launchd
Important fixes:
- Document config key resolution (allowed_executables -> executables.allowed,
  mcp_allowed_servers -> names from [[mcp.servers]])
- Clarify CLAUDE_PROJECT_DIR source (derived from payload cwd field)
- MCP rules: regex match_any operates on serialized tool_input, not tool_name
- Add with_args_matching semantics (joined argument string)

Suggestions also addressed:
- Fix launchd plist: use absolute paths, note install.sh expands placeholders
- Fix launchd socket path: use $TMPDIR for per-user isolation
- Rename SECURITY_HOOKS_CONFIG -> SECURITY_HOOKS_HOME (contains both
  rules/ and config/ subdirectories)
- Document directory discovery via single env var

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 21:11:26 +01:00
Flo
91911973d6 Address spec review iteration 3: parser strategy, semantics, examples
Critical:
- Add Bash Parser Strategy section with 3 options (bash Hex, tree-sitter,
  shlex) and validation plan for adversarial inputs
- Fix evaluation order: explicitly document strategy-grouped (regex first,
  then AST) rather than claiming pure file order

Important:
- Define reads_file, writes_file, sets_env detection semantics
- Define validator module behaviour/callback interface
- Add dual timeouts: 200ms steady-state, 3000ms cold start
- Define config.local.toml merge semantics for MCP servers (by name)
- Reframe "non-evasible" regex rules as "common pattern" detection
- Add XDG_RUNTIME_DIR unset fallback (/tmp/security-hooks-$UID/)
- Add match_server_not_in for MCP rules (clearer than overloading
  match_base_command_not_in)
- Add complete edit.rules and mcp.rules DSL examples

Suggestions:
- Add CLI commands: status, test, reload, log
- Note Burrito binary size expectations in parser strategy section

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 20:58:18 +01:00
Flo
e396632e2b Add hybrid daemon lifecycle: systemd, launchd, fallback
- Linux/WSL: systemd user service + socket activation for zero
  cold-start latency and automatic crash recovery
- macOS: launchd plist with KeepAlive and socket activation
- Fallback: shim-managed with lock file (containers, minimal VMs)
- Shell shim simplified — no longer manages daemon lifecycle
- Daemon detects inherited file descriptors for socket activation
- Add service/ directory with unit files and plist template
- Update install.sh to detect platform and install appropriate service

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 16:20:40 +01:00
Flo
c7748bc2cf Fix spec review iteration 2: grammar, config, response examples
- Remove deferred condition from grammar production
- Add [meta] version to config.toml example
- Add PostToolUse allow response (empty object)
- Mark post.rules as deferred in directory tree
- Complete lockfile list for all supported ecosystems
- Handle startup race condition (EADDRINUSE retry)
- Note log rotation as deferred

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 14:26:19 +01:00
Flo
0dca8797be Address spec review: fail-closed policy, validator security, match targets
Critical fixes:
- Fail-closed: shim returns deny if daemon unreachable
- Validators compiled into binary, not loaded dynamically
- Socket directory created with 0700 permissions

Important fixes:
- Document match target fields per hook type
- Note PreToolUse vs PostToolUse response format difference
- Defer only_when/except_when conditions to future version
- Add concrete match_base_command_not_in example
- Specify PID file locations
- Add versioning scheme for rules and config
- Defer post.rules linting to future version

Other:
- Clarify exfiltration rules (not blocking bare curl/wget)
- Add missing yarn to allowed executables
- Fix macOS socket path (avoid space in Application Support)
- Note Burrito first-run unpack latency
- Document existing hooks coexistence

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 13:00:10 +01:00
Flo
8d0ed3dd0d Add security hooks design spec
Defense-in-depth hooks for Claude Code: Elixir daemon with custom
.rules DSL, shell shim, JSONL logging, hot-reload, tiered
block/suspicious decisions.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 12:49:38 +01:00