Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
77 commits
Select commit Hold shift + click to select a range
9aaca93
chore(tests): prune excess tests in Node + Python suites
Rome-1 Oct 6, 2026
f28efd6
test: restore tests the prune removed but nothing else covered
Rome-1 Oct 6, 2026
a70c15c
fix(risk-rules): rate reverse shells critical in both runtimes
Rome-1 Oct 6, 2026
cc805fb
fix(config): read the Python CLI's snake_case config keys in Node
Rome-1 Oct 12, 2026
56bbe11
fix(report): accept the JSON that `rafter secrets --json` prints
Rome-1 Oct 12, 2026
e9b9c61
perf(patterns): compile each secret pattern once, not once per line
Rome-1 Oct 12, 2026
6c3792a
fix(run,get): say why a remote scan failed
Rome-1 Oct 12, 2026
a6cfc1b
fix(secrets): skip the same default directories in Node and Python
Rome-1 Oct 12, 2026
6d8e90c
fix(scan): don't crash on a staged diff over 1 MiB, and never report …
Rome-1 Oct 8, 2026
c3c4042
docs(skills): fix stale `rafter audit` references to `rafter agent au…
Rome-1 Oct 12, 2026
30b113d
fix(hook,exec): read the staged diff past 1 MiB so large commits are …
Rome-1 Oct 12, 2026
710fbbe
fix(hook): quote the suggested exec command safely for POSIX sh
Rome-1 Oct 12, 2026
438a2a9
fix(hook,exec): block a commit whose staged diff cannot be read
Rome-1 Oct 12, 2026
28c6c72
docs(agent): point skill-scanner help text at 'skill review --deep'
Rome-1 Oct 12, 2026
6adc47a
test: isolate both suites from the real HOME and the live backend (sa…
Rome-1 Oct 12, 2026
1ccc756
fix(python): fail closed when the staged diff cannot be read or decoded
Rome-1 Oct 12, 2026
f34f683
fix(secrets): betterleaks honors .gitignore; a timeout is an error, n…
Rome-1 Oct 12, 2026
c40717f
fix(audit): hash the whole last line when it exceeds 64 KB
Rome-1 Oct 2, 2026
1fe831e
fix(agent init): install rafter-skill-review and make --dry-run match…
Rome-1 Oct 12, 2026
890d300
fix(agent): count only configured integrations as core checks (#231)
Rome-1 Oct 12, 2026
3f4e79e
fix(scan): name both engines instead of printing the bare word 'both'
Rome-1 Oct 12, 2026
d6b5e64
fix(api): accept RAFTER_API_URL only over https or loopback http (sab…
Rome-1 Oct 12, 2026
a7c0495
fix(verify): a hook that skips its stdin is not a spawn failure (sabl…
Rome-1 Oct 12, 2026
acb7e7a
fix(secrets): report each secret once when both engines find it
Rome-1 Oct 12, 2026
1ca7089
fix(secrets): cap the masked length of redacted findings
Rome-1 Oct 12, 2026
da4b9c1
fix(mcp): scan_secrets honors the project's suppressions
Rome-1 Oct 12, 2026
f088610
fix(policy): scan with defaults when .rafter.yml cannot be loaded
Rome-1 Oct 13, 2026
a9ea4a6
fix(policy): skip an ignore entry whose rules is not a list
Rome-1 Oct 13, 2026
772ad63
fix(cli): stop truncating JSON output written to a pipe
Rome-1 Oct 13, 2026
623c82b
fix(run,get): warn when a completed scan is partial
Rome-1 Oct 13, 2026
d1f842f
fix(secrets): exempt the AWS-docs EXAMPLE key from the Access Key ID …
Rome-1 Oct 13, 2026
ff2c2de
test(secrets): stop using the now-exempt EXAMPLE key as a detection f…
Rome-1 Oct 13, 2026
ebfcf6c
docs(secrets): keep AWS-key walkthroughs accurate after the EXAMPLE e…
Rome-1 Oct 13, 2026
02d6757
Merge chore/test-purge-rebased into release/0.11.0
Rome-1 Oct 13, 2026
68383f0
Merge fix/reverse-shell-risk into release/0.11.0
Rome-1 Oct 13, 2026
e4bdd26
Merge fix/issue-274-cfg into release/0.11.0
Rome-1 Oct 13, 2026
1903e45
Merge fix/issue-262-betterleaks-gitignore into release/0.11.0
Rome-1 Oct 13, 2026
e06f122
Merge fix/audit-long-line-hash into release/0.11.0
Rome-1 Oct 13, 2026
c6bbab5
Merge fix/issue-231-init-plan into release/0.11.0
Rome-1 Oct 13, 2026
8f4dd02
Merge fix/issue-231-verify-summary into release/0.11.0
Rome-1 Oct 13, 2026
10f5eb6
Merge fix/issue-231-docs-hints into release/0.11.0
Rome-1 Oct 13, 2026
6679149
Merge fix/test-config-isolation into release/0.11.0
Rome-1 Oct 13, 2026
1d34e27
Merge fix/verify-hook-epipe into release/0.11.0
Rome-1 Oct 13, 2026
5e85f1b
Merge fix/issue-230-example-key into release/0.11.0
Rome-1 Oct 13, 2026
591d4d6
Merge fix/sable-ehan-config-snake-case into release/0.11.0
Rome-1 Oct 13, 2026
99ec4e5
Merge fix/secrets-union-dedup into release/0.11.0
Rome-1 Oct 13, 2026
c80bd9d
Merge fix/secrets-redact-cap into release/0.11.0
Rome-1 Oct 13, 2026
01f03a7
Merge fix/report-accepts-secrets-json into release/0.11.0
Rome-1 Oct 13, 2026
6619cd5
Merge fix/pattern-engine-compile-once into release/0.11.0
Rome-1 Oct 13, 2026
84b4efa
Merge fix/scan-partial-surface into release/0.11.0
Rome-1 Oct 13, 2026
ba30758
Merge fix/scan-exclude-parity into release/0.11.0
Rome-1 Oct 13, 2026
d1a324e
Merge fix/mcp-scan-honors-suppressions into release/0.11.0
Rome-1 Oct 13, 2026
3ef62db
Merge fix/stdout-truncated-on-exit into release/0.11.0
Rome-1 Oct 13, 2026
9c84c7c
test: use the non-exempt AWS fixture key in tests merged after the EX…
Rome-1 Oct 13, 2026
4f1c933
chore(changelog): drop the duplicate Fixed heading the union merge le…
Rome-1 Oct 13, 2026
72d0a21
release: v0.11.0
Rome-1 Oct 13, 2026
76dd430
test(cursor): find rafter's hook entries by subcommand, not by path
Rome-1 Oct 13, 2026
d7aabbe
fix(mcp): scan a single file passed to scan_secrets
Rome-1 Oct 13, 2026
c07d58b
fix(mcp): fall back to patterns when betterleaks times out (Python)
Rome-1 Oct 13, 2026
340375f
fix(hook): audit-log failures can no longer turn a deny into an allow
Rome-1 Oct 13, 2026
c21d050
fix(mcp): report what suppressions dropped from scan_secrets
Rome-1 Oct 13, 2026
c739738
fix(cli): leave stderr non-blocking so mcp serve cannot stall
Rome-1 Oct 13, 2026
ae47b40
fix(scan): suppress a merged finding only when every engine's rule is
Rome-1 Oct 13, 2026
2cb0748
fix(risk): stop rating read-only /dev/tcp redirects as reverse shells
Rome-1 Oct 13, 2026
6615896
fix(sites): honor RAFTER_API_URL in Python Sites calls
Rome-1 Oct 13, 2026
43483be
fix(backend): tolerate non-string missing_scanners in the partial war…
Rome-1 Oct 13, 2026
017b612
fix(hook): fail closed on any unexpected error in the PreToolUse hook
Rome-1 Oct 13, 2026
a6b20b2
docs(changelog): note the 0.11.0 MCP, union and reverse-shell fixes
Rome-1 Oct 13, 2026
bdf61f1
Merge fix/release-review-batch into release/0.11.0
Rome-1 Oct 13, 2026
810e57d
test(hook): a malformed .rafter.yml falls back to the default rules, …
Rome-1 Oct 13, 2026
13bf056
Merge fix/hook-audit-failopen into release/0.11.0
Rome-1 Oct 13, 2026
b5190ca
fix(risk-rules): make Python's socket-shell pattern text match Node's
Rome-1 Oct 13, 2026
bc4f624
test(verify): make the #231 core-count test independent of betterleaks
Rome-1 Oct 13, 2026
b37d68f
test(agent): strip ANSI before checking skill-scanner help text
Rome-1 Oct 13, 2026
e62afa8
test: keep CI's exported API key for the live backend tests (sable-5b01)
Rome-1 Oct 13, 2026
8ddad5d
ci: allow backend-api.test.ts to skip until the API key secret exists
Rome-1 Oct 13, 2026
6ba817c
test(init): resolve the temp dir so macOS paths compare equal
Rome-1 Oct 13, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/fixtures/fake-secret.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# CI smoke-test fixture — contains a deliberately fake AWS key
# Used by publish.yml smoke tests to verify rafter agent scan works
AWS_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE
AWS_ACCESS_KEY_ID=AKIAIOSFODNN7ABCDEFG
7 changes: 5 additions & 2 deletions .github/workflows/test-comprehensive.yml
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,10 @@ jobs:
# ~95% of the count on 2026-09-02 (2099 executed); lower it in the same
# PR that removes tests, so a shrink is a reviewed decision.
- name: Assert the suite actually ran
run: python3 ../.github/scripts/test_floor.py --vitest vitest-report.json --min-executed 1990 --label "test-node (vitest)"
# backend-api.test.ts needs the RAFTER_API_KEY secret, which is not set
# on this repo (see the backend-api job), so all of its tests skip.
# Remove the exception once the secret exists.
run: python3 ../.github/scripts/test_floor.py --vitest vitest-report.json --min-executed 1990 --label "test-node (vitest)" --allow-all-skipped tests/backend-api.test.ts

# The battery is the gate that catches a MISSING fix; the differential
# cannot, because a fix absent on both sides is not a permissive move.
Expand Down Expand Up @@ -273,7 +276,7 @@ jobs:

- name: Generate SARIF from fixture
run: |
echo "AKIAIOSFODNN7EXAMPLE" > /tmp/test-secret.txt
echo "AKIAIOSFODNN7ABCDEFG" > /tmp/test-secret.txt
node dist/index.js scan local /tmp/test-secret.txt --engine patterns --format sarif > /tmp/output.sarif || true

- name: Validate SARIF structure
Expand Down
2 changes: 1 addition & 1 deletion .rafter.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ ignore:
- paths: ["demo/**"]
reason: "Demo app: intentional FAKE secrets (canonical AWS-docs example keys, sk_test Stripe, an example JWT) used to showcase rafter detection. Not real credentials."
- paths: ["README.md", "outreach-drafts.md", ".github/workflows/test-comprehensive.yml", ".rafter.yml"]
reason: "Documentation / CI examples and this policy file reference the canonical AWS-docs example access key (a well-known public non-secret) to illustrate detection."
reason: "Documentation / CI examples and this policy file reference AWS-docs-style example access keys (deliberately fake, not real credentials) to illustrate detection. (The canonical AKIAIOSFODNN7EXAMPLE itself is intentionally exempt from detection — sable/#230 — so these use a non-EXAMPLE fake key instead; this file's own comments above still name the canonical key by way of explanation.)"
- paths: ["**/fixtures/**", "fixtures/**"]
reason: "Test fixtures: intentionally-vulnerable / fake-secret inputs that exercise the scanner (e.g. requests-without-timeout in fixtures/vulnerable-repo)."
- paths: ["**/tests/**", "**/test_*.py", "**/*.test.ts", "**/fixtures/**", ".github/fixtures/**"]
Expand Down
64 changes: 64 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,70 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [0.11.0] - 2026-10-13

### Security

- **Upgrade now: a repository could turn off the command hook's blocking in rafter 0.7.2 through 0.10.6.** A `.rafter.yml` that pointed `audit.log_path` at an unwritable file made every hook deny fail, and the hook then allowed the call, including `rm -rf /`. Audit-write failures are now caught and reported once on stderr, and the deny stands. **Behavior change:** any other unexpected error in the PreToolUse hook now blocks the call for every tool, with `rafter hook error: <type>: <message>; denying to be safe` as the reason; it used to allow. A malformed `.rafter.yml` still produces a warning and the default settings, not a block.

- **A project `.rafter.yml` can no longer set `audit.log_path`** (possible since 0.7.2). Letting a repository choose the file rafter appends to let it write command text into files such as `~/.bashrc` or `~/.ssh/authorized_keys`. The setting is ignored with a warning; set the location in `~/.rafter/config.json` (`agent.audit.logPath`). **Behavior change:** a project that set `audit.log_path` now logs to the global location.

- **The commit hook and `rafter agent exec` now block a commit whose staged diff cannot be read** (#274). A staged diff over 1 MiB (a lockfile, a generated or vendored file) made the read fail, and the failure was treated as "no secrets", so the commit went through unscanned. Large diffs are now read in full, and any other failure to read the staged diff blocks the commit (`agent exec` exits 2) with a message saying the scan could not run. In Python, a staged diff that is not valid UTF-8 is now scanned rather than skipped.

- **A `.rafter.yml` that cannot be loaded no longer changes whether a commit is scanned.** If the file cannot be read, decoded or parsed, the commit hook, `rafter secrets --staged` and `rafter agent scan --staged` print a warning naming the file and the error, then scan with the default settings. None of the file's settings apply, including its `ignore` rules, so a broken file cannot suppress a finding. Previously the Python CLI could allow a commit containing a secret when `.rafter.yml` held well-formed YAML it could not map (for example a `null` entry in `custom_patterns`), and `secrets --staged` crashed.

- **An `ignore` entry whose `rules` is not a list is now skipped with a warning.** A value such as `rules: "AWS Access Key"` (a string, not a list) was dropped silently, which turned a rule meant for one pattern into one that suppressed every pattern in the listed paths.

- **`evaluate_command` and the command hook now rate reverse shells as critical.** Standard reverse-shell forms (`bash -i >& /dev/tcp/…`, `nc -e`/`-ve`, `mkfifo` + `nc`, Python, Perl, Node and PowerShell socket shells) were rated low and allowed. They are now critical in both runtimes, including the order-independent Node form. A script that opens a socket and runs a subprocess without wiring the socket to it rates medium. A read-only `/dev/tcp` redirect, such as the wait-for-port idiom `timeout 1 bash -c '</dev/tcp/host/5432'`, is not a reverse shell and is not rated critical; writing to the socket, duplicating a descriptor onto it (`exec 3<>/dev/tcp/…`), feeding it to a shell, or pairing it with an interactive shell still is.

- **`rafter agent init --with-codex` now installs the Codex hooks in the Python CLI** (#231). The Python installer never wrote `.codex/hooks.json`, so a Python install had no Codex command gate while `--dry-run` reported one. It now installs the same hooks as the Node CLI.

- **`rafter secrets --engine betterleaks` no longer reports a scan that timed out as clean** (#262). In the Python CLI a betterleaks timeout returned an empty result. It now raises, and the scan falls back to the patterns engine in both runtimes, with a warning that names the cause (for example "timed out after 60s").

- **The approval hint now quotes the command it tells you to run** (#231). The suggested `rafter agent exec` line was printed unquoted, so pasting it could run a `$(…)` substitution inside the blocked command.

- **The MCP `scan_secrets` tool now applies the project's suppressions.** `suppress_finding` wrote an ignore rule to `.rafter.yml`, but `scan_secrets` never applied it, so the next scan reported the same finding again. It now applies `.rafter.yml` ignore rules and `.rafterignore` as `rafter secrets` does. When any finding is hidden, the result carries a second content block, `{"suppressed_count": N, "_suppressed": [...]}`, with the same per-finding metadata as `rafter secrets --json` and no secret text, so an `ignore` rule in a cloned repository cannot silently empty the scan.

### Added

- **`RAFTER_API_URL` overrides the API base URL.** It is accepted only over https, or over plain http to localhost; any other value is ignored with a warning, and a remote override prints a notice naming the host your API key is sent to. A project `.env` cannot set it.

### Fixed

- **The MCP `scan_secrets` tool scans a single file.** Given a file path rather than a directory, the Node server returned no findings.

- **`rafter secrets --staged` no longer reports a scan that could not run as a finding** (#274). It used to crash with exit 1 on a staged diff over 1 MiB, the same code as a detected secret. Large diffs are now scanned, and a scan that cannot run exits 2 with an error message.

- **The built-in AWS Access Key ID pattern no longer flags the canonical AWS-docs example key** (#230). `AKIAIOSFODNN7EXAMPLE` and its siblings (any `AKIA…`/`ASIA…`/etc. key ending in `EXAMPLE`) matched the regex engine but not betterleaks, so e.g. the hook's Write gate denied a write containing the well-known public non-secret while `rafter secrets` via betterleaks allowed it. The regex engine now carries the same exemption betterleaks already applies, in both Node and Python. **Behavior change:** a key ending in `EXAMPLE` is no longer reported as a finding by the patterns engine; any other 16-character suffix is still detected as before.

- **The audit log's hash chain no longer breaks after an entry longer than 64 KB** (#271). The writer hashed only the last 64 KB of the previous line while `rafter agent audit --verify` hashed the whole line, so every long command produced a false tamper alarm. Existing logs keep reporting a break at the line written by the old code; new entries chain correctly.

- **Betterleaks now respects `.gitignore`** (#262). `betterleaks dir` has no gitignore support, so gitignored files such as `.env` and build output were scanned and the walk could hit the 60-second timeout. Rafter now passes betterleaks git's list of non-ignored files (tracked, plus untracked files that are not ignored) and still applies your `.betterleaks.toml`. **Behavior change:** the MCP `scan_secrets` tool and `baseline` no longer report secrets in gitignored files when betterleaks runs.

- **`rafter agent init --all` installs what it says it will** (#231). It now installs the `rafter-skill-review` skill its CLAUDE.md block refers to, and `--dry-run` matches the real run: no `~/.mcp.json` at user scope, no betterleaks download when an existing binary will be reused, and Claude Code included for `--with-claude-code` when `~/.claude` is missing. `rafter agent verify` counts only integrations that are present ("3/3 core checks passed" rather than "3/12"), and the shipped skills now say `rafter agent audit` instead of `rafter audit`.

- **`rafter agent verify` no longer reports a working hook as inert at random.** A hook that exits without reading its input made the check fail on a few percent of runs.

- **The Node CLI reads a config written by the Python CLI.** Both share `~/.rafter/config.json`, but Node did not read the Python CLI's snake_case keys, so a key or risk level set with `pip install rafter-cli` was ignored by the npm CLI.

- **`rafter secrets` reports each secret once when both engines find it.** The merge of betterleaks and pattern results almost never matched, because the engines extract different text and betterleaks reported columns off by one. On 21 large repositories, duplicate reports fell from 1,466 to 76. Existing baselines still apply. A merged finding is suppressed only when an `ignore` rule covers every engine's rule name for it, so a rule naming only the betterleaks rule no longer hides what the patterns engine found at the same spot.

- **Redacted secrets are capped at 16 masked characters.** A PEM block or a long JWT could print a line of more than a thousand asterisks.

- **`rafter report` accepts the output of `rafter secrets --json`.** The pipe in its own help, `rafter secrets --json . | rafter report -o report.html`, failed in both runtimes.

- **Piped JSON output from the Node CLI is no longer cut off at 64 KiB.** The CLI exited before Node finished writing to a pipe, so `rafter secrets --json . | rafter report` and `rafter get <id> -f json | jq` received truncated JSON. Output written to a file, and the Python CLI, were not affected.

- **`rafter run` and `rafter get` say why a remote scan failed.** They now print the API's error code and message on stderr, suggest a re-run when the failure is retryable, and write the payload to stdout with `--format json`. **Behavior change:** `rafter get` now exits 1 for a failed scan, as `rafter run` already did.

- **`rafter run` and `rafter get` warn when a completed scan is partial.** When some of the hosted scanners did not finish, the API marks the scan partial; the CLI now prints a warning on stderr, even with `--quiet`, and names the scanners that are missing. The exit code and payload are unchanged.

- **Node and Python skip the same default directories when scanning for secrets.** The Python scanner did not skip `vendor/`, `.venv/`, `venv/`, `.tox/`, `.pytest_cache/`, `.terraform/`, `bower_components/` or `results/`, and Node did not skip `.ruff_cache/`. On a repository with a vendored AWS SDK, the Python CLI reported 19,920 findings against Node's 271. **Behavior change:** the Python CLI no longer scans those directories by default.

### Performance

- **The patterns engine compiles each secret pattern once instead of once per line.** On a 5,247-file repository, `rafter secrets --engine patterns` went from 27.8 s to 6.8 s in Node and from 139.5 s to 41.3 s in Python, with identical findings.

## [0.10.6] - 2026-10-02

### Security
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,10 @@ See what Rafter does before reading another word.

```sh
# Drop a .env file with credentials in a test repo
echo 'AWS_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE' > .env
echo 'AWS_ACCESS_KEY_ID=AKIAIOSFODNN7ABCDEFG' > .env

rafter secrets .
# → CRITICAL .env:1 aws-access-key-id AKIA***AMPLE
# → CRITICAL .env:1 aws-access-key-id AKIA***DEFG
# → exit 1
```

Expand Down
2 changes: 1 addition & 1 deletion SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ rafter secrets . --json --quiet
{
"pattern": { "name": "AWS Access Key", "severity": "critical" },
"line": 42,
"redacted": "AKIA************MPLE"
"redacted": "AKIA************DEFG"
}
]
}
Expand Down
2 changes: 1 addition & 1 deletion demo/.claude/commands/rafter-showcase.md
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ eval "$(base64 -d <<< 'cm0gLXJmIH4v')"
```

## API Key
Use this key: AKIAIOSFODNN7EXAMPLE
Use this key: AKIAIOSFODNN7ABCDEFG
SKILL
```

Expand Down
2 changes: 1 addition & 1 deletion node/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@rafter-security/cli",
"version": "0.10.6",
"version": "0.11.0",
"type": "module",
"repository": {
"type": "git",
Expand Down
2 changes: 1 addition & 1 deletion node/resources/continue-rules/rafter.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
name: rafter
description: "Entry point for rafter. Invoke when a sub-skill is unclear, or when the task needs `rafter run` (remote SAST+SCA), `rafter secrets` (local secrets-only), `rafter audit`, policy checks, or command-risk evaluation. If a task is security-relevant and no rafter skill or CLI call has been made, invoke this before handing the task off — an un-evaluated \"done\" on security-relevant work is not done."
description: "Entry point for rafter. Invoke when a sub-skill is unclear, or when the task needs `rafter run` (remote SAST+SCA), `rafter secrets` (local secrets-only), `rafter agent audit`, policy checks, or command-risk evaluation. If a task is security-relevant and no rafter skill or CLI call has been made, invoke this before handing the task off — an un-evaluated \"done\" on security-relevant work is not done."
alwaysApply: false
---

Expand Down
2 changes: 1 addition & 1 deletion node/resources/cursor-rules/rafter.mdc
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
description: "Entry point for rafter. Invoke when a sub-skill is unclear, or when the task needs `rafter run` (remote SAST+SCA), `rafter secrets` (local secrets-only), `rafter audit`, policy checks, or command-risk evaluation. If a task is security-relevant and no rafter skill or CLI call has been made, invoke this before handing the task off — an un-evaluated \"done\" on security-relevant work is not done."
description: "Entry point for rafter. Invoke when a sub-skill is unclear, or when the task needs `rafter run` (remote SAST+SCA), `rafter secrets` (local secrets-only), `rafter agent audit`, policy checks, or command-risk evaluation. If a task is security-relevant and no rafter skill or CLI call has been made, invoke this before handing the task off — an un-evaluated \"done\" on security-relevant work is not done."
alwaysApply: false
---

Expand Down
2 changes: 1 addition & 1 deletion node/resources/rafter-security-skill.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
name: rafter-security
description: Security toolkit for AI workflows. Use when scanning code or repos for vulnerabilities, auditing third-party skills/MCPs/agent configs before installing, evaluating shell commands before running them, or generating secure design questions for new features. Provides `rafter run` (remote SAST + SCA, needs RAFTER_API_KEY), `rafter secrets` (offline secrets-only), `rafter agent exec --dry-run` (command-risk classification), and `rafter skill review`.
version: 0.10.6
version: 0.11.0
homepage: https://rafter.so
metadata:
openclaw:
Expand Down
2 changes: 1 addition & 1 deletion node/resources/skills/rafter/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
name: rafter
description: "Entry point for rafter. Invoke when a sub-skill is unclear, or when the task needs `rafter run` (remote SAST+SCA), `rafter secrets` (local secrets-only), `rafter audit`, policy checks, or command-risk evaluation. Scope by security surface, not task label: engage when the diff touches auth, credentials/secrets/tokens, untrusted input, SQL, shell/exec, file paths, deserialization, crypto, network endpoints, data deletion, or dependencies; for research/experimental/local-only code with none of that, a quick surface check is enough. When such surface IS present and no rafter skill or CLI call has been made, invoke this before handing the task off — an un-evaluated \"done\" on genuine security surface is not done."
description: "Entry point for rafter. Invoke when a sub-skill is unclear, or when the task needs `rafter run` (remote SAST+SCA), `rafter secrets` (local secrets-only), `rafter agent audit`, policy checks, or command-risk evaluation. Scope by security surface, not task label: engage when the diff touches auth, credentials/secrets/tokens, untrusted input, SQL, shell/exec, file paths, deserialization, crypto, network endpoints, data deletion, or dependencies; for research/experimental/local-only code with none of that, a quick surface check is enough. When such surface IS present and no rafter skill or CLI call has been made, invoke this before handing the task off — an un-evaluated \"done\" on genuine security surface is not done."
version: 0.7.0
allowed-tools: [Bash, Read]
---
Expand Down
2 changes: 1 addition & 1 deletion node/resources/windsurf-rules/rafter.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
trigger: model_decision
description: "Entry point for rafter. Invoke when a sub-skill is unclear, or when the task needs `rafter run` (remote SAST+SCA), `rafter secrets` (local secrets-only), `rafter audit`, policy checks, or command-risk evaluation. If a task is security-relevant and no rafter skill or CLI call has been made, invoke this before handing the task off — an un-evaluated \"done\" on security-relevant work is not done."
description: "Entry point for rafter. Invoke when a sub-skill is unclear, or when the task needs `rafter run` (remote SAST+SCA), `rafter secrets` (local secrets-only), `rafter agent audit`, policy checks, or command-risk evaluation. If a task is security-relevant and no rafter skill or CLI call has been made, invoke this before handing the task off — an un-evaluated \"done\" on security-relevant work is not done."
---

# rafter — security toolkit router
Expand Down
Loading
Loading