From ae889beee2445660847a2da54595410d467ff7cb Mon Sep 17 00:00:00 2001 From: "Sharad." Date: Sat, 12 Sep 2026 14:18:49 +0000 Subject: [PATCH] Allow ignore patterns to suppress findings by rule id Extend applyIgnores to match ignore substrings against ruleId as well as location, so configs like ignore: ["MCP001"] work as expected. Fixes #23 --- README.md | 2 +- src/audit.ts | 7 +++++-- src/config.ts | 2 +- test/audit.test.ts | 48 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 55 insertions(+), 4 deletions(-) create mode 100644 test/audit.test.ts diff --git a/README.md b/README.md index 7480b79..7ba19f4 100644 --- a/README.md +++ b/README.md @@ -126,7 +126,7 @@ mcp-audit discovers the nearest one walking up from the working directory. | `disabledRules` | Rule ids to skip entirely. | | `enabledRules` | If set, run **only** these rule ids. | | `severityOverrides` | Remap a rule's severity, e.g. downgrade a noisy check. | -| `ignore` | Substrings matched against a finding's location to suppress it. | +| `ignore` | Substrings matched against a finding's location or rule id to suppress it. | Severities, lowest to highest: `info`, `low`, `medium`, `high`, `critical`. diff --git a/src/audit.ts b/src/audit.ts index 3cceb10..46f8d70 100644 --- a/src/audit.ts +++ b/src/audit.ts @@ -4,7 +4,7 @@ import { ALL_RULES } from "./rules/index.js"; import type { AuditTarget, Finding, Rule, Severity } from "./types.js"; import type { McpAuditConfig } from "./config.js"; -/** Remove findings whose location matches any ignore substring. */ +/** Remove findings whose location or rule id matches any ignore substring. */ export function applyIgnores( findings: Finding[], ignore: string[], @@ -12,7 +12,10 @@ export function applyIgnores( if (ignore.length === 0) return findings; return findings.filter((f) => { const loc = f.location ?? ""; - return !ignore.some((pattern) => loc.includes(pattern)); + const id = f.ruleId; + return !ignore.some( + (pattern) => loc.includes(pattern) || id.includes(pattern), + ); }); } diff --git a/src/config.ts b/src/config.ts index 5a8d4c2..add4117 100644 --- a/src/config.ts +++ b/src/config.ts @@ -14,7 +14,7 @@ export interface McpAuditConfig { severityOverrides: Record; /** Findings at or above this severity cause a non-zero exit. */ failOn: Severity; - /** Location globs/substrings to ignore in findings. */ + /** Location or rule-id substrings to ignore in findings. */ ignore: string[]; } diff --git a/test/audit.test.ts b/test/audit.test.ts new file mode 100644 index 0000000..d232e7d --- /dev/null +++ b/test/audit.test.ts @@ -0,0 +1,48 @@ +import { describe, it, expect } from "vitest"; +import { applyIgnores, runAudit } from "../src/audit.js"; +import { normalizeConfig } from "../src/config.js"; +import { ALL_RULES } from "../src/rules/index.js"; +import { normalize } from "../src/static/manifest.js"; +import { insecureSurface } from "../fixtures/surfaces.mjs"; +import type { Finding } from "../src/types.js"; + +describe("applyIgnores", () => { + const sample: Finding[] = [ + { + ruleId: "MCP001", + severity: "high", + title: "Destructive tool", + message: "no confirm", + remediation: "add confirm", + location: "delete_file", + }, + { + ruleId: "MCP002", + severity: "critical", + title: "Exec", + message: "shell", + remediation: "scope", + location: "run_shell", + }, + ]; + + it("suppresses findings when ignore matches location", () => { + const filtered = applyIgnores(sample, ["delete_file"]); + expect(filtered.map((f) => f.ruleId)).toEqual(["MCP002"]); + }); + + it("suppresses findings when ignore matches rule id", () => { + const filtered = applyIgnores(sample, ["MCP001"]); + expect(filtered.map((f) => f.ruleId)).toEqual(["MCP002"]); + }); +}); + +describe("runAudit ignore by rule id", () => { + it("suppresses MCP001 findings when ignore lists the rule id", () => { + const target = normalize(insecureSurface, "insecure"); + const config = normalizeConfig({ ignore: ["MCP001"] }); + const result = runAudit(target, config, ALL_RULES); + expect(result.findings.some((f) => f.ruleId === "MCP001")).toBe(false); + expect(result.findings.some((f) => f.ruleId === "MCP002")).toBe(true); + }); +});