# security-review-writer ## Purpose This extension gives security-scan worker agents one constrained persistence tool for review artifacts. It atomically creates or overwrites UTF-8 text beneath the current project's `ai-workspace/security-reviews` directory. ## Scope The `security_review_writer` tool accepts a review-root-relative path or an absolute path already beneath the review root. It rejects outside paths, traversal segments, symbolic-link components, symbolic-link targets, directories, non-regular files, and parents that resolve outside the canonical review root. It creates missing real parent directories and commits complete content with an atomic same-directory rename. It activates during `session_start` in TUI, RPC, JSON, and headless print modes without startup filesystem or subprocess probes. ## Non-goals - This extension is not a general-purpose file writer. - This extension does not read review artifacts. - This extension does not perform or interpret security scans. - This extension does not override Pi's built-in `write` tool. - This extension does not write outside `ai-workspace/security-reviews`. ## Alternatives considered No validated catalog candidate matched the constrained security-review artifact writer topic. Repeating path checks in worker prompts was rejected because prompts cannot provide an enforceable filesystem boundary. Overriding built-in `write` was rejected because the workflow intentionally omits that built-in and requires a separately named constrained tool. ## Decision rationale A single purpose-built tool gives security-scan workers a stable least-authority write surface while preserving Pi's built-in tool namespace. Native Node filesystem APIs provide portable UTF-8 encoding, exclusive temporary-file creation, canonical path checks, abort propagation, and atomic rename without runtime dependencies or shell probes. ## Usage Load `security-review-writer` through the Ultra step's `dynamicExtensions` field. Omit built-in `write` from the worker's selected tools and call `security_review_writer` with `{ "path": "worker-id/review.md", "text": "..." }`. Relative paths are resolved beneath `ai-workspace/security-reviews`, while absolute paths must already be lexically contained by that root. On success the tool returns the root-relative path, UTF-8 byte count, and whether it replaced an existing regular file. Typed failures include an error code and an actionable hint, and abort signals are rethrown unchanged. ## Architecture `index.ts` synchronously registers exactly one tool and activates it from `session_start` without blocking startup. `core.ts` owns path resolution, canonical containment, directory and target inspection, symlink rejection, UTF-8 temporary-file persistence, durability sync, and atomic rename. The temporary file is created in the verified target directory with exclusive mode and is removed after failures or aborts before commit. `debug.ts` remains scaffold-identical, while `index.ts` emits bounded events that exclude review text and redact requested paths to shape metadata on failure. Compact rendering reports create or overwrite status, and expanded rendering adds the relative path, byte count, and atomic commit detail. ## Test matrix | Capability | Exact `node:test` case name | Coverage | | --- | --- | --- | | `security-review-write-atomic` | `security-review-write-atomic` | Relative create, contained absolute overwrite, UTF-8 content, and temporary-file cleanup. | | `security-review-path-containment` | `security-review-path-containment` | Absolute outside path, slash and backslash traversal, and directory target rejection. | | `security-review-symlink-defense` | `security-review-symlink-defense` | Escaping linked parent, direct linked target, outside-file preservation, and platform-supported link forms. | ## Promotion notes The stable catalog name is `security-review-writer` and the registered tool name is `security_review_writer`. Keep this package private until a human deliberately promotes it. Future revisions must preserve or tighten the 10 ms path-resolution hot-path budgets and retain the no-override contract.