eslint-plugin-ai-guard 1.3.0 โ 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +683 -457
- package/dist/cli/index.js +469 -55
- package/dist/cli/index.js.map +1 -1
- package/dist/index.d.mts +6 -3
- package/dist/index.d.ts +6 -3
- package/dist/index.js +166 -66
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +165 -66
- package/dist/index.mjs.map +1 -1
- package/dist/mcp/server.js +4428 -0
- package/dist/mcp/server.js.map +1 -0
- package/package.json +103 -98
package/README.md
CHANGED
|
@@ -1,457 +1,683 @@
|
|
|
1
|
-
<p align="center">
|
|
2
|
-
<
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
</
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
**
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
-
|
|
138
|
-
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
|
157
|
-
|
|
158
|
-
| `
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
|
169
|
-
|
|
|
170
|
-
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
```
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
-
|
|
422
|
-
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
1
|
+
<p align="center">
|
|
2
|
+
<a href="https://getaiguard.dev">
|
|
3
|
+
<img src="./assets/logo/ai-guard-logo.png" alt="AI Guard Logo" width="260" />
|
|
4
|
+
</a>
|
|
5
|
+
</p>
|
|
6
|
+
|
|
7
|
+
<h1 align="center">AI Guard</h1>
|
|
8
|
+
|
|
9
|
+
<p align="center">
|
|
10
|
+
<strong>Deterministic AST safety layer and CI guardrails for AI-assisted JavaScript and TypeScript code.</strong>
|
|
11
|
+
</p>
|
|
12
|
+
|
|
13
|
+
<p align="center">
|
|
14
|
+
<a href="https://getaiguard.dev"><strong>Website</strong></a> โข
|
|
15
|
+
<a href="https://www.npmjs.com/package/eslint-plugin-ai-guard"><strong>npm Package</strong></a> โข
|
|
16
|
+
<a href="https://github.com/ai-guard-dev/eslint-plugin-ai-guard"><strong>GitHub Repository</strong></a> โข
|
|
17
|
+
<a href="./docs/rules/"><strong>Rules Catalog</strong></a> โข
|
|
18
|
+
<a href="./docs/benchmarks.md"><strong>Benchmarks</strong></a> โข
|
|
19
|
+
<a href="./docs/integrations/claude-code.md"><strong>Claude Code</strong></a> โข
|
|
20
|
+
<a href="./docs/getting-started.md"><strong>Documentation</strong></a>
|
|
21
|
+
</p>
|
|
22
|
+
|
|
23
|
+
<p align="center">
|
|
24
|
+
<a href="https://www.npmjs.com/package/eslint-plugin-ai-guard"><img src="https://img.shields.io/npm/v/eslint-plugin-ai-guard.svg?style=flat-square&color=0284c7" alt="npm version"></a>
|
|
25
|
+
<a href="https://github.com/ai-guard-dev/eslint-plugin-ai-guard/actions/workflows/ci.yml"><img src="https://img.shields.io/github/actions/workflow/status/ai-guard-dev/eslint-plugin-ai-guard/ci.yml?style=flat-square&label=CI&color=10b981" alt="CI Status"></a>
|
|
26
|
+
<a href="https://www.npmjs.com/package/eslint-plugin-ai-guard"><img src="https://img.shields.io/npm/dm/eslint-plugin-ai-guard.svg?style=flat-square&color=3b82f6" alt="npm downloads"></a>
|
|
27
|
+
<a href="https://github.com/ai-guard-dev/eslint-plugin-ai-guard/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-MIT-64748b?style=flat-square" alt="MIT License"></a>
|
|
28
|
+
<a href="https://github.com/ai-guard-dev/eslint-plugin-ai-guard/blob/main/SECURITY.md"><img src="https://img.shields.io/badge/security-policy-orange?style=flat-square" alt="Security Policy"></a>
|
|
29
|
+
<a href="https://getaiguard.dev"><img src="https://img.shields.io/badge/website-getaiguard.dev-0ea5e9?style=flat-square" alt="Website"></a>
|
|
30
|
+
</p>
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## What is AI Guard?
|
|
35
|
+
|
|
36
|
+
**AI Guard** (`eslint-plugin-ai-guard`) provides:
|
|
37
|
+
- **ESLint plugin** with 18 deterministic rules and 4 presets (`recommended`, `strict`, `security`, `agent`)
|
|
38
|
+
- **CLI** (`ai-guard`) for terminal, changed-file, and CI scanning
|
|
39
|
+
- **GitHub Action** with native SARIF 2.1.0 output for GitHub Code Scanning
|
|
40
|
+
- **Claude Code integration** with a zero-config PostToolUse hook
|
|
41
|
+
- **MCP server** (`ai-guard-mcp`) for local AI-agent workflows (Claude Code, Claude Desktop, Antigravity)
|
|
42
|
+
|
|
43
|
+
It is engineered to detect reliability bugs, async hazards, security vulnerabilities, and code-scaffolding defects frequently introduced during AI-assisted development (GitHub Copilot, Cursor, Claude Code, Gemini Code Assist, etc.).
|
|
44
|
+
|
|
45
|
+
AI Guard analyzes Abstract Syntax Trees (AST) using ESLint's native engine. It runs locally in your editor, in your terminal via the zero-config CLI, and in your CI/CD pipelines via native SARIF 2.1.0 integration with GitHub Code Scanning.
|
|
46
|
+
|
|
47
|
+
### What AI Guard is NOT
|
|
48
|
+
|
|
49
|
+
> [!IMPORTANT]
|
|
50
|
+
> - **AI Guard is NOT an AI detector.** It does not attempt to predict whether code was authored by an LLM or a human.
|
|
51
|
+
> - **AI Guard detects dangerous or fragile code patterns** that LLMs repeatedly introduce due to incomplete context, hallucinated patterns, or probabilistic generation.
|
|
52
|
+
> - **AI Guard does NOT replace ESLint.** It extends ESLint with 18 specialized, high-impact rules that core ESLint and standard configurations omit.
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## Why AI Guard?
|
|
57
|
+
|
|
58
|
+
AI coding assistants write code at remarkable velocity, but generated code repeatedly suffers from predictable reliability and security anti-patterns that conventional linters miss:
|
|
59
|
+
|
|
60
|
+
| Pattern | Why AI Assistants Generate It | Real-World Impact |
|
|
61
|
+
| :--- | :--- | :--- |
|
|
62
|
+
| **Floating Promises** | Omits `await`, `return`, or `.catch()` on async calls | Unhandled promise rejections, silent failures in background jobs |
|
|
63
|
+
| **Async Array Iteration** | Passes async callbacks into `array.map()` or `.filter()` | Returns unawaited `Promise[]` instead of resolved values |
|
|
64
|
+
| **Sequential Awaits in Loops** | Loops over items with sequential `await` | Significant latency bottlenecks; blocks event loop execution |
|
|
65
|
+
| **Empty Catch Blocks** | Inserts generic `try { ... } catch (e) {}` blocks | Swallows production exceptions silently without telemetry |
|
|
66
|
+
| **Hardcoded Secrets** | Injects placeholder or real API keys/tokens | Credential leakage in version control and deployment bundles |
|
|
67
|
+
| **Dynamic `eval()`** | Generates dynamic function compilation | Arbitrary code execution and code injection |
|
|
68
|
+
| **Raw SQL Concatenation** | Concatenates query strings with variables | Severe SQL injection vulnerabilities |
|
|
69
|
+
| **Unsafe Deserialization** | Calls `JSON.parse(req.body)` directly without schema checks | Denial of service and unhandled runtime crashes |
|
|
70
|
+
| **Missing Route Auth & Authz** | Emits boilerplate endpoints without auth middleware | Unprotected API endpoints and IDOR privilege escalations |
|
|
71
|
+
| **Dead Branches & Scaffolding** | Leaves `if (true)` or conflicting conditions from prompt iterations | Bloated bundles and dead code paths |
|
|
72
|
+
|
|
73
|
+
AI Guard provides an instantaneous, deterministic feedback loop that catches these issues before they reach pull requests or production.
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## Architecture & Workflow
|
|
78
|
+
|
|
79
|
+
```mermaid
|
|
80
|
+
flowchart TD
|
|
81
|
+
subgraph Dev["1. Development & Prompt Phase"]
|
|
82
|
+
A["Developer + AI Coding Assistant\n(Copilot, Cursor, Claude Code)"] --> B["JavaScript / TypeScript Code"]
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
subgraph ShiftLeft["Shift Left โ Context Injection"]
|
|
86
|
+
SL["npx ai-guard init-context"] -.-> CTX["CLAUDE.md\n.cursorrules\ncopilot-instructions.md"]
|
|
87
|
+
CTX -.-> A
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
subgraph Analysis["2. Deterministic AST Analysis"]
|
|
91
|
+
B --> C["ESLint Parser\n(espree / @typescript-eslint/parser)"]
|
|
92
|
+
C --> D["AST Representation"]
|
|
93
|
+
D --> E["AI Guard Rules Engine\n(18 Deterministic Rules)"]
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
subgraph Tiers["3. Classification & Presets"]
|
|
97
|
+
E --> F{"Active Preset\n(recommended | strict | security | agent)"}
|
|
98
|
+
F --> G["Confidence Tiering & AST Filtering"]
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
subgraph Outputs["4. Output & Remediation"]
|
|
102
|
+
G --> H["Local CLI Scanning\n(ai-guard run / changed)"]
|
|
103
|
+
G --> I["Autofix Remediation\n(eslint --fix)"]
|
|
104
|
+
G --> J["HTML Dashboard\n(ai-guard report)"]
|
|
105
|
+
G --> K["SARIF 2.1.0 Artifact\n(ai-guard --sarif)"]
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
subgraph CI["5. GitHub Pull Request & CI/CD"]
|
|
109
|
+
K --> L["GitHub Action\nai-guard-dev/eslint-plugin-ai-guard@v1"]
|
|
110
|
+
L --> M["GitHub Code Scanning Alerts"]
|
|
111
|
+
L --> N["Inline PR Code Annotations"]
|
|
112
|
+
L --> O["PR Status Check (Blocks Merge)"]
|
|
113
|
+
end
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
## Rules Catalog
|
|
119
|
+
|
|
120
|
+
AI Guard includes **18 deterministic rules** divided into four specialized categories. Every rule is engineered with low false-positive heuristics and validated against real-world production codebases:
|
|
121
|
+
|
|
122
|
+
### ๐ด Security (6 Rules)
|
|
123
|
+
|
|
124
|
+
| Rule | Recommended | What It Catches | Fixable? |
|
|
125
|
+
| :--- | :---: | :--- | :---: |
|
|
126
|
+
| [`no-hardcoded-secret`](./docs/rules/no-hardcoded-secret.md) | **`error`** | API keys, bearer tokens, passwords, and private keys committed directly in source code. | **Yes** (`process.env.*`) |
|
|
127
|
+
| [`no-eval-dynamic`](./docs/rules/no-eval-dynamic.md) | **`error`** | `eval()`, `new Function()`, and `setTimeout`/`setInterval` with dynamic/non-literal string expressions. | No |
|
|
128
|
+
| [`no-sql-string-concat`](./docs/rules/no-sql-string-concat.md) | `warn` | SQL queries constructed by string concatenation or raw template literals โ SQL injection risks. | No |
|
|
129
|
+
| [`no-unsafe-deserialize`](./docs/rules/no-unsafe-deserialize.md) | `warn` | Unchecked `JSON.parse()` called directly on HTTP request inputs (`req.body`, `req.query`, `req.params`). | No |
|
|
130
|
+
| [`require-auth-middleware`](./docs/rules/require-auth-middleware.md) | `warn` | Express and Fastify route definitions exposed without authentication middleware. | No |
|
|
131
|
+
| [`require-authz-check`](./docs/rules/require-authz-check.md) | `warn` | Endpoints accessing sensitive resources or user IDs without tenant/ownership authorization checks. | No |
|
|
132
|
+
|
|
133
|
+
### ๐ Reliability (4 Rules)
|
|
134
|
+
|
|
135
|
+
| Rule | Recommended | What It Catches | Fixable? |
|
|
136
|
+
| :--- | :---: | :--- | :---: |
|
|
137
|
+
| [`no-empty-catch`](./docs/rules/no-empty-catch.md) | **`error`** | Empty `catch (e) {}` blocks that silently swallow exceptions without logging or rethrowing. | **Yes** (inserts `/* TODO: handle error */`) |
|
|
138
|
+
| [`no-broad-exception`](./docs/rules/no-broad-exception.md) | `warn` | Catching broad exception types like `catch (e: any)` that mask system faults and typing. | No |
|
|
139
|
+
| [`no-catch-log-rethrow`](./docs/rules/no-catch-log-rethrow.md) | `off`* | Catch blocks that only log to `console` and rethrow without adding context or diagnostic info. | No |
|
|
140
|
+
| [`no-catch-without-use`](./docs/rules/no-catch-without-use.md) | `off`* | Caught error variables that are declared in catch parameters but never referenced. | No |
|
|
141
|
+
|
|
142
|
+
### ๐ก Async Stability (5 Rules)
|
|
143
|
+
|
|
144
|
+
| Rule | Recommended | What It Catches | Fixable? |
|
|
145
|
+
| :--- | :---: | :--- | :---: |
|
|
146
|
+
| [`no-floating-promise`](./docs/rules/no-floating-promise.md) | **`error`** | Async function invocations without `await`, `.catch()`, or `return` โ leading to silent dropped errors. | **Yes** (marks with `void`) |
|
|
147
|
+
| [`no-async-array-callback`](./docs/rules/no-async-array-callback.md) | `warn` | Async callbacks passed to `map()`, `filter()`, `forEach()`, or `reduce()` returning `Promise[]`. | No |
|
|
148
|
+
| [`no-await-in-loop`](./docs/rules/no-await-in-loop.md) | `warn` | Sequential `await` in loops where iterations can be safely executed concurrently with `Promise.all`. | **Yes** (rewrites to `Promise.all`) |
|
|
149
|
+
| [`no-async-without-await`](./docs/rules/no-async-without-await.md) | `warn` | Functions declared `async` that never execute an `await` expression, adding unnecessary Promise overhead. | No |
|
|
150
|
+
| [`no-redundant-await`](./docs/rules/no-redundant-await.md) | `off`* | Redundant `return await` statements outside of `try...catch` blocks. | No |
|
|
151
|
+
|
|
152
|
+
### ๐ต AI Patterns (3 Rules)
|
|
153
|
+
|
|
154
|
+
| Rule | Recommended | What It Catches | Fixable? |
|
|
155
|
+
| :--- | :---: | :--- | :---: |
|
|
156
|
+
| [`no-dead-branch`](./docs/rules/no-dead-branch.md) | `warn` | Unreachable or tautological branches (`if (true)`, `if (false)`, `x && !x`) left behind from LLM code synthesis. | No |
|
|
157
|
+
| [`no-duplicate-logic-block`](./docs/rules/no-duplicate-logic-block.md) | `off`* | Consecutive duplicate code blocks or repeated conditional branches duplicated during AI edits. | No |
|
|
158
|
+
| [`no-console-in-handler`](./docs/rules/no-console-in-handler.md) | `off`* | Unstructured `console.log` statements left in HTTP route handlers instead of production loggers. | No |
|
|
159
|
+
|
|
160
|
+
*\* Enabled at `error` level in the `strict` preset.*
|
|
161
|
+
|
|
162
|
+
---
|
|
163
|
+
|
|
164
|
+
## Presets
|
|
165
|
+
|
|
166
|
+
AI Guard exports four official configurations ready for flat config or legacy setups:
|
|
167
|
+
|
|
168
|
+
| Preset | Description | Configuration Focus |
|
|
169
|
+
| :--- | :--- | :--- |
|
|
170
|
+
| **`recommended`** | **Default.** Balanced adoption preset. Enables 4 high-confidence critical rules at `error`, 9 context-sensitive rules at `warn`, and disables 5 noisy rules. Zero noise on day one. | Production codebases, new teams |
|
|
171
|
+
| **`strict`** | Enforces **all 18 rules at `error`**. Designed for zero-tolerance CI gates, high-assurance software, and mature teams. | Strict CI/CD quality gates |
|
|
172
|
+
| **`security`** | Focuses exclusively on the **6 security rules** (`no-hardcoded-secret`, `no-eval-dynamic`, `no-sql-string-concat` at `error`; remainder at `warn`). | AppSec auditing & security scans |
|
|
173
|
+
| **`agent`** | **5 high-signal rules at `error`**. Optimized for AI-agent editing workflows where lint feedback runs immediately after each file edit (e.g., PostToolUse hooks). | Claude Code, Cursor, real-time agent loops |
|
|
174
|
+
|
|
175
|
+
---
|
|
176
|
+
|
|
177
|
+
## Quick Start & Installation
|
|
178
|
+
|
|
179
|
+
Install the package as a development dependency using your package manager:
|
|
180
|
+
|
|
181
|
+
```bash
|
|
182
|
+
# npm
|
|
183
|
+
npm install --save-dev eslint-plugin-ai-guard
|
|
184
|
+
|
|
185
|
+
# pnpm
|
|
186
|
+
pnpm add -D eslint-plugin-ai-guard
|
|
187
|
+
|
|
188
|
+
# yarn
|
|
189
|
+
yarn add -D eslint-plugin-ai-guard
|
|
190
|
+
|
|
191
|
+
# bun
|
|
192
|
+
bun add -d eslint-plugin-ai-guard
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
### Requirements
|
|
196
|
+
|
|
197
|
+
- **Node.js:** `>= 20.0.0`
|
|
198
|
+
- **ESLint:** `>= 8.0.0` (Supports both Flat Config and legacy configs)
|
|
199
|
+
- **TypeScript (optional):** `@typescript-eslint/parser >= 6.0.0` for TypeScript AST parsing
|
|
200
|
+
|
|
201
|
+
---
|
|
202
|
+
|
|
203
|
+
## ESLint Configuration
|
|
204
|
+
|
|
205
|
+
### 1. Modern Flat Config (`eslint.config.mjs` / `eslint.config.js`)
|
|
206
|
+
|
|
207
|
+
AI Guard exports full native support for modern ESLint Flat Config:
|
|
208
|
+
|
|
209
|
+
```javascript
|
|
210
|
+
// eslint.config.mjs
|
|
211
|
+
import aiGuard from 'eslint-plugin-ai-guard';
|
|
212
|
+
|
|
213
|
+
export default [
|
|
214
|
+
{
|
|
215
|
+
plugins: {
|
|
216
|
+
'ai-guard': aiGuard,
|
|
217
|
+
},
|
|
218
|
+
rules: {
|
|
219
|
+
...aiGuard.configs.recommended.rules,
|
|
220
|
+
// Custom overrides if desired:
|
|
221
|
+
'ai-guard/no-floating-promise': 'error',
|
|
222
|
+
},
|
|
223
|
+
},
|
|
224
|
+
];
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
To use the `strict` or `security` preset in flat config:
|
|
228
|
+
|
|
229
|
+
```javascript
|
|
230
|
+
// Strict preset โ all 18 rules at error
|
|
231
|
+
rules: {
|
|
232
|
+
...aiGuard.configs.strict.rules,
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// Security preset โ security rules only
|
|
236
|
+
rules: {
|
|
237
|
+
...aiGuard.configs.security.rules,
|
|
238
|
+
}
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
### 2. Legacy Config (`.eslintrc.js` / `.eslintrc.json`)
|
|
242
|
+
|
|
243
|
+
```javascript
|
|
244
|
+
// .eslintrc.js
|
|
245
|
+
module.exports = {
|
|
246
|
+
plugins: ['ai-guard'],
|
|
247
|
+
extends: ['plugin:ai-guard/recommended'],
|
|
248
|
+
};
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
---
|
|
252
|
+
|
|
253
|
+
## CLI Reference
|
|
254
|
+
|
|
255
|
+
AI Guard includes a full-featured CLI binary (`ai-guard`) that runs out of the box with zero ESLint configuration files required:
|
|
256
|
+
|
|
257
|
+
```bash
|
|
258
|
+
npx ai-guard <command> [options]
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
### Core Commands
|
|
262
|
+
|
|
263
|
+
| Command | Purpose | Common Options |
|
|
264
|
+
| :--- | :--- | :--- |
|
|
265
|
+
| `run` | Scan your workspace using AI Guard AST rules | `--path <dir>`, `--strict`, `--security`, `--json`, `--sarif`, `--fail-on <level>`, `--max-warnings <n>` |
|
|
266
|
+
| `changed` | Fast CI scan โ only scans modified files in git | `--pr`, `--staged`, `--base <branch>`, `--strict`, `--sarif`, `--sarif-output <file>`, `--fail-on <level>` |
|
|
267
|
+
| `init` | Automatically detect environment & configure ESLint | `--preset <name>`, `--flat`, `--dry-run`, `-y, --yes` |
|
|
268
|
+
| `init-context` | Generate prompt instruction files for AI coding agents | `-a, --all`, `--force`, `--dry-run`, `--rules <categories>` |
|
|
269
|
+
| `doctor` | Diagnose your ESLint, parser, and plugin environment | (No options needed โ prints actionable diagnostic report) |
|
|
270
|
+
| `baseline` | Snapshot current issues to track only new regressions | `--save`, `--check`, `--mode <strict\|stable>`, `--preset <name>` |
|
|
271
|
+
| `report` | Generate an interactive standalone HTML audit report | `--path <dir>`, `--preset <name>`, `--output <file>`, `--no-open`, `--json` |
|
|
272
|
+
| `preset` | Interactively select and switch active preset in config | (Interactive prompt with automatic config patch & backup) |
|
|
273
|
+
| `ignore` | Add standard ignore paths (`.next`, `dist`, `build`) to config | (Patches flat config or legacy ignores safely) |
|
|
274
|
+
|
|
275
|
+
### CLI Usage Examples
|
|
276
|
+
|
|
277
|
+
```bash
|
|
278
|
+
# 1. Immediate scan of current directory
|
|
279
|
+
npx ai-guard run
|
|
280
|
+
|
|
281
|
+
# 2. Strict CI scan failing only on high-confidence issues
|
|
282
|
+
npx ai-guard run --strict --fail-on high
|
|
283
|
+
|
|
284
|
+
# 3. Pull Request scan (diffs against PR target branch)
|
|
285
|
+
npx ai-guard changed --pr --sarif --sarif-output results.sarif
|
|
286
|
+
|
|
287
|
+
# 4. Generate AI agent guardrails for Cursor, Claude Code, and Copilot
|
|
288
|
+
npx ai-guard init-context --all
|
|
289
|
+
|
|
290
|
+
# 5. Generate interactive HTML diagnostic report
|
|
291
|
+
npx ai-guard report --output ai-guard-report.html
|
|
292
|
+
|
|
293
|
+
# 6. Save existing issues as baseline and only fail on new regressions
|
|
294
|
+
npx ai-guard baseline --save
|
|
295
|
+
npx ai-guard baseline --check
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
---
|
|
299
|
+
|
|
300
|
+
## AI Agent Integration (`init-context`)
|
|
301
|
+
|
|
302
|
+
Standard linters only run **after** code has already been written. The `init-context` command shifts your guardrails left by embedding AI Guard's rules directly into the instruction files loaded by your AI coding tools:
|
|
303
|
+
|
|
304
|
+
```bash
|
|
305
|
+
npx ai-guard init-context --all
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
This generates three targeted context files:
|
|
309
|
+
1. **`CLAUDE.md`** โ Automatically loaded by **Claude Code**
|
|
310
|
+
2. **`.cursorrules`** โ Automatically loaded by **Cursor**
|
|
311
|
+
3. **`.github/copilot-instructions.md`** โ Automatically loaded by **GitHub Copilot**
|
|
312
|
+
|
|
313
|
+
### How Shift-Left Works
|
|
314
|
+
|
|
315
|
+
```
|
|
316
|
+
AI Guard (init-context)
|
|
317
|
+
โ
|
|
318
|
+
Generates project guardrail files (CLAUDE.md, .cursorrules, copilot-instructions.md)
|
|
319
|
+
โ
|
|
320
|
+
AI coding assistant reads safety rules before generating code
|
|
321
|
+
โ
|
|
322
|
+
Model avoids floating promises, empty catches, and hardcoded secrets at prompt time
|
|
323
|
+
โ
|
|
324
|
+
AI Guard CLI & GitHub Action deterministically verifies the output in CI
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
This dual-layer defense minimizes review friction and ensures generated code meets your security standard on the first pass.
|
|
328
|
+
|
|
329
|
+
---
|
|
330
|
+
|
|
331
|
+
## Claude Code Integration
|
|
332
|
+
|
|
333
|
+
AI Guard integrates directly with [Claude Code](https://docs.anthropic.com/en/docs/claude-code) as a **PostToolUse validation hook**. Every time Claude Code edits or writes a JS/TS file, AI Guard automatically scans it for common issues.
|
|
334
|
+
|
|
335
|
+
```bash
|
|
336
|
+
# One-command setup
|
|
337
|
+
npx ai-guard init-claude
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
This configures a PostToolUse hook in `.claude/settings.json` that runs AI Guard's fast `agent` preset (5 high-confidence rules, ~50-200ms per file) after every file edit. Claude Code reads the diagnostics and can fix issues automatically.
|
|
341
|
+
|
|
342
|
+
```bash
|
|
343
|
+
# Preview before applying
|
|
344
|
+
npx ai-guard init-claude --dry-run
|
|
345
|
+
|
|
346
|
+
# Use per-machine settings (gitignored)
|
|
347
|
+
npx ai-guard init-claude --local
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
**Agent preset rules:** `no-hardcoded-secret`, `no-eval-dynamic`, `no-empty-catch`, `no-sql-string-concat`, `no-floating-promise`
|
|
351
|
+
|
|
352
|
+
โ [Full documentation](./docs/integrations/claude-code.md)
|
|
353
|
+
|
|
354
|
+
---
|
|
355
|
+
|
|
356
|
+
## GitHub Action
|
|
357
|
+
|
|
358
|
+
The official AI Guard GitHub Action runs on PRs, detects changed files, provides step summaries, outputs SARIF 2.1.0, and posts inline PR annotations directly on GitHub:
|
|
359
|
+
|
|
360
|
+
```yaml
|
|
361
|
+
# .github/workflows/ai-guard.yml
|
|
362
|
+
name: AI Guard
|
|
363
|
+
|
|
364
|
+
on:
|
|
365
|
+
pull_request:
|
|
366
|
+
branches: [main, develop]
|
|
367
|
+
push:
|
|
368
|
+
branches: [main]
|
|
369
|
+
|
|
370
|
+
jobs:
|
|
371
|
+
ai-guard-scan:
|
|
372
|
+
name: AI Guard Code Review
|
|
373
|
+
runs-on: ubuntu-latest
|
|
374
|
+
|
|
375
|
+
permissions:
|
|
376
|
+
contents: read
|
|
377
|
+
security-events: write
|
|
378
|
+
actions: read
|
|
379
|
+
|
|
380
|
+
steps:
|
|
381
|
+
- name: Checkout Code
|
|
382
|
+
uses: actions/checkout@v4
|
|
383
|
+
with:
|
|
384
|
+
fetch-depth: 0 # Required for git diff comparison
|
|
385
|
+
|
|
386
|
+
- name: Setup Node.js
|
|
387
|
+
uses: actions/setup-node@v4
|
|
388
|
+
with:
|
|
389
|
+
node-version: 20
|
|
390
|
+
cache: 'npm'
|
|
391
|
+
|
|
392
|
+
- name: Run AI Guard
|
|
393
|
+
uses: ai-guard-dev/eslint-plugin-ai-guard@v1
|
|
394
|
+
with:
|
|
395
|
+
preset: 'recommended'
|
|
396
|
+
fail-on: 'high'
|
|
397
|
+
changed-only: 'true'
|
|
398
|
+
upload-sarif: 'true'
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
### Action Inputs (`action.yml`)
|
|
402
|
+
|
|
403
|
+
| Input | Description | Default |
|
|
404
|
+
| :--- | :--- | :---: |
|
|
405
|
+
| `preset` | Rule preset: `recommended` \| `strict` \| `security` | `'recommended'` |
|
|
406
|
+
| `fail-on` | Severity threshold to fail CI: `high` \| `medium` \| `any` \| `none` | `'high'` |
|
|
407
|
+
| `changed-only` | Scan only files changed in this PR / commit | `'true'` |
|
|
408
|
+
| `path` | Target file or directory to scan | `'.'` |
|
|
409
|
+
| `upload-sarif` | Upload results to GitHub Code Scanning | `'true'` |
|
|
410
|
+
| `github-summary` | Write an execution breakdown to the GitHub Actions Job Summary | `'true'` |
|
|
411
|
+
| `working-directory`| Working directory for scanning (ideal for monorepos) | `'.'` |
|
|
412
|
+
| `package-manager` | Package manager: `auto` \| `npm` \| `pnpm` \| `yarn` | `'auto'` |
|
|
413
|
+
| `sarif-output` | Output filepath for generated SARIF report | `'ai-guard-results.sarif'` |
|
|
414
|
+
| `install-deps` | Install project dependencies prior to scanning | `'true'` |
|
|
415
|
+
|
|
416
|
+
### Action Outputs
|
|
417
|
+
|
|
418
|
+
| Output | Description |
|
|
419
|
+
| :--- | :--- |
|
|
420
|
+
| `issues-found` | Total number of issues found across scanned files |
|
|
421
|
+
| `high-confidence-count` | Number of high-confidence issues flagged |
|
|
422
|
+
| `medium-confidence-count` | Number of medium-confidence issues flagged |
|
|
423
|
+
| `files-scanned` | Count of files analyzed during the execution |
|
|
424
|
+
| `sarif-file` | Absolute path to the generated SARIF 2.1.0 artifact |
|
|
425
|
+
| `duration-ms` | Total scan execution duration in milliseconds |
|
|
426
|
+
|
|
427
|
+
---
|
|
428
|
+
|
|
429
|
+
## SARIF & GitHub Code Scanning
|
|
430
|
+
|
|
431
|
+
AI Guard natively outputs **SARIF 2.1.0** (`Static Analysis Results Interchange Format`). When uploaded via the GitHub Action or `github/codeql-action/upload-sarif@v3`, findings integrate directly with GitHub Advanced Security:
|
|
432
|
+
|
|
433
|
+
- **Inline PR Annotations:** Direct comments on the exact source lines where flaws exist.
|
|
434
|
+
- **Security Dashboard:** Persistent alerts under your repository's `Security โ Code scanning` tab.
|
|
435
|
+
- **Merge Protection:** Block merges automatically when high-confidence security or async bugs are detected.
|
|
436
|
+
|
|
437
|
+
### Visual Previews
|
|
438
|
+
|
|
439
|
+
#### Inline Pull Request Annotations
|
|
440
|
+
<img src="./assets/ss9.jpg" alt="AI Guard PR Inline Annotations" width="1000" />
|
|
441
|
+
|
|
442
|
+
#### GitHub Advanced Security Summary
|
|
443
|
+
<img src="./assets/ss10.jpg" alt="GitHub Advanced Security Summary for AI Guard" width="1000" />
|
|
444
|
+
|
|
445
|
+
#### Persistent Code Scanning Dashboard
|
|
446
|
+
<img src="./assets/ss11.jpg" alt="GitHub Code Scanning Alerts List" width="1000" />
|
|
447
|
+
|
|
448
|
+
---
|
|
449
|
+
|
|
450
|
+
## Rule Examples (Before & After)
|
|
451
|
+
|
|
452
|
+
### 1. `no-floating-promise` (Unhandled Promises)
|
|
453
|
+
|
|
454
|
+
```typescript
|
|
455
|
+
// โ BAD: Floating promise. Errors are dropped silently.
|
|
456
|
+
async function syncUserProfile(user: User) {
|
|
457
|
+
sendTelemetryEvent('user_sync', user.id);
|
|
458
|
+
database.save(user);
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
// โ
GOOD: Awaited, explicitly handled, or marked with void
|
|
462
|
+
async function syncUserProfile(user: User) {
|
|
463
|
+
await database.save(user);
|
|
464
|
+
void sendTelemetryEvent('user_sync', user.id); // Explicitly unhandled
|
|
465
|
+
}
|
|
466
|
+
```
|
|
467
|
+
|
|
468
|
+
### 2. `no-hardcoded-secret` (Committed Credentials)
|
|
469
|
+
|
|
470
|
+
```typescript
|
|
471
|
+
// โ BAD: Secret committed inline
|
|
472
|
+
const client = new PaymentGateway({
|
|
473
|
+
apiKey: 'sk-prod-983427598273498273948273',
|
|
474
|
+
});
|
|
475
|
+
|
|
476
|
+
// โ
GOOD: Read from environment variable (Autofixable!)
|
|
477
|
+
const client = new PaymentGateway({
|
|
478
|
+
apiKey: process.env.API_KEY,
|
|
479
|
+
});
|
|
480
|
+
```
|
|
481
|
+
|
|
482
|
+
### 3. `no-await-in-loop` (Sequential Latency Trap)
|
|
483
|
+
|
|
484
|
+
```typescript
|
|
485
|
+
// โ BAD: Consecutive awaits block each iteration sequentially
|
|
486
|
+
async function fetchAllUsers(ids: string[]) {
|
|
487
|
+
const users = [];
|
|
488
|
+
for (const id of ids) {
|
|
489
|
+
users.push(await fetchUser(id));
|
|
490
|
+
}
|
|
491
|
+
return users;
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
// โ
GOOD: Concurrently fetched with Promise.all (Autofixable!)
|
|
495
|
+
async function fetchAllUsers(ids: string[]) {
|
|
496
|
+
return await Promise.all(ids.map((id) => fetchUser(id)));
|
|
497
|
+
}
|
|
498
|
+
```
|
|
499
|
+
|
|
500
|
+
### 4. `no-empty-catch` (Swallowed Errors)
|
|
501
|
+
|
|
502
|
+
```typescript
|
|
503
|
+
// โ BAD: Exception swallowed without trace
|
|
504
|
+
try {
|
|
505
|
+
parseConfiguration(rawConfig);
|
|
506
|
+
} catch (e) {}
|
|
507
|
+
|
|
508
|
+
// โ
GOOD: Logged, rethrown, or documented (Autofixable!)
|
|
509
|
+
try {
|
|
510
|
+
parseConfiguration(rawConfig);
|
|
511
|
+
} catch (e) {
|
|
512
|
+
logger.error('Configuration parsing failed', { error: e });
|
|
513
|
+
throw e;
|
|
514
|
+
}
|
|
515
|
+
```
|
|
516
|
+
|
|
517
|
+
### 5. `no-sql-string-concat` (SQL Injection)
|
|
518
|
+
|
|
519
|
+
```typescript
|
|
520
|
+
// โ BAD: Dynamic string interpolation in SQL
|
|
521
|
+
const query = `SELECT * FROM users WHERE organization_id = '${orgId}' AND role = '${role}'`;
|
|
522
|
+
await db.query(query);
|
|
523
|
+
|
|
524
|
+
// โ
GOOD: Parameterized query binding
|
|
525
|
+
const query = 'SELECT * FROM users WHERE organization_id = $1 AND role = $2';
|
|
526
|
+
await db.query(query, [orgId, role]);
|
|
527
|
+
```
|
|
528
|
+
|
|
529
|
+
---
|
|
530
|
+
|
|
531
|
+
## Automatic Remediation (Autofix)
|
|
532
|
+
|
|
533
|
+
Rules that have deterministic solutions provide automatic autofix handlers. Run ESLint's native `--fix` flag to automatically resolve them:
|
|
534
|
+
|
|
535
|
+
```bash
|
|
536
|
+
npx eslint . --fix
|
|
537
|
+
```
|
|
538
|
+
|
|
539
|
+
| Rule | Automatic Fix Behavior |
|
|
540
|
+
| :--- | :--- |
|
|
541
|
+
| `no-hardcoded-secret` | Replaces hardcoded string literal with `process.env.VARIABLE_NAME` |
|
|
542
|
+
| `no-empty-catch` | Inserts `/* TODO: handle error */` comment to prevent silent swallowing |
|
|
543
|
+
| `no-floating-promise` | Prepends `void ` expression to intentionally unawaited calls |
|
|
544
|
+
| `no-await-in-loop` | Rewrites straightforward sequential loops to `await Promise.all(...)` |
|
|
545
|
+
|
|
546
|
+
---
|
|
547
|
+
|
|
548
|
+
## Benchmarks & Empirical Evaluation
|
|
549
|
+
|
|
550
|
+
AI Guard has been empirically evaluated across multiple benchmarks comparing runtime scan performance, coverage gaps vs. standard tooling, and detection accuracy across real-world codebases.
|
|
551
|
+
|
|
552
|
+
### 1. What AI Guard Catches vs. Conventional Linters
|
|
553
|
+
|
|
554
|
+
Conventional linters either omit AI-specific hazards entirely or require heavyweight TypeScript type-checking (`parserOptions.project`) that significantly slows down CI:
|
|
555
|
+
|
|
556
|
+
| Pattern | AI Guard Rule | ESLint Core | `@typescript-eslint` |
|
|
557
|
+
| :--- | :--- | :---: | :--- |
|
|
558
|
+
| **Floating Promises** (unawaited async call) | [`no-floating-promise`](./docs/rules/no-floating-promise.md) | โ None | `@typescript-eslint/no-floating-promises` *(requires type info)* |
|
|
559
|
+
| **Async Array Callbacks** (`.map(async ...)`) | [`no-async-array-callback`](./docs/rules/no-async-array-callback.md) | โ None | Partial: `no-misused-promises` *(requires type info)* |
|
|
560
|
+
| **Empty Catch Blocks** (swallowed errors) | [`no-empty-catch`](./docs/rules/no-empty-catch.md) | `no-empty` *(weaker)* | โ None |
|
|
561
|
+
| **Hardcoded Secrets / API Tokens** | [`no-hardcoded-secret`](./docs/rules/no-hardcoded-secret.md) | โ None | โ None |
|
|
562
|
+
| **Raw SQL String Concatenation** | [`no-sql-string-concat`](./docs/rules/no-sql-string-concat.md) | โ None | โ None |
|
|
563
|
+
| **Missing Route Auth Middleware** | [`require-auth-middleware`](./docs/rules/require-auth-middleware.md) | โ None | โ None |
|
|
564
|
+
| **Missing Route Authorization Checks** | [`require-authz-check`](./docs/rules/require-authz-check.md) | โ None | โ None |
|
|
565
|
+
| **Dynamic `eval()` / `new Function()`** | [`no-eval-dynamic`](./docs/rules/no-eval-dynamic.md) | `no-eval` *(blanket ban)* | โ None |
|
|
566
|
+
| **Unsafe `JSON.parse(req.body)`** | [`no-unsafe-deserialize`](./docs/rules/no-unsafe-deserialize.md) | โ None | โ None |
|
|
567
|
+
| **Async Without Await** | [`no-async-without-await`](./docs/rules/no-async-without-await.md) | โ None | `require-await` |
|
|
568
|
+
| **Sequential Await in Loop** | [`no-await-in-loop`](./docs/rules/no-await-in-loop.md) | `no-await-in-loop` *(no fix)* | โ None |
|
|
569
|
+
| **Dead Code Branches (`if (true)`)** | [`no-dead-branch`](./docs/rules/no-dead-branch.md) | โ None | โ None |
|
|
570
|
+
|
|
571
|
+
> [!TIP]
|
|
572
|
+
> **Minimal Type-Information Dependency:** 17 of 18 AI Guard rules operate in pure syntax/scope-analysis mode without `projectService` or `tsconfig.json`. The `no-floating-promise` rule optionally uses TypeScript parser services for higher recall on cross-module Promise calls, with syntax/scope-based heuristics as a zero-config fallback.
|
|
573
|
+
|
|
574
|
+
---
|
|
575
|
+
|
|
576
|
+
### 2. Runtime Performance
|
|
577
|
+
|
|
578
|
+
Benchmark: scanning 196 TypeScript / JavaScript files (`algorithm-automata-simulator`, Windows 11, Node.js 20, median of 3 runs):
|
|
579
|
+
|
|
580
|
+
| Tool / Mode | Scan Time | Configuration Overhead |
|
|
581
|
+
| :--- | :---: | :--- |
|
|
582
|
+
| **`ai-guard run --strict`** | **~1.8s** | **Zero config** (18 AST heuristic rules, no `tsconfig.json` needed) |
|
|
583
|
+
| `eslint .` (recommended) | ~2.5s | Core syntax rules only (misses floating promises & secrets) |
|
|
584
|
+
| `eslint .` (type-aware `@typescript-eslint`) | **~8โ12s** | Requires full TS compiler graph binding (**4xโ6x slower**) |
|
|
585
|
+
|
|
586
|
+
AI Guard executes **4xโ6x faster** than type-aware linting suites because it leverages deterministic AST heuristics rather than reconstructing the full TypeScript symbol graph.
|
|
587
|
+
|
|
588
|
+
---
|
|
589
|
+
|
|
590
|
+
### 3. Empirical Bug Detection & Precision Study
|
|
591
|
+
|
|
592
|
+
Two comprehensive empirical benchmark evaluations were conducted to measure real-world precision and detection yields:
|
|
593
|
+
|
|
594
|
+
#### A. Accuracy & False Positive Audit (4 Real-World Repositories, 378 Files)
|
|
595
|
+
|
|
596
|
+
| Category | Findings | True Positives | False Positive Rate |
|
|
597
|
+
| :--- | :---: | :---: | :---: |
|
|
598
|
+
| **Security** (`no-hardcoded-secret`, `no-eval-dynamic`, etc.) | 15 | 15 | **0%** |
|
|
599
|
+
| **Reliability** (`no-empty-catch`, broad exceptions) | 53 | 53 | **0%** |
|
|
600
|
+
| **Async Stability** (`no-floating-promise`, async callbacks) | 43 | ~40 | **~7%** |
|
|
601
|
+
| **AI Patterns** (duplicate logic, dead branches) | 58 | 43 | **26%** *(reduced in v1.2.8+)* |
|
|
602
|
+
|
|
603
|
+
#### B. Dual-Mode Detection Study (48 Call Sites & Real Production Target)
|
|
604
|
+
|
|
605
|
+
Audited across a controlled multi-file test corpus (13 files, 48 call sites) and a real-world Express + MongoDB production application (`Truvita New`):
|
|
606
|
+
|
|
607
|
+
- **High Precision:** **100% precision** on type-aware exclusive findings (26 of 26 verified True Positives; 0 false alarms on synchronous controls).
|
|
608
|
+
- **Critical Detection:** Detected **1 critical database startup race condition** in production (`server/index.ts connectDB()`) where an unawaited connection call allowed requests to hit the database before initialization.
|
|
609
|
+
- **Single-File Actionability:** **100%** of findings were resolvable locally at the call site (`await`, `.catch()`, or `void`).
|
|
610
|
+
|
|
611
|
+
For the complete methodology, raw findings, and benchmark harness, see [**`docs/benchmarks.md`**](./docs/benchmarks.md).
|
|
612
|
+
|
|
613
|
+
---
|
|
614
|
+
|
|
615
|
+
## Performance & Philosophy
|
|
616
|
+
|
|
617
|
+
- **Zero LLM Overhead:** AI Guard does not call external APIs, does not incur token costs, and does not add LLM latency. A scan of 100+ files executes in milliseconds.
|
|
618
|
+
- **100% Deterministic:** Every finding is derived strictly from Abstract Syntax Tree analysis. No probabilistic drift, no non-deterministic hallucinated findings.
|
|
619
|
+
- **Low False Positives:** Built with precision-first design. Context-sensitive rules are configured at `warn` or `off` in the recommended preset so developers are never blocked by noise.
|
|
620
|
+
- **Self-Scanning:** AI Guard enforces its own rules on its own codebase in CI using the `strict` preset.
|
|
621
|
+
|
|
622
|
+
---
|
|
623
|
+
|
|
624
|
+
## MCP Server (Model Context Protocol)
|
|
625
|
+
|
|
626
|
+
AI Guard includes a local MCP server that exposes its deterministic analysis engine to MCP-capable AI clients (Claude Code, Claude Desktop, and other MCP-compatible integrations).
|
|
627
|
+
|
|
628
|
+
```bash
|
|
629
|
+
npx ai-guard-mcp
|
|
630
|
+
```
|
|
631
|
+
|
|
632
|
+
**Available tools:**
|
|
633
|
+
|
|
634
|
+
| Tool | Description |
|
|
635
|
+
| :--- | :--- |
|
|
636
|
+
| `ai_guard_scan_file` | Scan a single JS/TS file with structured findings |
|
|
637
|
+
| `ai_guard_scan_diff` | Scan changed files in git diff (including newly created untracked JS/TS files) |
|
|
638
|
+
| `ai_guard_rules` | List available rules and presets |
|
|
639
|
+
|
|
640
|
+
**Claude Code configuration** (`.claude/mcp.json`):
|
|
641
|
+
|
|
642
|
+
```json
|
|
643
|
+
{
|
|
644
|
+
"mcpServers": {
|
|
645
|
+
"ai-guard": {
|
|
646
|
+
"command": "npx",
|
|
647
|
+
"args": ["ai-guard-mcp"]
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
```
|
|
652
|
+
|
|
653
|
+
For detailed documentation, tool schemas, and security model, see [**`docs/mcp-server.md`**](./docs/mcp-server.md).
|
|
654
|
+
|
|
655
|
+
---
|
|
656
|
+
|
|
657
|
+
## Learn More & Ecosystem
|
|
658
|
+
|
|
659
|
+
Visit [getaiguard.dev](https://getaiguard.dev) to explore interactive documentation, rule catalogs, benchmarks, and deep-dive engineering articles.
|
|
660
|
+
|
|
661
|
+
### Official Links
|
|
662
|
+
|
|
663
|
+
- **Website:** [https://getaiguard.dev](https://getaiguard.dev)
|
|
664
|
+
- **GitHub Organization:** [https://github.com/ai-guard-dev](https://github.com/ai-guard-dev)
|
|
665
|
+
- **Repository:** [https://github.com/ai-guard-dev/eslint-plugin-ai-guard](https://github.com/ai-guard-dev/eslint-plugin-ai-guard)
|
|
666
|
+
- **npm Registry:** [https://www.npmjs.com/package/eslint-plugin-ai-guard](https://www.npmjs.com/package/eslint-plugin-ai-guard)
|
|
667
|
+
- **GitHub Action:** [ai-guard-dev/eslint-plugin-ai-guard@v1](https://github.com/ai-guard-dev/eslint-plugin-ai-guard)
|
|
668
|
+
|
|
669
|
+
---
|
|
670
|
+
|
|
671
|
+
## Contributing
|
|
672
|
+
|
|
673
|
+
We welcome contributions, new rule ideas, bug reports, and false-positive reports!
|
|
674
|
+
|
|
675
|
+
1. Check out our [Contributing Guide](CONTRIBUTING.md) for local setup and testing standards.
|
|
676
|
+
2. Review our [Security Policy](SECURITY.md) to report vulnerabilities responsibly.
|
|
677
|
+
3. Check open issues or submit new ones on our [Issue Tracker](https://github.com/ai-guard-dev/eslint-plugin-ai-guard/issues).
|
|
678
|
+
|
|
679
|
+
---
|
|
680
|
+
|
|
681
|
+
## License
|
|
682
|
+
|
|
683
|
+
[MIT](LICENSE) ยฉ AI Guard Authors. Free and open source forever.
|