-
Notifications
You must be signed in to change notification settings - Fork 2
Finding Allowlist & Suppression #17
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
MikeeBuilds
wants to merge
13
commits into
main
Choose a base branch
from
auto-claude/007-finding-allowlist-suppression
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
13 commits
Select commit
Hold shift + click to select a range
fc9ba5c
auto-claude: subtask-1-1 - Create suppression.sh helper with load_sup…
MikeeBuilds 4c80059
auto-claude: subtask-2-1 - Add --show-suppressed and --no-ignore flag…
MikeeBuilds d53c404
auto-claude: subtask-2-2 - Source suppression.sh and apply filtering …
MikeeBuilds 9e90970
auto-claude: subtask-3-2 - Update interactive/terminal output to show…
MikeeBuilds 7041a3f
auto-claude: subtask-3-3 - Add --show-suppressed display logic to inc…
MikeeBuilds 28e121f
auto-claude: subtask-4-1 - Create .clawpinch-ignore.json.example with…
MikeeBuilds 832f3ee
auto-claude: subtask-4-2 - Update README.md with suppression document…
MikeeBuilds 8f59a63
auto-claude: subtask-4-3 - Update CLAUDE.md and SKILL.md with suppres…
MikeeBuilds ee007ef
auto-claude: subtask-6-1 - Test suppression with no expiry
MikeeBuilds 22b5b8f
auto-claude: subtask-6-2 - Test suppression with expiration (future a…
MikeeBuilds ead3cd2
fix: address review feedback — fix dirname bug, optimize jq filtering…
MikeeBuilds bbe77b0
fix: address round 3 review — harden suppression, consolidate jq, rem…
MikeeBuilds 3b7a7d3
fix: address PR #17 review — revert to individual jq calls, remove de…
MikeeBuilds File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,53 @@ | ||
| { | ||
| "$schema": "https://clawpinch.dev/schemas/ignore.json", | ||
| "_comment": "This file configures finding suppression for ClawPinch security scans", | ||
| "_documentation": { | ||
| "purpose": "Suppress accepted-risk findings to prevent CI/CD pipeline failures", | ||
| "location": "Copy this file to .clawpinch-ignore.json in your project root", | ||
| "fields": { | ||
| "id": "(required) Check ID to suppress (e.g., CHK-CFG-001)", | ||
| "reason": "(required) Justification for suppressing this finding", | ||
| "expires": "(optional) ISO 8601 timestamp when suppression expires and finding reactivates", | ||
| "suppressed_by": "(optional) Email or identifier of person who approved suppression", | ||
| "suppressed_at": "(optional) ISO 8601 timestamp when suppression was created" | ||
| }, | ||
| "behavior": { | ||
| "suppressed_findings": "Moved to 'suppressed' array in JSON output, excluded from severity counts", | ||
| "expired_suppressions": "Automatically reactivated if expires date is in the past", | ||
| "flags": { | ||
| "--show-suppressed": "Include suppressed findings in output with [SUPPRESSED] marker", | ||
| "--no-ignore": "Disable all suppressions for full audit scans" | ||
| } | ||
| } | ||
| }, | ||
| "suppressions": [ | ||
| { | ||
| "id": "CHK-CFG-001", | ||
| "reason": "Dev environment - open gateway is intentional for local testing", | ||
| "expires": "2025-12-31T23:59:59Z", | ||
| "suppressed_by": "[email protected]", | ||
| "suppressed_at": "2024-01-15T10:30:00Z" | ||
| }, | ||
| { | ||
| "id": "CHK-SEC-003", | ||
| "reason": "Test API key in example config - not used in production deployments" | ||
| }, | ||
| { | ||
| "id": "CHK-NET-004", | ||
| "reason": "WebSocket endpoint exposed for real-time collaboration feature", | ||
| "expires": "2025-06-30T00:00:00Z", | ||
| "suppressed_by": "[email protected]" | ||
| }, | ||
| { | ||
| "id": "CHK-PRM-002", | ||
| "reason": "Wildcard permission required for dynamic skill loader - reviewed by security", | ||
| "suppressed_by": "[email protected]", | ||
| "suppressed_at": "2024-02-20T14:30:00Z" | ||
| }, | ||
| { | ||
| "id": "CHK-CRN-001", | ||
| "reason": "Cron job needs elevated permissions for system maintenance tasks", | ||
| "expires": "2025-03-01T00:00:00Z" | ||
| } | ||
| ] | ||
| } |
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -16,6 +16,12 @@ bash clawpinch.sh --remediate | |
|
|
||
| # Deep scan | ||
| bash clawpinch.sh --deep | ||
|
|
||
| # Show suppressed findings | ||
| bash clawpinch.sh --show-suppressed | ||
|
|
||
| # Disable all suppressions (full audit) | ||
| bash clawpinch.sh --no-ignore | ||
| ``` | ||
|
|
||
| ## Architecture | ||
|
|
@@ -32,6 +38,7 @@ clawpinch/ | |
| │ │ ├── report.sh # Terminal UI: banner, finding cards, summary dashboard, spinner | ||
| │ │ ├── redact.sh # Secret redaction: redact_value(), redact_line(), redact_json_secrets() | ||
| │ │ ├── safe_exec.sh # Safe command execution: whitelist-based validation, replaces eval() | ||
| │ │ ├── suppression.sh # Finding suppression: load_suppressions(), filter_findings(), expiration handling | ||
| │ │ └── interactive.sh # Post-scan menu: review, auto-fix, handoff export, AI remediation | ||
| │ ├── scan_config.sh # CHK-CFG-001..010 — gateway, TLS, auth, CORS | ||
| │ ├── scan_secrets.py # CHK-SEC-001..008 — API keys, passwords, tokens | ||
|
|
@@ -46,6 +53,7 @@ clawpinch/ | |
| │ ├── malicious-patterns.json # Known bad skill hashes | ||
| │ ├── check-catalog.md # Full check documentation | ||
| │ └── threat-model.md # Threat model for OpenClaw | ||
| ├── .clawpinch-ignore.json.example # Example suppression config with documentation | ||
| ├── package.json # npm package metadata | ||
| ├── SKILL.md # AI-readable skill documentation | ||
| ├── CLAUDE.md # This file — project context for Claude Code | ||
|
|
@@ -72,6 +80,19 @@ Every scanner emits findings via `emit_finding()` from `common.sh`: | |
|
|
||
| Severity order: `critical` > `warn` > `info` > `ok`. | ||
|
|
||
| ### Output Format with Suppressions | ||
|
|
||
| When suppressions are enabled (via `.clawpinch-ignore.json`), the JSON output contains two arrays: | ||
|
|
||
| ```json | ||
| { | ||
| "findings": [ /* active findings only */ ], | ||
| "suppressed": [ /* suppressed findings */ ] | ||
| } | ||
| ``` | ||
|
|
||
| Suppressed findings do not count toward severity totals or exit codes. Use `--show-suppressed` to include them in terminal output (marked with `[SUPPRESSED]`), or `--no-ignore` to disable all suppressions for full audits. | ||
|
|
||
| ## How to Add a New Check | ||
|
|
||
| 1. Choose the appropriate scanner file in `scripts/` (or create a new `scan_*.sh`) | ||
|
|
@@ -80,6 +101,39 @@ Severity order: `critical` > `warn` > `info` > `ok`. | |
| 4. Call `emit_finding "CHK-XXX-NNN" "severity" "title" "description" "evidence" "remediation" "auto_fix"` | ||
| 5. Add the check to `references/check-catalog.md` and `SKILL.md` category table | ||
|
|
||
| ## Finding Suppression | ||
|
|
||
| Findings can be suppressed by creating a `.clawpinch-ignore.json` file in the project root: | ||
|
|
||
| ```json | ||
| { | ||
| "suppressions": [ | ||
| { | ||
| "id": "CHK-CFG-001", | ||
| "reason": "Dev environment - open gateway is intentional", | ||
| "expires": "2025-12-31T23:59:59Z", | ||
| "suppressed_by": "[email protected]", | ||
| "suppressed_at": "2024-01-15T10:30:00Z" | ||
| } | ||
| ] | ||
| } | ||
| ``` | ||
|
|
||
| **Behavior:** | ||
| - Suppressed findings move to `suppressed` array in JSON output | ||
| - Suppressed findings do not count toward severity totals or exit codes | ||
| - Expired suppressions (past `expires` date) automatically reactivate | ||
| - `--show-suppressed` includes suppressed findings in output with `[SUPPRESSED]` marker | ||
| - `--no-ignore` disables all suppressions for full audit scans | ||
|
|
||
| **Use cases:** | ||
| - Accepted risks in development environments | ||
| - Findings under gradual remediation with expiration tracking | ||
| - Security-reviewed exceptions with documented justifications | ||
| - CI/CD pipelines that fail on active findings only | ||
|
|
||
| See `.clawpinch-ignore.json.example` for a fully documented template. | ||
|
|
||
| ## Conventions | ||
|
|
||
| - All scanners output a JSON array to stdout | ||
|
|
||
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -207,6 +207,12 @@ bash clawpinch.sh --config-dir /path/to/openclaw/config | |
|
|
||
| # Print auto-fix commands (read-only -- does not execute them) | ||
| bash clawpinch.sh --fix | ||
|
|
||
| # Show suppressed findings in output | ||
| bash clawpinch.sh --show-suppressed | ||
|
|
||
| # Disable all suppressions for full audit | ||
| bash clawpinch.sh --no-ignore | ||
| ``` | ||
|
|
||
| --- | ||
|
|
@@ -241,6 +247,128 @@ bash clawpinch.sh --sequential | |
|
|
||
| --- | ||
|
|
||
| ## Suppressing Findings | ||
|
|
||
| ClawPinch allows you to suppress specific findings by check ID -- useful for accepted risks in development environments or findings that have been reviewed and approved by your security team. Suppressed findings are still scanned but reported separately and excluded from severity counts and exit codes. | ||
|
|
||
| ### Creating a Suppression File | ||
|
|
||
| Create a `.clawpinch-ignore.json` file in your project root: | ||
|
|
||
| ```json | ||
| { | ||
| "suppressions": [ | ||
| { | ||
| "id": "CHK-CFG-001", | ||
| "reason": "Dev environment - open gateway is intentional for local testing" | ||
| }, | ||
| { | ||
| "id": "CHK-SEC-003", | ||
| "reason": "Test API key in example config - not used in production", | ||
| "expires": "2025-12-31T23:59:59Z", | ||
| "suppressed_by": "[email protected]" | ||
| } | ||
| ] | ||
| } | ||
| ``` | ||
|
|
||
| ### Suppression Fields | ||
|
|
||
| - **`id`** (required) -- The check ID to suppress (e.g., `CHK-CFG-001`, `CHK-NET-004`) | ||
| - **`reason`** (required) -- Justification for why this finding is being suppressed | ||
| - **`expires`** (optional) -- ISO 8601 timestamp when the suppression expires and the finding reactivates | ||
| - **`suppressed_by`** (optional) -- Email or identifier of the person who approved the suppression | ||
| - **`suppressed_at`** (optional) -- ISO 8601 timestamp when the suppression was created | ||
|
|
||
| ### How Suppressions Work | ||
|
|
||
| 1. **Automatic Filtering** -- Suppressed findings are moved from the main `findings` array to a separate `suppressed` array in JSON output | ||
| 2. **Severity Exclusion** -- Suppressed findings do not count toward severity totals or affect exit codes | ||
| 3. **Expiration** -- If a suppression has an `expires` date in the past, it is automatically reactivated and the finding appears in normal output | ||
| 4. **Visibility** -- Use `--show-suppressed` to include suppressed findings in output (marked with `[SUPPRESSED]`) | ||
| 5. **Audit Mode** -- Use `--no-ignore` to disable all suppressions for full audit scans | ||
|
|
||
| ### Example Workflow | ||
|
|
||
| ```bash | ||
| # 1. Run initial scan and identify accepted risks | ||
| npx clawpinch --json > findings.json | ||
|
|
||
| # 2. Create .clawpinch-ignore.json with suppressions | ||
| cat > .clawpinch-ignore.json <<EOF | ||
| { | ||
| "suppressions": [ | ||
| { | ||
| "id": "CHK-CFG-001", | ||
| "reason": "Dev environment - reviewed by security team", | ||
| "expires": "2025-12-31T23:59:59Z", | ||
| "suppressed_by": "[email protected]" | ||
| } | ||
| ] | ||
| } | ||
| EOF | ||
|
|
||
| # 3. Re-run scan -- suppressed findings no longer fail CI | ||
| npx clawpinch --json | ||
| # Exit code: 0 (even if CHK-CFG-001 was critical) | ||
|
|
||
| # 4. Review suppressed findings | ||
| npx clawpinch --show-suppressed | ||
|
|
||
| # 5. Full audit (ignore all suppressions) | ||
| npx clawpinch --no-ignore | ||
| ``` | ||
|
|
||
| ### JSON Output with Suppressions | ||
|
|
||
| When suppressions are configured, JSON output includes both `findings` and `suppressed` arrays: | ||
|
|
||
| ```json | ||
| { | ||
| "findings": [ | ||
| { | ||
| "id": "CHK-CFG-002", | ||
| "severity": "warn", | ||
| "title": "Debug mode enabled", | ||
| "description": "...", | ||
| "evidence": "...", | ||
| "remediation": "...", | ||
| "auto_fix": "" | ||
| } | ||
| ], | ||
| "suppressed": [ | ||
| { | ||
| "id": "CHK-CFG-001", | ||
| "severity": "critical", | ||
| "title": "Gateway listening on 0.0.0.0", | ||
| "description": "...", | ||
| "evidence": "...", | ||
| "remediation": "...", | ||
| "auto_fix": "", | ||
| "suppression": { | ||
| "reason": "Dev environment - reviewed by security team", | ||
| "expires": "2025-12-31T23:59:59Z", | ||
| "suppressed_by": "[email protected]" | ||
| } | ||
| } | ||
| ] | ||
| } | ||
| ``` | ||
|
|
||
| ### Use Cases | ||
|
|
||
| - **CI/CD Pipelines** -- Suppress accepted risks to prevent false positive failures | ||
| - **Development Environments** -- Suppress intentional misconfigurations (e.g., open gateways for debugging) | ||
| - **Gradual Remediation** -- Suppress findings while you work on fixes, set expiration dates to ensure follow-up | ||
| - **Security Review** -- Document accepted risks with justifications and approval metadata | ||
| - **Quarterly Audits** -- Use `--no-ignore` to perform full audits that include all suppressed findings | ||
|
|
||
| ### Example File | ||
|
|
||
| See `.clawpinch-ignore.json.example` in the repository for a fully documented template with multiple suppression examples. | ||
|
|
||
| --- | ||
|
|
||
| ## Example Output | ||
|
|
||
| ``` | ||
|
|
||
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -61,6 +61,12 @@ clawpinch --no-interactive | |
| # AI-powered remediation — scan then pipe to Claude for automated fixing | ||
| clawpinch --remediate | ||
|
|
||
| # Show suppressed findings in output (marked with [SUPPRESSED]) | ||
| clawpinch --show-suppressed | ||
|
|
||
| # Disable all suppressions for full audit scans | ||
| clawpinch --no-ignore | ||
|
|
||
| # Target specific config directory | ||
| clawpinch --config-dir /path/to/openclaw/config | ||
|
|
||
|
|
@@ -84,6 +90,17 @@ Each finding is a JSON object: | |
| } | ||
| ``` | ||
|
|
||
| When suppressions are enabled via `.clawpinch-ignore.json`, the output format changes: | ||
|
|
||
| ```json | ||
| { | ||
| "findings": [ /* active findings only */ ], | ||
| "suppressed": [ /* suppressed findings */ ] | ||
| } | ||
| ``` | ||
|
|
||
| Suppressed findings do not count toward severity totals or exit codes. | ||
|
|
||
| ## Check Categories | ||
|
|
||
| | Category | ID Range | Count | Description | | ||
|
|
@@ -121,6 +138,47 @@ npx clawpinch --json --no-interactive | jq '[.[] | select(.severity == "critical | |
| npx clawpinch --quiet --no-interactive | ||
| ``` | ||
|
|
||
| ## Finding Suppression | ||
|
|
||
| Suppress specific findings by creating `.clawpinch-ignore.json`: | ||
|
|
||
| ```json | ||
| { | ||
| "suppressions": [ | ||
| { | ||
| "id": "CHK-CFG-001", | ||
| "reason": "Dev environment - open gateway is intentional", | ||
| "expires": "2025-12-31T23:59:59Z", | ||
| "suppressed_by": "[email protected]", | ||
| "suppressed_at": "2024-01-15T10:30:00Z" | ||
| } | ||
| ] | ||
| } | ||
| ``` | ||
|
|
||
| **Fields:** | ||
| - `id` (required): Check ID to suppress | ||
| - `reason` (required): Justification for suppression | ||
| - `expires` (optional): ISO 8601 timestamp when suppression expires | ||
| - `suppressed_by` (optional): Email/identifier of approver | ||
| - `suppressed_at` (optional): ISO 8601 timestamp when created | ||
|
|
||
| **Behavior:** | ||
| - Suppressed findings appear in `suppressed` array, not `findings` | ||
| - Suppressed findings excluded from severity counts and exit codes | ||
| - Expired suppressions automatically reactivate | ||
| - `--show-suppressed`: Include suppressed findings in output with `[SUPPRESSED]` marker | ||
| - `--no-ignore`: Disable all suppressions for full audits | ||
|
|
||
| **Use cases:** | ||
| - **CI/CD:** Prevent pipeline failures from accepted risks | ||
| - **Development:** Suppress intentional misconfigurations in dev environments | ||
| - **Gradual remediation:** Suppress findings with expiration dates for periodic review | ||
| - **Security review:** Document accepted risks with justifications | ||
| - **Audits:** Use `--no-ignore` for quarterly full scans | ||
|
|
||
| See `.clawpinch-ignore.json.example` for detailed examples. | ||
|
|
||
| ## Dependencies | ||
|
|
||
| - **Required:** `bash` >= 4.0, `jq` | ||
|
|
@@ -139,5 +197,7 @@ npx clawpinch --quiet --no-interactive | |
|
|
||
| | Code | Meaning | | ||
| |------|---------| | ||
| | 0 | No critical findings | | ||
| | 1 | One or more critical findings detected | | ||
| | 0 | No active critical findings (suppressed findings excluded) | | ||
| | 1 | One or more active critical findings detected | | ||
|
|
||
| **Note:** Suppressed findings do not affect exit codes. Use `--no-ignore` to include suppressed findings in exit code calculation. | ||
Oops, something went wrong.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Documentation shows
suppressionobject in JSON output, butfilter_findings()atscripts/helpers/suppression.sh:173-185doesn't add it - just copies findings as-is.Either enrich findings with metadata or update docs to reflect actual output format.
Prompt To Fix With AI