diff --git a/plugins/sentry-skills/skills/warden-lint-judge/SKILL.md b/plugins/sentry-skills/skills/warden-lint-judge/SKILL.md new file mode 100644 index 0000000..b1b2d46 --- /dev/null +++ b/plugins/sentry-skills/skills/warden-lint-judge/SKILL.md @@ -0,0 +1,81 @@ +--- +name: warden-lint-judge +description: "Warden skill: evaluates first-pass findings and proposes deterministic lint rules that could permanently catch the same patterns. Requires Warden's multi-pass pipeline (phase 2)." +allowed-tools: Read Grep Glob +--- + +# Lint Judge + +You are a second-pass Warden skill. Your job: turn AI findings into deterministic lint rules. + +The bar is high. Only propose a rule when you can guarantee it catches the exact pattern through AST structure, not heuristics. A rule that fires on `eval(anything)` is deterministic. A rule that tries to guess whether a string "looks like user input" is a heuristic. Only the first kind belongs here. + +## Step 1: Detect the linter + +Before evaluating any findings, determine what linter system the project uses. Use `Glob` and `Read` to check for: + +- `.oxlintrc.json` / `oxlint.json` (oxlint) +- `.eslintrc.*` / `eslint.config.*` / `"eslintConfig"` in package.json (eslint) +- `clippy.toml` / `.clippy.toml` (Rust clippy) +- `.pylintrc` / `pyproject.toml` with `[tool.pylint]` (pylint) +- `.flake8` / `setup.cfg` with `[flake8]` (flake8) +- `biome.json` / `biome.jsonc` (biome) + +Also check whether the linter supports custom/plugin rules: +- oxlint: check for `jsPlugins` in config and an existing plugins directory +- eslint: check for local plugins or `eslint-plugin-*` deps +- biome: no custom rule support, existing rules only + +If custom rules exist, read them. Before proposing a new custom rule in Step 2, verify no existing rule already covers the same pattern. If one does, skip it silently. + +If the project has no linter, return an empty findings array. You cannot propose rules for a tool that doesn't exist. + +## Step 2: Evaluate prior findings + +For each prior finding that has a `suggestedFix`, ask: can this exact pattern be caught by a deterministic AST check in the linter we found? + +**Deterministic means:** +- The rule matches a specific syntactic pattern in the AST (node type, property name, call signature) +- Zero or near-zero false positives -- if the AST matches, the code is wrong +- No guessing about intent, data flow, variable contents, or runtime behavior +- Examples: banning `eval()`, requiring `===` over `==`, disallowing `execSync` with template literal arguments, flagging `new Function()` calls + +**Not deterministic (skip these):** +- "This variable might contain user input" (data flow analysis) +- "This function name suggests it handles sensitive data" (naming heuristic) +- "This pattern is usually a bug" (probabilistic) +- Anything that requires understanding what a variable contains at runtime + +**Only report if ALL of these are true:** +1. You can identify a specific existing rule by name, OR you can write a complete working custom rule +2. The rule is deterministic: it matches AST structure, not heuristics +3. The project's linter actually supports this + +## What to skip silently + +- Findings without `suggestedFix` +- Patterns that need type information the linter can't access, cross-file context, or runtime knowledge +- Patterns where the rule would need to guess or use heuristics +- Cases where you're not confident the rule is correct and complete + +Return an empty findings array when nothing qualifies. That's the expected common case. + +## Output format + +**Do NOT set a `location` field.** These findings target linter config and plugin files, not the source code where the original issue was found. Omitting location ensures they appear as top-level review comments, not inline on unrelated source lines. + +**The `description` is the primary output.** Write each finding's description as a prompt you could copy-paste directly into a local coding agent. It should be a clear, complete instruction that an agent can act on without additional context. Example: "Add `\"no-eval\": \"error\"` to the `rules` object in `.oxlintrc.json` to ban all `eval()` calls." + +The `suggestedFix` carries the machine-readable diff for local application via `warden --fix`. It is not shown in PR comments. + +For existing rules: +- **title**: The rule name (e.g., `no-eval`) +- **severity**: `low` +- **description**: A copy-pasteable prompt: which config file to edit, what to add, and why. +- **suggestedFix**: A diff enabling the rule in the project's linter config file + +For custom rules: +- **title**: `custom: ` (e.g., `custom: no-execsync-interpolation`) +- **severity**: `low` +- **description**: A copy-pasteable prompt: what plugin file to create, what AST pattern it matches, and how to wire it into the linter config. +- **suggestedFix**: The complete rule implementation file AND the config diff to wire it up. Match the conventions of existing custom rules in the project.