feat(plugin): add Claude Code plugin#282
Conversation
Adds plugins/claude-code/ — a Claude Code plugin that integrates foxguard into the Claude Code workflow. What it does: - PostToolUse hook auto-scans every Write/Edit/MultiEdit/NotebookEdit with `foxguard --format json --severity medium`. Findings are surfaced to Claude on stderr (exit 2) so the model self-corrects before bad patterns land. Clean files, missing binary, or unreadable inputs stay silent (exit 0) — the hook never blocks Claude on its own machinery. - SessionStart hook seeds each session with foxguard's secure-coding defaults (command exec, SQL, path traversal, SSRF, secrets, randomness, crypto, deserialization). - Slash commands: /foxguard:setup, scan, diff-scan, pq-audit, secrets, triage. Each is a SKILL.md with disable-model-invocation so the user drives them. - Model-invokable `secure-coding` skill provides remediation guidance Claude can pull in proactively when touching security-sensitive code. The hook resolves foxguard from PATH first, then falls back to `npx --yes foxguard`. Severity threshold is tunable via FOXGUARD_HOOK_SEVERITY (default: medium). Tested against bad files (exit 2 with findings), clean files (exit 0), missing files, empty input, and a severity override — all behave as expected.
📝 WalkthroughWalkthroughThis PR introduces a complete Claude Code plugin for foxguard that enables automatic security scanning as Claude writes and edits code. It includes PostToolUse hooks for auto-scanning files, SessionStart hooks for security defaults, and seven skill-based slash commands for setup, full/diff scanning, post-quantum auditing, secret scanning, and remediation guidance. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Review rate limit: 9/10 reviews remaining, refill in 6 minutes. Comment |
There was a problem hiding this comment.
Actionable comments posted: 5
🧹 Nitpick comments (1)
plugins/claude-code/skills/setup/SKILL.md (1)
10-14: ⚡ Quick winAvoid “curl | sh” without verification guidance.
Line 10 uses
curl -fsSL https://foxguard.dev/install.sh | sh. Even with “do NOT install without confirmation”, this still encourages an insecure-by-default installation pattern. Consider updating the step to: download the script to a file, verify a published checksum/signature (or explicitly instruct users to inspect the script before executing), then run it.Suggested doc wording
- - **Prebuilt binary (fastest)**: `curl -fsSL https://foxguard.dev/install.sh | sh` + - **Prebuilt binary (fastest)**: Download the installer script, verify it (checksum/signature if provided by foxguard), then run it (e.g., `sh install.sh`).🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@plugins/claude-code/skills/setup/SKILL.md` around lines 10 - 14, Replace the insecure "curl -fsSL https://foxguard.dev/install.sh | sh" install suggestion with explicit download-and-verify guidance: instruct users to curl or wget the install script to a local file (e.g., download the install.sh), verify its published checksum or signature (or inspect the script manually), and only then run it (sh ./install.sh) after verification and explicit consent; update the SKILL.md install bullet that currently contains the piped curl command to this safer sequence and mention verifying signed checksums or manual inspection as the required step before execution.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@plugins/claude-code/README.md`:
- Around line 64-73: The fenced code block under "How the auto-scan looks" in
README.md is missing a language specifier which triggers markdownlint MD040;
update the opening triple-backtick to include a language (for example change ```
to ```text) so the block is recognized as text, leaving the block contents
unchanged; locate the fenced block in the "How the auto-scan looks" example and
modify its opening delimiter accordingly.
- Around line 79-95: The README's layout directory tree code block uses a bare
triple-backtick which triggers markdownlint MD040; update the fenced code block
around the "plugins/claude-code/" tree (the Layout directory tree block) to
include a language identifier (e.g., change ``` to ```text) so the block is
fenced with a language and MD040 is resolved.
- Around line 54-57: The markdown table defining configuration (the row for
FOXGUARD_HOOK_SEVERITY) is malformed and triggers MD056 because the
header/separator doesn't unambiguously define three columns; open the table near
the FOXGUARD_HOOK_SEVERITY row and fix the header and separator to have exactly
three columns (e.g., a single header row with three cells and a matching
separator like `| :-- | :-- | :-- |`), and remove any accidental extra `|`
characters inside cells so the FOXGUARD_HOOK_SEVERITY row and its header align
to three columns.
In `@plugins/claude-code/scripts/scan-edited-file.sh`:
- Line 30: The scanner is invoked as "${fg[@]}" --format json --severity
"$min_severity" "$file_path" which can misinterpret filenames beginning with '-'
as options; update the invocation that constructs findings to insert a
standalone "--" before the positional path (i.e., call "${fg[@]}" --format json
--severity "$min_severity" -- "$file_path") so the scanner treats file_path as a
filename; ensure you update the line that assigns findings and keep existing
quoting and the fallback "|| true".
In `@plugins/claude-code/skills/secure-coding/SKILL.md`:
- Line 11: The inline code span on Line 11 is malformed because nested backticks
break Markdown rendering around the Node example; update the text to avoid
nested backticks by using a single backtick for the surrounding inline code and
escaping or reformatting the inner example (e.g., use execFile("git", ["log",
branch"]) instead of backticked exec(`git log ${branch}`) or present the inner
command in a code span block), targeting the phrase that references execFile and
exec with the git log ${branch} example so the Markdown renders correctly.
---
Nitpick comments:
In `@plugins/claude-code/skills/setup/SKILL.md`:
- Around line 10-14: Replace the insecure "curl -fsSL
https://foxguard.dev/install.sh | sh" install suggestion with explicit
download-and-verify guidance: instruct users to curl or wget the install script
to a local file (e.g., download the install.sh), verify its published checksum
or signature (or inspect the script manually), and only then run it (sh
./install.sh) after verification and explicit consent; update the SKILL.md
install bullet that currently contains the piped curl command to this safer
sequence and mention verifying signed checksums or manual inspection as the
required step before execution.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: bbb1bd68-9515-4b57-ae5c-bdf71bda486d
📒 Files selected for processing (12)
plugins/claude-code/.claude-plugin/plugin.jsonplugins/claude-code/README.mdplugins/claude-code/hooks/hooks.jsonplugins/claude-code/scripts/scan-edited-file.shplugins/claude-code/scripts/secure-defaults.txtplugins/claude-code/skills/diff-scan/SKILL.mdplugins/claude-code/skills/pq-audit/SKILL.mdplugins/claude-code/skills/scan/SKILL.mdplugins/claude-code/skills/secrets/SKILL.mdplugins/claude-code/skills/secure-coding/SKILL.mdplugins/claude-code/skills/setup/SKILL.mdplugins/claude-code/skills/triage/SKILL.md
| | Var | Default | Purpose | | ||
| | :-- | :-- | :-- | | ||
| | `FOXGUARD_HOOK_SEVERITY` | `medium` | Minimum severity for the auto-scan. One of `low|medium|high|critical`. | | ||
|
|
There was a problem hiding this comment.
Fix markdownlint MD056: table column count.
Your configuration table around lines 54-57 is triggering markdownlint-cli2 MD056 (“Expected: 3; Actual: 6”). Adjust the table to unambiguously define 3 columns in the header/separator, and avoid any accidental extra | characters.
Example normalization
-| Var | Default | Purpose |
-| :-- | :-- | :-- |
+| Var | Default | Purpose |
+| --- | --- | --- |
| `FOXGUARD_HOOK_SEVERITY` | `medium` | Minimum severity for the auto-scan. One of `low|medium|high|critical`. |📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| | Var | Default | Purpose | | |
| | :-- | :-- | :-- | | |
| | `FOXGUARD_HOOK_SEVERITY` | `medium` | Minimum severity for the auto-scan. One of `low|medium|high|critical`. | | |
| | Var | Default | Purpose | | |
| | --- | --- | --- | | |
| | `FOXGUARD_HOOK_SEVERITY` | `medium` | Minimum severity for the auto-scan. One of `low\|medium\|high\|critical`. | |
🧰 Tools
🪛 markdownlint-cli2 (0.22.1)
[warning] 56-56: Table column count
Expected: 3; Actual: 6; Too many cells, extra data will be missing
(MD056, table-column-count)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@plugins/claude-code/README.md` around lines 54 - 57, The markdown table
defining configuration (the row for FOXGUARD_HOOK_SEVERITY) is malformed and
triggers MD056 because the header/separator doesn't unambiguously define three
columns; open the table near the FOXGUARD_HOOK_SEVERITY row and fix the header
and separator to have exactly three columns (e.g., a single header row with
three cells and a matching separator like `| :-- | :-- | :-- |`), and remove any
accidental extra `|` characters inside cells so the FOXGUARD_HOOK_SEVERITY row
and its header align to three columns.
| ``` | ||
| foxguard found 1 issue(s) in src/auth.py (severity >= medium): | ||
|
|
||
| [CRITICAL] py/no-command-injection at line 42 | ||
| os.system() called with dynamic argument — risk of command injection | ||
| CWE-78 | ||
| > os.system("ls " + user_input) | ||
|
|
||
| Fix these before continuing. Run `/foxguard:scan` for the full repo or `/foxguard:triage` for the interactive TUI. | ||
| ``` |
There was a problem hiding this comment.
Fix markdownlint MD040: add a fenced-code language.
The example block under “How the auto-scan looks” starts with a bare triple-backtick (line 64 per hint). Specify a language (e.g. text) to satisfy MD040.
Suggested change
-```
+```text
foxguard found 1 issue(s) in src/auth.py (severity >= medium):
...</details>
<!-- suggestion_start -->
<details>
<summary>📝 Committable suggestion</summary>
> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
```suggestion
🧰 Tools
🪛 markdownlint-cli2 (0.22.1)
[warning] 64-64: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@plugins/claude-code/README.md` around lines 64 - 73, The fenced code block
under "How the auto-scan looks" in README.md is missing a language specifier
which triggers markdownlint MD040; update the opening triple-backtick to include
a language (for example change ``` to ```text) so the block is recognized as
text, leaving the block contents unchanged; locate the fenced block in the "How
the auto-scan looks" example and modify its opening delimiter accordingly.
| ``` | ||
| plugins/claude-code/ | ||
| ├── .claude-plugin/plugin.json # manifest | ||
| ├── hooks/hooks.json # PostToolUse + SessionStart | ||
| ├── scripts/ | ||
| │ ├── scan-edited-file.sh # the PostToolUse scanner | ||
| │ └── secure-defaults.txt # SessionStart preamble | ||
| ├── skills/ | ||
| │ ├── setup/SKILL.md # /foxguard:setup | ||
| │ ├── scan/SKILL.md # /foxguard:scan | ||
| │ ├── diff-scan/SKILL.md # /foxguard:diff-scan | ||
| │ ├── pq-audit/SKILL.md # /foxguard:pq-audit | ||
| │ ├── secrets/SKILL.md # /foxguard:secrets | ||
| │ ├── triage/SKILL.md # /foxguard:triage | ||
| │ └── secure-coding/SKILL.md # model-invoked remediation guidance | ||
| └── README.md | ||
| ``` |
There was a problem hiding this comment.
Fix markdownlint MD040: add a fenced-code language.
The “Layout” directory tree block also uses a bare triple-backtick (line 79 per hint). Add a language identifier like text to clear MD040.
Suggested change
-```
+```text
plugins/claude-code/
├── .claude-plugin/plugin.json # manifest
...</details>
<details>
<summary>🧰 Tools</summary>
<details>
<summary>🪛 markdownlint-cli2 (0.22.1)</summary>
[warning] 79-79: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
</details>
</details>
<details>
<summary>🤖 Prompt for AI Agents</summary>
Verify each finding against the current code and only fix it if needed.
In @plugins/claude-code/README.md around lines 79 - 95, The README's layout
directory tree code block uses a bare triple-backtick which triggers
markdownlint MD040; update the fenced code block around the
"plugins/claude-code/" tree (the Layout directory tree block) to include a
language identifier (e.g., change totext) so the block is fenced with a
language and MD040 is resolved.
</details>
<!-- fingerprinting:phantom:triton:puma:05f3783a-a64c-4a50-b1f4-3b1690357be0 -->
<!-- d98c2f50 -->
<!-- This is an auto-generated comment by CodeRabbit -->
|
|
||
| min_severity="${FOXGUARD_HOOK_SEVERITY:-medium}" | ||
|
|
||
| findings=$("${fg[@]}" --format json --severity "$min_severity" "$file_path" 2>/dev/null) || true |
There was a problem hiding this comment.
Prevent option-style filename bypass in scanner invocation
On Line 30, "$file_path" is passed as a positional argument without --. If the edited filename starts with -, the scanner may parse it as a flag instead of a path.
Suggested fix
-findings=$("${fg[@]}" --format json --severity "$min_severity" "$file_path" 2>/dev/null) || true
+findings=$("${fg[@]}" --format json --severity "$min_severity" -- "$file_path" 2>/dev/null) || true📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| findings=$("${fg[@]}" --format json --severity "$min_severity" "$file_path" 2>/dev/null) || true | |
| findings=$("${fg[@]}" --format json --severity "$min_severity" -- "$file_path" 2>/dev/null) || true |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@plugins/claude-code/scripts/scan-edited-file.sh` at line 30, The scanner is
invoked as "${fg[@]}" --format json --severity "$min_severity" "$file_path"
which can misinterpret filenames beginning with '-' as options; update the
invocation that constructs findings to insert a standalone "--" before the
positional path (i.e., call "${fg[@]}" --format json --severity "$min_severity"
-- "$file_path") so the scanner treats file_path as a filename; ensure you
update the line that assigns findings and keep existing quoting and the fallback
"|| true".
|
|
||
| - Never pass concatenated strings to a shell. Use argument lists. | ||
| - Python: `subprocess.run(["git", "log", branch], check=True)` — never `subprocess.run(f"git log {branch}", shell=True)`. | ||
| - Node: `execFile("git", ["log", branch])` — never `exec(`git log ${branch}`)`. |
There was a problem hiding this comment.
Fix malformed inline code span in Node example
On Line 11, nested backticks break Markdown rendering for the exec example.
Suggested fix
- - Node: `execFile("git", ["log", branch])` — never `exec(`git log ${branch}`)`.
+ - Node: `execFile("git", ["log", branch])` — never `exec("git log " + branch)` (or template-string shell commands).📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| - Node: `execFile("git", ["log", branch])` — never `exec(`git log ${branch}`)`. | |
| - Node: `execFile("git", ["log", branch])` — never `exec("git log " + branch)` (or template-string shell commands). |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@plugins/claude-code/skills/secure-coding/SKILL.md` at line 11, The inline
code span on Line 11 is malformed because nested backticks break Markdown
rendering around the Node example; update the text to avoid nested backticks by
using a single backtick for the surrounding inline code and escaping or
reformatting the inner example (e.g., use execFile("git", ["log", branch"])
instead of backticked exec(`git log ${branch}`) or present the inner command in
a code span block), targeting the phrase that references execFile and exec with
the git log ${branch} example so the Markdown renders correctly.
Summary
/foxguard:*skills for setup, scan, diff scan, PQ audit, secrets, triage, and secure-coding guidance.Verification
jq empty plugins/claude-code/.claude-plugin/plugin.json && jq empty plugins/claude-code/hooks/hooks.jsonbash -n plugins/claude-code/scripts/scan-edited-file.shprintf '%s' '{"tool_input":{"file_path":"Cargo.toml"}}' | PATH="$(pwd)/target/debug:$PATH" plugins/claude-code/scripts/scan-edited-file.shCloses #280
Summary by CodeRabbit
New Features
Documentation