From c7748bc2cf6e9f19093a91e307f9a9502739da9a Mon Sep 17 00:00:00 2001 From: Flo Date: Fri, 27 Mar 2026 14:26:19 +0100 Subject: [PATCH] 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) --- .../specs/2026-03-26-security-hooks-design.md | 22 ++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/docs/superpowers/specs/2026-03-26-security-hooks-design.md b/docs/superpowers/specs/2026-03-26-security-hooks-design.md index 62b1963..041dd17 100644 --- a/docs/superpowers/specs/2026-03-26-security-hooks-design.md +++ b/docs/superpowers/specs/2026-03-26-security-hooks-design.md @@ -58,7 +58,7 @@ security-hooks/ │ ├── bash.rules # bash command rules │ ├── edit.rules # file edit rules │ ├── mcp.rules # MCP tool rules -│ ├── post.rules # post-tool-use checks +│ ├── post.rules # post-tool-use checks (deferred, reserved) │ └── validators/ # complex Elixir validators │ ├── unknown_executable.ex │ ├── dependency_mutation.ex @@ -149,7 +149,14 @@ PreToolUse ask (tier: suspicious): } ``` -PostToolUse block (note: PostToolUse uses top-level `decision`/`reason` fields, unlike PreToolUse which nests under `hookSpecificOutput`): +PostToolUse responses (note: PostToolUse uses top-level `decision`/`reason` fields, unlike PreToolUse which nests under `hookSpecificOutput`): + +PostToolUse allow (no issues found): +```json +{} +``` + +PostToolUse block: ```json { "decision": "block", @@ -202,7 +209,7 @@ comment := '#' rule := tier SP name NL clauses tier := "block" | "suspicious" name := '"' '"' -clauses := matcher nudge [condition]* +clauses := matcher nudge matcher := match | match_any | match_not_in | validator match := INDENT "match " NL match_any := INDENT "match_any" NL (INDENT2 NL)+ @@ -279,7 +286,7 @@ Rules are evaluated in file order. First match wins. Place specific rules before **Tier: suspicious** - Edits to CI/CD config: `.github/workflows/`, `.gitlab-ci.yml`, `Jenkinsfile` - Edits to `Dockerfile`, `docker-compose.yml` -- Edits to lockfiles: `package-lock.json`, `mix.lock`, `Cargo.lock`, `poetry.lock` +- Edits to lockfiles: `package-lock.json`, `pnpm-lock.yaml`, `yarn.lock`, `mix.lock`, `Cargo.lock`, `poetry.lock`, `Gemfile.lock`, `go.sum`, `composer.lock` - Dependency field changes in manifest files (validator: `DependencyMutation`) ### mcp.rules @@ -344,6 +351,9 @@ sensitive = [ "/etc/passwd", ] +[meta] +version = "1.0.0" + [daemon] idle_timeout_minutes = 30 log_format = "jsonl" @@ -363,7 +373,7 @@ Merges on top of `config.toml`: **Starting:** The shell shim starts the daemon on first hook call. The daemon writes its PID to `$XDG_RUNTIME_DIR/security-hooks/pid` (Linux/WSL) or `$TMPDIR/security-hooks/pid` (macOS) and opens the Unix socket. First-ever startup with a Burrito binary may take 1-3 seconds (unpacking); subsequent starts are ~300ms (BEAM boot). The install script pre-warms the daemon to avoid first-call latency. -**Health check:** The shim checks socket connectivity. If the PID file exists but the socket is dead, the shim kills the stale process and restarts. +**Health check:** The shim checks socket connectivity. If the PID file exists but the socket is dead, the shim kills the stale process and restarts. If two sessions race to start the daemon simultaneously, the second will get `EADDRINUSE` — the shim handles this by retrying the socket connection (the first daemon won the race and is now available). **Idle shutdown:** The daemon exits after 30 minutes of inactivity (configurable via `daemon.idle_timeout_minutes`). Handles `SIGTERM` gracefully. @@ -376,6 +386,8 @@ Merges on top of `config.toml`: {"ts":"2026-03-26T14:02:05Z","event":"PreToolUse","tool":"Bash","input":"mix test","rule":null,"decision":"allow"} ``` +Log rotation and size limits are deferred — users can manage this with external tools (logrotate, etc.) since the log path is well-defined. + Future: streaming connectors for centralized logging (stdout, webhook, syslog). ## Installation