Release v0.8.10 → prod (publish npm + PyPI) - #186
Merged
Merged
Conversation
…ands (sable-nf2i)
CommandInterceptor.evaluate() returned {allowed:true, requiresApproval:false}
for critical destructive commands (rm -rf /, fork bombs, dd to disk, mkfs, …)
whenever no commandPolicy was configured — which is the real-world default
(the user's ~/.rafter/config.json often omits agent.commandPolicy). The pretool
hook only denies on (!allowed && !requiresApproval) || requiresApproval, so
allowed=true+approval=false sailed straight through: a security CLI that did not
block `rm -rf /` by default.
Fix: add an UNCONDITIONAL critical-destructive hard-block at the very top of
evaluate(), before any policy is loaded, in both implementations. Critical
commands now always return allowed=false, requiresApproval=false — independent
of whether a policy exists or which mode is set (allow-all and custom deny-lists
can no longer opt out of catastrophic commands). With no policy configured,
high-risk commands now fall back to requiring approval instead of allow-all.
- node/src/core/risk-rules.ts: add matchedCriticalPattern() helper
- python/rafter_cli/core/risk_rules.py: add match_critical_pattern() helper
- both interceptors: hard-block keyed on assessCommandRisk()=="critical",
surfacing the matched built-in pattern; exact node/python parity verified
(16/16 commands identical under the same config)
Updated the policy-mode tests that encoded the old (insecure) contract
(allow-all / custom deny-list / approve-dangerous permitting critical commands)
to assert the hard-block. Repairs the 13 red command-interceptor.test.ts cases,
the hook-integration "blocks rm -rf / even in a git repo" case, and the two
error-handling-gauntlet interceptor cases.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…block fix(security): unconditional hard-block for critical destructive commands (sable-nf2i)
…son)
Claude Code appends `--hook-json <data>` to the hook command at invocation; both
CLIs rejected it as an unknown option and exited non-zero, breaking the hook.
Hook input comes from stdin, so the extra flag (and its value) is unused and
safe to discard.
- Node: `.allowUnknownOption()` + `.allowExcessArguments()` on BOTH the pretool
and posttool Commander subcommands (the `<data>` value lands as an excess arg,
so allowUnknownOption alone isn't enough).
- Python: `context_settings={allow_extra_args, ignore_unknown_options}` on the
pretool/posttool `@hook_app.command(...)` decorators. (Setting it on the
hook_app *group* — the prior approach — does NOT reach subcommand parsing, so
`--hook-json` was still rejected; verified the group-only fix fails.)
Declared options like `--format` are still parsed normally. Adds Node + Python
regression tests covering: --hook-json tolerated on pretool & posttool, --format
still honored (not swallowed), and unchanged no-flag behavior. CLI_SPEC.md
documents the tolerance.
Supersedes the original #180 branch (which had no merge-base with main and
bundled an unrelated docs/vitest-upgrade history); re-applied cleanly on main.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…-json) fix(hook): tolerate --hook-json flag from Claude Code harness
…te|Edit|MultiEdit rafter agent init --with-claude-code (and agent enable claude-code.hooks) registered the `rafter hook posttool` redaction hook with a catch-all `.*` matcher, so it fired after EVERY Claude Code tool call — including Read and MCP tools, which never produce secrets to redact — adding latency to every operation. Narrow the matcher to the tools whose output is worth scanning: shell output (Bash) and file writes (Write/Edit/MultiEdit). Changed in both install paths per language (init/legacy + component spec), keeping Node and Python identical. PreToolUse matchers are unchanged. Scope is Claude Code only. Codex (.* PostToolUse) and Gemini (.* AfterTool) have the same broad-matcher latency issue and are tracked separately in sable-4alt for platform-correct narrow matchers. Docs (SKILL.md, PLATFORM_PARITY_AUDIT.md, CHANGELOG) and test expectations updated; a PostToolUse-matcher assertion added to the Python install test to mirror the Node coverage. Closes sable-h0ah Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…posttool-matcher fix(claude-code): narrow PostToolUse hook matcher from .* to Bash|Write|Edit|MultiEdit (sable-h0ah)
…ening) (#184) Triage + remediation of the Rafter scan on main (bead sable-qsig). The large majority of the 780 findings are context-blind SAST false positives for a local CLI (fs/path ops on the user's own filesystem, an XXE rule firing on code that parses no XML, status-string compares flagged as timing attacks, git-diff parsing flagged as URL validation) and intentional demo/fixture secrets. Those are documented and suppressed in a new repo-root .rafter.yml — each entry traced input->sink first, honored by both the local engines and remote `rafter run`. Real fixes applied: - Node dependency CVE bumps via pnpm workspace overrides + direct deps, re-locked: axios 1.13.6->1.18.1, hono 4.12.8->4.12.27, tar ->7.5.17, js-yaml ->4.3.0, fast-uri, path-to-regexp, form-data, follow-redirects, ip-address, qs, brace-expansion all bumped past their fixed versions (~50 CVEs). tsc build clean; affected suites pass. - Python direct-dep floors bumped in pyproject (requests ^2.33.0, urllib3 >=2.7.0, python-dotenv ^1.2.2). Transitive CVEs (via mcp) need `poetry lock` on a box with poetry -> tracked in sable-i7ll. - skill_remote.extract_npm_tarball: skip non-file/dir members (symlink/hardlink/ device) as defense-in-depth on top of the existing zip-slip guard. Local secrets rescan after: 0 active, 488 suppressed (all triaged fixtures). Refs sable-qsig. Follow-ups: sable-i7ll (python poetry lock), sable-ufd9 (backend FP rules behind GH #178/#182). Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Patch release bundling the unreleased changes on main since 0.8.9: - Claude Code PostToolUse matcher narrowed .* -> Bash|Write|Edit|MultiEdit (#183) - Hooks tolerate harness-appended flags, e.g. --hook-json (#180) - Dependency CVE re-lock (axios, hono, tar, js-yaml, +transitives) and remote-skill tarball extraction hardening (#184) Bumps node/package.json + python/pyproject.toml to 0.8.10 (parity), the rafter-security skill resource version (node + python), and finalizes the CHANGELOG 0.8.10 section. Refs sable-ehb1 Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Raftersecurity
approved these changes
Jun 28, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Promote
main→prodto publish v0.8.10 to npm (@rafter-security/cli) and PyPI (rafter-cli).Shipping (since 0.8.9)
PostToolUsematcher narrowed.*→Bash|Write|Edit|MultiEdit--hook-json)Pre-flight
pnpm install --frozen-lockfileclean,tscclean,--version→ 0.8.10, no stray version refs.Merging this triggers
publish.yaml(tests gate → OIDC publish → post-publish smoke tests). Refs sable-ehb1.🤖 Generated with Claude Code