@claude-tools-i-use/ai-code-audit 0.1.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 +148 -0
- package/dist/auditor.d.ts +7 -0
- package/dist/auditor.d.ts.map +1 -0
- package/dist/auditor.js +190 -0
- package/dist/auditor.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +233 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/dist/rules/ai-specific.d.ts +7 -0
- package/dist/rules/ai-specific.d.ts.map +1 -0
- package/dist/rules/ai-specific.js +124 -0
- package/dist/rules/ai-specific.js.map +1 -0
- package/dist/rules/index.d.ts +7 -0
- package/dist/rules/index.d.ts.map +1 -0
- package/dist/rules/index.js +10 -0
- package/dist/rules/index.js.map +1 -0
- package/dist/rules/quality.d.ts +8 -0
- package/dist/rules/quality.d.ts.map +1 -0
- package/dist/rules/quality.js +123 -0
- package/dist/rules/quality.js.map +1 -0
- package/dist/rules/security.d.ts +9 -0
- package/dist/rules/security.d.ts.map +1 -0
- package/dist/rules/security.js +168 -0
- package/dist/rules/security.js.map +1 -0
- package/dist/types.d.ts +30 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +45 -0
package/README.md
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
# ai-code-audit
|
|
2
|
+
|
|
3
|
+
Security and quality linter specifically designed for AI-generated code.
|
|
4
|
+
|
|
5
|
+
## The Problem
|
|
6
|
+
|
|
7
|
+
AI coding assistants can introduce security vulnerabilities and quality issues:
|
|
8
|
+
|
|
9
|
+
- SQL injection through string concatenation
|
|
10
|
+
- Command injection via unsanitized inputs
|
|
11
|
+
- Hardcoded secrets and credentials
|
|
12
|
+
- Missing error handling
|
|
13
|
+
- Unsafe deserialization
|
|
14
|
+
- Over-complex "clever" solutions
|
|
15
|
+
|
|
16
|
+
Traditional linters catch some of these, but AI code has unique patterns that need specific attention.
|
|
17
|
+
|
|
18
|
+
## Installation
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm install -g ai-code-audit
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Usage
|
|
25
|
+
|
|
26
|
+
### Audit Files
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
# Audit a single file
|
|
30
|
+
aca src/api.ts
|
|
31
|
+
|
|
32
|
+
# Audit multiple files
|
|
33
|
+
aca src/**/*.ts
|
|
34
|
+
|
|
35
|
+
# Audit a git diff
|
|
36
|
+
git diff HEAD~1 | aca --stdin
|
|
37
|
+
|
|
38
|
+
# Audit staged changes
|
|
39
|
+
git diff --cached | aca --stdin
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### Options
|
|
43
|
+
|
|
44
|
+
```
|
|
45
|
+
Options:
|
|
46
|
+
-s, --stdin Read diff from stdin
|
|
47
|
+
-f, --format <type> Output format: text, json, sarif (default: text)
|
|
48
|
+
-c, --config <file> Config file path
|
|
49
|
+
--severity <level> Minimum severity: info, warning, error (default: warning)
|
|
50
|
+
-q, --quiet Only output errors
|
|
51
|
+
-h, --help Show help
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Git Hook Integration
|
|
55
|
+
|
|
56
|
+
Add to `.git/hooks/pre-commit`:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
#!/bin/bash
|
|
60
|
+
git diff --cached | aca --stdin --severity error
|
|
61
|
+
if [ $? -ne 0 ]; then
|
|
62
|
+
echo "AI code audit found issues. Please review before committing."
|
|
63
|
+
exit 1
|
|
64
|
+
fi
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### CI Integration
|
|
68
|
+
|
|
69
|
+
```yaml
|
|
70
|
+
# GitHub Actions
|
|
71
|
+
- name: AI Code Audit
|
|
72
|
+
run: |
|
|
73
|
+
npm install -g ai-code-audit
|
|
74
|
+
git diff ${{ github.event.before }} ${{ github.sha }} | aca --stdin --format sarif > results.sarif
|
|
75
|
+
|
|
76
|
+
- name: Upload SARIF
|
|
77
|
+
uses: github/codeql-action/upload-sarif@v2
|
|
78
|
+
with:
|
|
79
|
+
sarif_file: results.sarif
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Rules
|
|
83
|
+
|
|
84
|
+
### Security Rules
|
|
85
|
+
|
|
86
|
+
| Rule | Severity | Description |
|
|
87
|
+
| ------------------- | -------- | --------------------------------------------- |
|
|
88
|
+
| `sql-injection` | error | Detects SQL queries with string interpolation |
|
|
89
|
+
| `command-injection` | error | Detects shell commands with unsanitized input |
|
|
90
|
+
| `hardcoded-secret` | error | Detects hardcoded API keys, passwords, tokens |
|
|
91
|
+
| `unsafe-eval` | error | Detects use of eval() or Function() |
|
|
92
|
+
| `unsafe-regex` | warning | Detects potentially catastrophic regex |
|
|
93
|
+
| `path-traversal` | error | Detects unsanitized file path operations |
|
|
94
|
+
| `xss-risk` | warning | Detects potential XSS in HTML generation |
|
|
95
|
+
|
|
96
|
+
### Quality Rules
|
|
97
|
+
|
|
98
|
+
| Rule | Severity | Description |
|
|
99
|
+
| ------------------------ | -------- | ---------------------------------------------- |
|
|
100
|
+
| `missing-error-handling` | warning | Detects async operations without try/catch |
|
|
101
|
+
| `empty-catch` | warning | Detects empty catch blocks that swallow errors |
|
|
102
|
+
| `console-log` | info | Detects console.log left in code |
|
|
103
|
+
| `todo-fixme` | info | Detects TODO/FIXME comments |
|
|
104
|
+
| `magic-number` | info | Detects unexplained numeric literals |
|
|
105
|
+
| `deep-nesting` | warning | Detects deeply nested code (>4 levels) |
|
|
106
|
+
|
|
107
|
+
### AI-Specific Rules
|
|
108
|
+
|
|
109
|
+
| Rule | Severity | Description |
|
|
110
|
+
| -------------------- | -------- | ----------------------------------------------------- |
|
|
111
|
+
| `ai-placeholder` | error | Detects placeholder text like "// Add implementation" |
|
|
112
|
+
| `incomplete-impl` | warning | Detects `throw new Error('Not implemented')` |
|
|
113
|
+
| `excessive-comments` | info | Detects over-commented obvious code |
|
|
114
|
+
| `type-any-abuse` | warning | Detects excessive use of `any` type |
|
|
115
|
+
|
|
116
|
+
## Configuration
|
|
117
|
+
|
|
118
|
+
Create `.ai-code-audit.json`:
|
|
119
|
+
|
|
120
|
+
```json
|
|
121
|
+
{
|
|
122
|
+
"rules": {
|
|
123
|
+
"sql-injection": "error",
|
|
124
|
+
"console-log": "off",
|
|
125
|
+
"magic-number": "warning"
|
|
126
|
+
},
|
|
127
|
+
"ignore": ["**/*.test.ts", "**/fixtures/**"],
|
|
128
|
+
"languages": ["typescript", "javascript", "python"]
|
|
129
|
+
}
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
## Output Example
|
|
133
|
+
|
|
134
|
+
```
|
|
135
|
+
src/api/users.ts
|
|
136
|
+
12:5 error SQL injection risk: query uses string interpolation sql-injection
|
|
137
|
+
24:3 warning Missing error handling for async operation missing-error-handling
|
|
138
|
+
45:1 error Hardcoded secret detected: API_KEY = "sk-..." hardcoded-secret
|
|
139
|
+
|
|
140
|
+
src/utils/shell.ts
|
|
141
|
+
8:12 error Command injection: exec() with unsanitized input command-injection
|
|
142
|
+
|
|
143
|
+
4 problems (3 errors, 1 warning)
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## License
|
|
147
|
+
|
|
148
|
+
MIT
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Finding, AuditResult, Config } from "./types.js";
|
|
2
|
+
export declare function auditFile(filename: string, config?: Config): Finding[];
|
|
3
|
+
export declare function auditContent(content: string, filename: string, config?: Config): Finding[];
|
|
4
|
+
export declare function auditDiff(diff: string, config?: Config): Finding[];
|
|
5
|
+
export declare function summarize(findings: Finding[]): AuditResult;
|
|
6
|
+
export declare function loadConfig(configPath?: string): Config;
|
|
7
|
+
//# sourceMappingURL=auditor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auditor.d.ts","sourceRoot":"","sources":["../src/auditor.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAsC/D,wBAAgB,SAAS,CACvB,QAAQ,EAAE,MAAM,EAChB,MAAM,GAAE,MAAuB,GAC9B,OAAO,EAAE,CAmCX;AAED,wBAAgB,YAAY,CAC1B,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EAChB,MAAM,GAAE,MAAuB,GAC9B,OAAO,EAAE,CAwBX;AAED,wBAAgB,SAAS,CACvB,IAAI,EAAE,MAAM,EACZ,MAAM,GAAE,MAAuB,GAC9B,OAAO,EAAE,CAkEX;AAED,wBAAgB,SAAS,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,WAAW,CA8B1D;AAED,wBAAgB,UAAU,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,CAsBtD"}
|
package/dist/auditor.js
ADDED
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import { readFileSync, existsSync } from "node:fs";
|
|
2
|
+
import { extname } from "node:path";
|
|
3
|
+
import { allRules } from "./rules/index.js";
|
|
4
|
+
const EXTENSION_MAP = {
|
|
5
|
+
".ts": "typescript",
|
|
6
|
+
".tsx": "typescript",
|
|
7
|
+
".js": "javascript",
|
|
8
|
+
".jsx": "javascript",
|
|
9
|
+
".mjs": "javascript",
|
|
10
|
+
".cjs": "javascript",
|
|
11
|
+
".py": "python",
|
|
12
|
+
".rb": "ruby",
|
|
13
|
+
".go": "go",
|
|
14
|
+
};
|
|
15
|
+
const DEFAULT_CONFIG = {
|
|
16
|
+
rules: {},
|
|
17
|
+
ignore: [],
|
|
18
|
+
languages: ["typescript", "javascript", "python"],
|
|
19
|
+
};
|
|
20
|
+
function getLanguage(filename) {
|
|
21
|
+
const ext = extname(filename).toLowerCase();
|
|
22
|
+
return EXTENSION_MAP[ext] || null;
|
|
23
|
+
}
|
|
24
|
+
function shouldIgnore(finding, config) {
|
|
25
|
+
const ruleSeverity = config.rules[finding.rule];
|
|
26
|
+
return ruleSeverity === "off";
|
|
27
|
+
}
|
|
28
|
+
function adjustSeverity(finding, config) {
|
|
29
|
+
const ruleSeverity = config.rules[finding.rule];
|
|
30
|
+
if (ruleSeverity && ruleSeverity !== "off") {
|
|
31
|
+
return { ...finding, severity: ruleSeverity };
|
|
32
|
+
}
|
|
33
|
+
return finding;
|
|
34
|
+
}
|
|
35
|
+
export function auditFile(filename, config = DEFAULT_CONFIG) {
|
|
36
|
+
const language = getLanguage(filename);
|
|
37
|
+
if (!language) {
|
|
38
|
+
return [];
|
|
39
|
+
}
|
|
40
|
+
if (!config.languages.includes(language)) {
|
|
41
|
+
return [];
|
|
42
|
+
}
|
|
43
|
+
let content;
|
|
44
|
+
try {
|
|
45
|
+
content = readFileSync(filename, "utf-8");
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
return [];
|
|
49
|
+
}
|
|
50
|
+
const findings = [];
|
|
51
|
+
for (const rule of allRules) {
|
|
52
|
+
if (!rule.languages.includes(language)) {
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
const ruleFindings = rule.check(content, filename);
|
|
56
|
+
for (const finding of ruleFindings) {
|
|
57
|
+
if (!shouldIgnore(finding, config)) {
|
|
58
|
+
findings.push(adjustSeverity(finding, config));
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return findings;
|
|
63
|
+
}
|
|
64
|
+
export function auditContent(content, filename, config = DEFAULT_CONFIG) {
|
|
65
|
+
const language = getLanguage(filename);
|
|
66
|
+
if (!language) {
|
|
67
|
+
return [];
|
|
68
|
+
}
|
|
69
|
+
const findings = [];
|
|
70
|
+
for (const rule of allRules) {
|
|
71
|
+
if (!rule.languages.includes(language)) {
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
const ruleFindings = rule.check(content, filename);
|
|
75
|
+
for (const finding of ruleFindings) {
|
|
76
|
+
if (!shouldIgnore(finding, config)) {
|
|
77
|
+
findings.push(adjustSeverity(finding, config));
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return findings;
|
|
82
|
+
}
|
|
83
|
+
export function auditDiff(diff, config = DEFAULT_CONFIG) {
|
|
84
|
+
const findings = [];
|
|
85
|
+
let currentFile = "";
|
|
86
|
+
let lineOffset = 0;
|
|
87
|
+
const addedLines = new Map();
|
|
88
|
+
// Parse the diff
|
|
89
|
+
const lines = diff.split("\n");
|
|
90
|
+
for (const line of lines) {
|
|
91
|
+
// New file
|
|
92
|
+
if (line.startsWith("+++ b/")) {
|
|
93
|
+
currentFile = line.slice(6);
|
|
94
|
+
addedLines.set(currentFile, []);
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
// Hunk header
|
|
98
|
+
if (line.startsWith("@@")) {
|
|
99
|
+
const match = line.match(/@@ -\d+(?:,\d+)? \+(\d+)/);
|
|
100
|
+
if (match) {
|
|
101
|
+
lineOffset = parseInt(match[1], 10) - 1;
|
|
102
|
+
}
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
// Added line
|
|
106
|
+
if (line.startsWith("+") && !line.startsWith("+++")) {
|
|
107
|
+
lineOffset++;
|
|
108
|
+
const fileLines = addedLines.get(currentFile);
|
|
109
|
+
if (fileLines) {
|
|
110
|
+
fileLines.push({
|
|
111
|
+
line: lineOffset,
|
|
112
|
+
content: line.slice(1),
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
// Context or removed line
|
|
118
|
+
if (!line.startsWith("-")) {
|
|
119
|
+
lineOffset++;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
// Audit added lines for each file
|
|
123
|
+
for (const [filename, lines] of addedLines) {
|
|
124
|
+
if (lines.length === 0)
|
|
125
|
+
continue;
|
|
126
|
+
const content = lines.map((l) => l.content).join("\n");
|
|
127
|
+
const contentFindings = auditContent(content, filename, config);
|
|
128
|
+
// Adjust line numbers back to original file
|
|
129
|
+
for (const finding of contentFindings) {
|
|
130
|
+
const originalLine = lines[finding.line - 1];
|
|
131
|
+
if (originalLine) {
|
|
132
|
+
findings.push({
|
|
133
|
+
...finding,
|
|
134
|
+
line: originalLine.line,
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
return findings;
|
|
140
|
+
}
|
|
141
|
+
export function summarize(findings) {
|
|
142
|
+
let errorCount = 0;
|
|
143
|
+
let warningCount = 0;
|
|
144
|
+
let infoCount = 0;
|
|
145
|
+
const files = new Set();
|
|
146
|
+
for (const finding of findings) {
|
|
147
|
+
files.add(finding.file);
|
|
148
|
+
switch (finding.severity) {
|
|
149
|
+
case "error":
|
|
150
|
+
errorCount++;
|
|
151
|
+
break;
|
|
152
|
+
case "warning":
|
|
153
|
+
warningCount++;
|
|
154
|
+
break;
|
|
155
|
+
case "info":
|
|
156
|
+
infoCount++;
|
|
157
|
+
break;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
return {
|
|
161
|
+
findings,
|
|
162
|
+
filesScanned: files.size,
|
|
163
|
+
errorCount,
|
|
164
|
+
warningCount,
|
|
165
|
+
infoCount,
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
export function loadConfig(configPath) {
|
|
169
|
+
const paths = configPath
|
|
170
|
+
? [configPath]
|
|
171
|
+
: [".ai-code-audit.json", ".ai-code-audit.config.json"];
|
|
172
|
+
for (const path of paths) {
|
|
173
|
+
if (existsSync(path)) {
|
|
174
|
+
try {
|
|
175
|
+
const content = readFileSync(path, "utf-8");
|
|
176
|
+
const userConfig = JSON.parse(content);
|
|
177
|
+
return {
|
|
178
|
+
...DEFAULT_CONFIG,
|
|
179
|
+
...userConfig,
|
|
180
|
+
rules: { ...DEFAULT_CONFIG.rules, ...userConfig.rules },
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
catch {
|
|
184
|
+
// Invalid config, use defaults
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
return DEFAULT_CONFIG;
|
|
189
|
+
}
|
|
190
|
+
//# sourceMappingURL=auditor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auditor.js","sourceRoot":"","sources":["../src/auditor.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { resolve } from "node:path";
|
|
3
|
+
import { auditFile, auditDiff, summarize, loadConfig } from "./auditor.js";
|
|
4
|
+
const VERSION = "0.1.0";
|
|
5
|
+
const COLORS = {
|
|
6
|
+
reset: "\x1b[0m",
|
|
7
|
+
bold: "\x1b[1m",
|
|
8
|
+
dim: "\x1b[2m",
|
|
9
|
+
red: "\x1b[31m",
|
|
10
|
+
yellow: "\x1b[33m",
|
|
11
|
+
blue: "\x1b[34m",
|
|
12
|
+
cyan: "\x1b[36m",
|
|
13
|
+
gray: "\x1b[90m",
|
|
14
|
+
};
|
|
15
|
+
const SEVERITY_COLORS = {
|
|
16
|
+
error: COLORS.red,
|
|
17
|
+
warning: COLORS.yellow,
|
|
18
|
+
info: COLORS.blue,
|
|
19
|
+
};
|
|
20
|
+
const HELP = `
|
|
21
|
+
${COLORS.bold}ai-code-audit${COLORS.reset} v${VERSION}
|
|
22
|
+
Security and quality linter for AI-generated code
|
|
23
|
+
|
|
24
|
+
${COLORS.bold}USAGE:${COLORS.reset}
|
|
25
|
+
aca [options] <files...>
|
|
26
|
+
git diff | aca --stdin
|
|
27
|
+
|
|
28
|
+
${COLORS.bold}OPTIONS:${COLORS.reset}
|
|
29
|
+
-s, --stdin Read diff from stdin
|
|
30
|
+
-f, --format <type> Output format: text, json, sarif (default: text)
|
|
31
|
+
-c, --config <file> Config file path
|
|
32
|
+
--severity <level> Minimum severity: info, warning, error (default: warning)
|
|
33
|
+
-q, --quiet Only output errors
|
|
34
|
+
-h, --help Show help
|
|
35
|
+
-v, --version Show version
|
|
36
|
+
|
|
37
|
+
${COLORS.bold}EXAMPLES:${COLORS.reset}
|
|
38
|
+
aca src/api.ts # Audit a single file
|
|
39
|
+
aca src/**/*.ts # Audit multiple files
|
|
40
|
+
git diff HEAD~1 | aca --stdin # Audit a diff
|
|
41
|
+
git diff --cached | aca --stdin # Audit staged changes
|
|
42
|
+
|
|
43
|
+
${COLORS.bold}GIT HOOK:${COLORS.reset}
|
|
44
|
+
Add to .git/hooks/pre-commit:
|
|
45
|
+
git diff --cached | aca --stdin --severity error
|
|
46
|
+
|
|
47
|
+
`;
|
|
48
|
+
function parseArgs(args) {
|
|
49
|
+
const options = {
|
|
50
|
+
stdin: false,
|
|
51
|
+
format: "text",
|
|
52
|
+
severity: "warning",
|
|
53
|
+
quiet: false,
|
|
54
|
+
files: [],
|
|
55
|
+
};
|
|
56
|
+
for (let i = 0; i < args.length; i++) {
|
|
57
|
+
const arg = args[i];
|
|
58
|
+
switch (arg) {
|
|
59
|
+
case "-h":
|
|
60
|
+
case "--help":
|
|
61
|
+
console.log(HELP);
|
|
62
|
+
process.exit(0);
|
|
63
|
+
break;
|
|
64
|
+
case "-v":
|
|
65
|
+
case "--version":
|
|
66
|
+
console.log(`ai-code-audit v${VERSION}`);
|
|
67
|
+
process.exit(0);
|
|
68
|
+
break;
|
|
69
|
+
case "-s":
|
|
70
|
+
case "--stdin":
|
|
71
|
+
options.stdin = true;
|
|
72
|
+
break;
|
|
73
|
+
case "-f":
|
|
74
|
+
case "--format":
|
|
75
|
+
options.format = args[++i];
|
|
76
|
+
break;
|
|
77
|
+
case "-c":
|
|
78
|
+
case "--config":
|
|
79
|
+
options.configPath = args[++i];
|
|
80
|
+
break;
|
|
81
|
+
case "--severity":
|
|
82
|
+
options.severity = args[++i];
|
|
83
|
+
break;
|
|
84
|
+
case "-q":
|
|
85
|
+
case "--quiet":
|
|
86
|
+
options.quiet = true;
|
|
87
|
+
options.severity = "error";
|
|
88
|
+
break;
|
|
89
|
+
default:
|
|
90
|
+
if (!arg.startsWith("-")) {
|
|
91
|
+
options.files.push(arg);
|
|
92
|
+
}
|
|
93
|
+
break;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return options;
|
|
97
|
+
}
|
|
98
|
+
function filterBySeverity(findings, minSeverity) {
|
|
99
|
+
const severityOrder = ["info", "warning", "error"];
|
|
100
|
+
const minIndex = severityOrder.indexOf(minSeverity);
|
|
101
|
+
return findings.filter((f) => severityOrder.indexOf(f.severity) >= minIndex);
|
|
102
|
+
}
|
|
103
|
+
function formatText(result) {
|
|
104
|
+
const output = [];
|
|
105
|
+
// Group findings by file
|
|
106
|
+
const byFile = new Map();
|
|
107
|
+
for (const finding of result.findings) {
|
|
108
|
+
const existing = byFile.get(finding.file) || [];
|
|
109
|
+
existing.push(finding);
|
|
110
|
+
byFile.set(finding.file, existing);
|
|
111
|
+
}
|
|
112
|
+
for (const [file, findings] of byFile) {
|
|
113
|
+
output.push(`\n${COLORS.bold}${file}${COLORS.reset}`);
|
|
114
|
+
for (const f of findings) {
|
|
115
|
+
const color = SEVERITY_COLORS[f.severity];
|
|
116
|
+
const loc = `${f.line}:${f.column}`.padEnd(8);
|
|
117
|
+
const sev = f.severity.padEnd(8);
|
|
118
|
+
output.push(` ${COLORS.gray}${loc}${COLORS.reset} ${color}${sev}${COLORS.reset} ${f.message} ${COLORS.dim}${f.rule}${COLORS.reset}`);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
output.push("");
|
|
122
|
+
const { errorCount, warningCount, infoCount } = result;
|
|
123
|
+
const total = errorCount + warningCount + infoCount;
|
|
124
|
+
if (total === 0) {
|
|
125
|
+
output.push(`${COLORS.cyan}✓ No issues found${COLORS.reset}`);
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
const parts = [];
|
|
129
|
+
if (errorCount > 0)
|
|
130
|
+
parts.push(`${COLORS.red}${errorCount} error${errorCount !== 1 ? "s" : ""}${COLORS.reset}`);
|
|
131
|
+
if (warningCount > 0)
|
|
132
|
+
parts.push(`${COLORS.yellow}${warningCount} warning${warningCount !== 1 ? "s" : ""}${COLORS.reset}`);
|
|
133
|
+
if (infoCount > 0)
|
|
134
|
+
parts.push(`${COLORS.blue}${infoCount} info${COLORS.reset}`);
|
|
135
|
+
output.push(parts.join(", "));
|
|
136
|
+
}
|
|
137
|
+
return output.join("\n");
|
|
138
|
+
}
|
|
139
|
+
function formatJson(result) {
|
|
140
|
+
return JSON.stringify(result, null, 2);
|
|
141
|
+
}
|
|
142
|
+
function formatSarif(result) {
|
|
143
|
+
const sarif = {
|
|
144
|
+
$schema: "https://json.schemastore.org/sarif-2.1.0.json",
|
|
145
|
+
version: "2.1.0",
|
|
146
|
+
runs: [
|
|
147
|
+
{
|
|
148
|
+
tool: {
|
|
149
|
+
driver: {
|
|
150
|
+
name: "ai-code-audit",
|
|
151
|
+
version: VERSION,
|
|
152
|
+
rules: result.findings.map((f) => ({
|
|
153
|
+
id: f.rule,
|
|
154
|
+
shortDescription: { text: f.message },
|
|
155
|
+
})),
|
|
156
|
+
},
|
|
157
|
+
},
|
|
158
|
+
results: result.findings.map((f) => ({
|
|
159
|
+
ruleId: f.rule,
|
|
160
|
+
level: f.severity === "error"
|
|
161
|
+
? "error"
|
|
162
|
+
: f.severity === "warning"
|
|
163
|
+
? "warning"
|
|
164
|
+
: "note",
|
|
165
|
+
message: { text: f.message },
|
|
166
|
+
locations: [
|
|
167
|
+
{
|
|
168
|
+
physicalLocation: {
|
|
169
|
+
artifactLocation: { uri: f.file },
|
|
170
|
+
region: { startLine: f.line, startColumn: f.column },
|
|
171
|
+
},
|
|
172
|
+
},
|
|
173
|
+
],
|
|
174
|
+
})),
|
|
175
|
+
},
|
|
176
|
+
],
|
|
177
|
+
};
|
|
178
|
+
return JSON.stringify(sarif, null, 2);
|
|
179
|
+
}
|
|
180
|
+
async function main() {
|
|
181
|
+
const args = process.argv.slice(2);
|
|
182
|
+
if (args.length === 0) {
|
|
183
|
+
console.log(HELP);
|
|
184
|
+
process.exit(0);
|
|
185
|
+
}
|
|
186
|
+
const options = parseArgs(args);
|
|
187
|
+
const config = loadConfig(options.configPath);
|
|
188
|
+
let findings = [];
|
|
189
|
+
if (options.stdin) {
|
|
190
|
+
// Read diff from stdin
|
|
191
|
+
const chunks = [];
|
|
192
|
+
for await (const chunk of process.stdin) {
|
|
193
|
+
chunks.push(chunk);
|
|
194
|
+
}
|
|
195
|
+
const diff = Buffer.concat(chunks).toString("utf-8");
|
|
196
|
+
findings = auditDiff(diff, config);
|
|
197
|
+
}
|
|
198
|
+
else if (options.files.length > 0) {
|
|
199
|
+
// Audit files
|
|
200
|
+
for (const file of options.files) {
|
|
201
|
+
const filePath = resolve(file);
|
|
202
|
+
findings.push(...auditFile(filePath, config));
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
else {
|
|
206
|
+
console.error("Error: No files specified. Use --stdin for diff input.");
|
|
207
|
+
process.exit(1);
|
|
208
|
+
}
|
|
209
|
+
// Filter by severity
|
|
210
|
+
findings = filterBySeverity(findings, options.severity);
|
|
211
|
+
const result = summarize(findings);
|
|
212
|
+
// Output
|
|
213
|
+
switch (options.format) {
|
|
214
|
+
case "json":
|
|
215
|
+
console.log(formatJson(result));
|
|
216
|
+
break;
|
|
217
|
+
case "sarif":
|
|
218
|
+
console.log(formatSarif(result));
|
|
219
|
+
break;
|
|
220
|
+
default:
|
|
221
|
+
console.log(formatText(result));
|
|
222
|
+
break;
|
|
223
|
+
}
|
|
224
|
+
// Exit with error if there are errors
|
|
225
|
+
if (result.errorCount > 0) {
|
|
226
|
+
process.exit(1);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
main().catch((err) => {
|
|
230
|
+
console.error("Fatal error:", err);
|
|
231
|
+
process.exit(1);
|
|
232
|
+
});
|
|
233
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { auditFile, auditContent, auditDiff, summarize, loadConfig, } from "./auditor.js";
|
|
2
|
+
export { allRules, securityRules, qualityRules, aiSpecificRules, } from "./rules/index.js";
|
|
3
|
+
export type { Finding, Rule, AuditResult, Config, Severity } from "./types.js";
|
|
4
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,SAAS,EACT,YAAY,EACZ,SAAS,EACT,SAAS,EACT,UAAU,GACX,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,QAAQ,EACR,aAAa,EACb,YAAY,EACZ,eAAe,GAChB,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EAAE,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
// ai-code-audit - Security and quality linter for AI-generated code
|
|
2
|
+
export { auditFile, auditContent, auditDiff, summarize, loadConfig, } from "./auditor.js";
|
|
3
|
+
export { allRules, securityRules, qualityRules, aiSpecificRules, } from "./rules/index.js";
|
|
4
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,oEAAoE;AAEpE,OAAO,EACL,SAAS,EACT,YAAY,EACZ,SAAS,EACT,SAAS,EACT,UAAU,GACX,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,QAAQ,EACR,aAAa,EACb,YAAY,EACZ,eAAe,GAChB,MAAM,kBAAkB,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Rule } from "../types.js";
|
|
2
|
+
export declare const aiPlaceholder: Rule;
|
|
3
|
+
export declare const incompleteImpl: Rule;
|
|
4
|
+
export declare const typeAnyAbuse: Rule;
|
|
5
|
+
export declare const excessiveComments: Rule;
|
|
6
|
+
export declare const aiSpecificRules: Rule[];
|
|
7
|
+
//# sourceMappingURL=ai-specific.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ai-specific.d.ts","sourceRoot":"","sources":["../../src/rules/ai-specific.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAW,MAAM,aAAa,CAAC;AAqCjD,eAAO,MAAM,aAAa,EAAE,IA+B3B,CAAC;AAEF,eAAO,MAAM,cAAc,EAAE,IA4B5B,CAAC;AAEF,eAAO,MAAM,YAAY,EAAE,IA0B1B,CAAC;AAEF,eAAO,MAAM,iBAAiB,EAAE,IAsC/B,CAAC;AAEF,eAAO,MAAM,eAAe,EAAE,IAAI,EAKjC,CAAC"}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
function findMatches(content, pattern, rule, severity, message, filename) {
|
|
2
|
+
const findings = [];
|
|
3
|
+
const lines = content.split("\n");
|
|
4
|
+
for (let i = 0; i < lines.length; i++) {
|
|
5
|
+
const line = lines[i];
|
|
6
|
+
let match;
|
|
7
|
+
pattern.lastIndex = 0;
|
|
8
|
+
while ((match = pattern.exec(line)) !== null) {
|
|
9
|
+
findings.push({
|
|
10
|
+
rule,
|
|
11
|
+
severity,
|
|
12
|
+
message,
|
|
13
|
+
file: filename,
|
|
14
|
+
line: i + 1,
|
|
15
|
+
column: match.index + 1,
|
|
16
|
+
snippet: line.trim(),
|
|
17
|
+
});
|
|
18
|
+
if (!pattern.global)
|
|
19
|
+
break;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return findings;
|
|
23
|
+
}
|
|
24
|
+
export const aiPlaceholder = {
|
|
25
|
+
name: "ai-placeholder",
|
|
26
|
+
description: "Detects placeholder text left by AI",
|
|
27
|
+
severity: "error",
|
|
28
|
+
languages: ["javascript", "typescript", "python", "ruby", "go"],
|
|
29
|
+
check: (content, filename) => {
|
|
30
|
+
const patterns = [
|
|
31
|
+
/\/\/\s*(?:Add|TODO:?\s*add|Implement)\s+(?:your|the)\s+/gi,
|
|
32
|
+
/\/\/\s*(?:Replace|Update)\s+(?:this|with)\s+/gi,
|
|
33
|
+
/#\s*(?:Add|TODO:?\s*add|Implement)\s+(?:your|the)\s+/gi,
|
|
34
|
+
/\/\/\s*\.\.\.\s*(?:rest|more|additional|other)/gi,
|
|
35
|
+
/\/\*\s*(?:Add|Implement|Your)\s+.*\s+here\s*\*\//gi,
|
|
36
|
+
/['"](?:your-api-key|YOUR_API_KEY|api-key-here|replace-me|CHANGE_ME)['"]/gi,
|
|
37
|
+
/(?:example|placeholder|dummy)[@.](?:com|org|io)/gi,
|
|
38
|
+
];
|
|
39
|
+
const findings = [];
|
|
40
|
+
for (const pattern of patterns) {
|
|
41
|
+
findings.push(...findMatches(content, pattern, "ai-placeholder", "error", "AI placeholder text detected - needs implementation", filename));
|
|
42
|
+
}
|
|
43
|
+
return findings;
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
export const incompleteImpl = {
|
|
47
|
+
name: "incomplete-impl",
|
|
48
|
+
description: "Detects incomplete implementations",
|
|
49
|
+
severity: "warning",
|
|
50
|
+
languages: ["javascript", "typescript", "python"],
|
|
51
|
+
check: (content, filename) => {
|
|
52
|
+
const patterns = [
|
|
53
|
+
/throw\s+new\s+Error\s*\(\s*['"](?:Not\s+implemented|TODO|FIXME)['"]/gi,
|
|
54
|
+
/raise\s+NotImplementedError/gi,
|
|
55
|
+
/pass\s*#\s*(?:TODO|FIXME)/gi,
|
|
56
|
+
/return\s+(?:null|undefined|None)\s*;?\s*\/\/\s*(?:TODO|FIXME)/gi,
|
|
57
|
+
];
|
|
58
|
+
const findings = [];
|
|
59
|
+
for (const pattern of patterns) {
|
|
60
|
+
findings.push(...findMatches(content, pattern, "incomplete-impl", "warning", "Incomplete implementation detected", filename));
|
|
61
|
+
}
|
|
62
|
+
return findings;
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
export const typeAnyAbuse = {
|
|
66
|
+
name: "type-any-abuse",
|
|
67
|
+
description: "Detects excessive use of any type",
|
|
68
|
+
severity: "warning",
|
|
69
|
+
languages: ["typescript"],
|
|
70
|
+
check: (content, filename) => {
|
|
71
|
+
if (!filename.endsWith(".ts") && !filename.endsWith(".tsx")) {
|
|
72
|
+
return [];
|
|
73
|
+
}
|
|
74
|
+
const pattern = /:\s*any\b/g;
|
|
75
|
+
const findings = findMatches(content, pattern, "type-any-abuse", "warning", 'Unsafe "any" type usage - consider using a specific type', filename);
|
|
76
|
+
// Only report if there are many instances
|
|
77
|
+
if (findings.length > 3) {
|
|
78
|
+
return findings;
|
|
79
|
+
}
|
|
80
|
+
return [];
|
|
81
|
+
},
|
|
82
|
+
};
|
|
83
|
+
export const excessiveComments = {
|
|
84
|
+
name: "excessive-comments",
|
|
85
|
+
description: "Detects over-commented obvious code",
|
|
86
|
+
severity: "info",
|
|
87
|
+
languages: ["javascript", "typescript"],
|
|
88
|
+
check: (content, filename) => {
|
|
89
|
+
const findings = [];
|
|
90
|
+
const lines = content.split("\n");
|
|
91
|
+
let commentLines = 0;
|
|
92
|
+
let codeLines = 0;
|
|
93
|
+
for (const line of lines) {
|
|
94
|
+
const trimmed = line.trim();
|
|
95
|
+
if (trimmed.startsWith("//") ||
|
|
96
|
+
trimmed.startsWith("/*") ||
|
|
97
|
+
trimmed.startsWith("*")) {
|
|
98
|
+
commentLines++;
|
|
99
|
+
}
|
|
100
|
+
else if (trimmed.length > 0) {
|
|
101
|
+
codeLines++;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
// If comments exceed 50% of code, flag it
|
|
105
|
+
if (codeLines > 10 && commentLines > codeLines * 0.5) {
|
|
106
|
+
findings.push({
|
|
107
|
+
rule: "excessive-comments",
|
|
108
|
+
severity: "info",
|
|
109
|
+
message: `High comment ratio (${commentLines} comments / ${codeLines} code lines) - may be over-documented`,
|
|
110
|
+
file: filename,
|
|
111
|
+
line: 1,
|
|
112
|
+
column: 1,
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
return findings;
|
|
116
|
+
},
|
|
117
|
+
};
|
|
118
|
+
export const aiSpecificRules = [
|
|
119
|
+
aiPlaceholder,
|
|
120
|
+
incompleteImpl,
|
|
121
|
+
typeAnyAbuse,
|
|
122
|
+
excessiveComments,
|
|
123
|
+
];
|
|
124
|
+
//# sourceMappingURL=ai-specific.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ai-specific.js","sourceRoot":"","sources":["../../src/rules/ai-specific.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { securityRules } from "./security.js";
|
|
2
|
+
import { qualityRules } from "./quality.js";
|
|
3
|
+
import { aiSpecificRules } from "./ai-specific.js";
|
|
4
|
+
import type { Rule } from "../types.js";
|
|
5
|
+
export declare const allRules: Rule[];
|
|
6
|
+
export { securityRules, qualityRules, aiSpecificRules };
|
|
7
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/rules/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAExC,eAAO,MAAM,QAAQ,EAAE,IAAI,EAI1B,CAAC;AAEF,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,eAAe,EAAE,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { securityRules } from "./security.js";
|
|
2
|
+
import { qualityRules } from "./quality.js";
|
|
3
|
+
import { aiSpecificRules } from "./ai-specific.js";
|
|
4
|
+
export const allRules = [
|
|
5
|
+
...securityRules,
|
|
6
|
+
...qualityRules,
|
|
7
|
+
...aiSpecificRules,
|
|
8
|
+
];
|
|
9
|
+
export { securityRules, qualityRules, aiSpecificRules };
|
|
10
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/rules/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAGnD,MAAM,CAAC,MAAM,QAAQ,GAAW;IAC9B,GAAG,aAAa;IAChB,GAAG,YAAY;IACf,GAAG,eAAe;CACnB,CAAC;AAEF,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,eAAe,EAAE,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Rule } from "../types.js";
|
|
2
|
+
export declare const missingErrorHandling: Rule;
|
|
3
|
+
export declare const emptyCatch: Rule;
|
|
4
|
+
export declare const consoleLog: Rule;
|
|
5
|
+
export declare const todoFixme: Rule;
|
|
6
|
+
export declare const deepNesting: Rule;
|
|
7
|
+
export declare const qualityRules: Rule[];
|
|
8
|
+
//# sourceMappingURL=quality.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"quality.d.ts","sourceRoot":"","sources":["../../src/rules/quality.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAW,MAAM,aAAa,CAAC;AAqCjD,eAAO,MAAM,oBAAoB,EAAE,IAkClC,CAAC;AAEF,eAAO,MAAM,UAAU,EAAE,IAgBxB,CAAC;AAEF,eAAO,MAAM,UAAU,EAAE,IAgBxB,CAAC;AAEF,eAAO,MAAM,SAAS,EAAE,IAgBvB,CAAC;AAEF,eAAO,MAAM,WAAW,EAAE,IAiCzB,CAAC;AAEF,eAAO,MAAM,YAAY,EAAE,IAAI,EAM9B,CAAC"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
function findMatches(content, pattern, rule, severity, message, filename) {
|
|
2
|
+
const findings = [];
|
|
3
|
+
const lines = content.split("\n");
|
|
4
|
+
for (let i = 0; i < lines.length; i++) {
|
|
5
|
+
const line = lines[i];
|
|
6
|
+
let match;
|
|
7
|
+
pattern.lastIndex = 0;
|
|
8
|
+
while ((match = pattern.exec(line)) !== null) {
|
|
9
|
+
findings.push({
|
|
10
|
+
rule,
|
|
11
|
+
severity,
|
|
12
|
+
message,
|
|
13
|
+
file: filename,
|
|
14
|
+
line: i + 1,
|
|
15
|
+
column: match.index + 1,
|
|
16
|
+
snippet: line.trim(),
|
|
17
|
+
});
|
|
18
|
+
if (!pattern.global)
|
|
19
|
+
break;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return findings;
|
|
23
|
+
}
|
|
24
|
+
export const missingErrorHandling = {
|
|
25
|
+
name: "missing-error-handling",
|
|
26
|
+
description: "Detects async operations without try/catch",
|
|
27
|
+
severity: "warning",
|
|
28
|
+
languages: ["javascript", "typescript"],
|
|
29
|
+
check: (content, filename) => {
|
|
30
|
+
const findings = [];
|
|
31
|
+
const lines = content.split("\n");
|
|
32
|
+
// Look for await outside of try blocks
|
|
33
|
+
let inTry = 0;
|
|
34
|
+
for (let i = 0; i < lines.length; i++) {
|
|
35
|
+
const line = lines[i];
|
|
36
|
+
if (/\btry\s*\{/.test(line))
|
|
37
|
+
inTry++;
|
|
38
|
+
if (/\}\s*catch/.test(line))
|
|
39
|
+
inTry = Math.max(0, inTry - 1);
|
|
40
|
+
if (inTry === 0 && /\bawait\s+/.test(line)) {
|
|
41
|
+
// Check if it's in an async function without surrounding try
|
|
42
|
+
findings.push({
|
|
43
|
+
rule: "missing-error-handling",
|
|
44
|
+
severity: "warning",
|
|
45
|
+
message: "Async operation without error handling",
|
|
46
|
+
file: filename,
|
|
47
|
+
line: i + 1,
|
|
48
|
+
column: line.indexOf("await") + 1,
|
|
49
|
+
snippet: line.trim(),
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return findings;
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
export const emptyCatch = {
|
|
57
|
+
name: "empty-catch",
|
|
58
|
+
description: "Detects empty catch blocks that swallow errors",
|
|
59
|
+
severity: "warning",
|
|
60
|
+
languages: ["javascript", "typescript"],
|
|
61
|
+
check: (content, filename) => {
|
|
62
|
+
const pattern = /catch\s*\([^)]*\)\s*\{\s*\}/g;
|
|
63
|
+
return findMatches(content, pattern, "empty-catch", "warning", "Empty catch block swallows errors", filename);
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
export const consoleLog = {
|
|
67
|
+
name: "console-log",
|
|
68
|
+
description: "Detects console.log left in code",
|
|
69
|
+
severity: "info",
|
|
70
|
+
languages: ["javascript", "typescript"],
|
|
71
|
+
check: (content, filename) => {
|
|
72
|
+
const pattern = /console\.log\s*\(/g;
|
|
73
|
+
return findMatches(content, pattern, "console-log", "info", "console.log statement found", filename);
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
export const todoFixme = {
|
|
77
|
+
name: "todo-fixme",
|
|
78
|
+
description: "Detects TODO/FIXME comments",
|
|
79
|
+
severity: "info",
|
|
80
|
+
languages: ["javascript", "typescript", "python", "ruby", "go"],
|
|
81
|
+
check: (content, filename) => {
|
|
82
|
+
const pattern = /\/\/\s*(?:TODO|FIXME|HACK|XXX|BUG)[\s:]/gi;
|
|
83
|
+
return findMatches(content, pattern, "todo-fixme", "info", "TODO/FIXME comment found", filename);
|
|
84
|
+
},
|
|
85
|
+
};
|
|
86
|
+
export const deepNesting = {
|
|
87
|
+
name: "deep-nesting",
|
|
88
|
+
description: "Detects deeply nested code (>4 levels)",
|
|
89
|
+
severity: "warning",
|
|
90
|
+
languages: ["javascript", "typescript"],
|
|
91
|
+
check: (content, filename) => {
|
|
92
|
+
const findings = [];
|
|
93
|
+
const lines = content.split("\n");
|
|
94
|
+
let depth = 0;
|
|
95
|
+
const MAX_DEPTH = 4;
|
|
96
|
+
for (let i = 0; i < lines.length; i++) {
|
|
97
|
+
const line = lines[i];
|
|
98
|
+
const opens = (line.match(/\{/g) || []).length;
|
|
99
|
+
const closes = (line.match(/\}/g) || []).length;
|
|
100
|
+
depth += opens - closes;
|
|
101
|
+
if (depth > MAX_DEPTH && opens > 0) {
|
|
102
|
+
findings.push({
|
|
103
|
+
rule: "deep-nesting",
|
|
104
|
+
severity: "warning",
|
|
105
|
+
message: `Code nested ${depth} levels deep (max: ${MAX_DEPTH})`,
|
|
106
|
+
file: filename,
|
|
107
|
+
line: i + 1,
|
|
108
|
+
column: 1,
|
|
109
|
+
snippet: line.trim(),
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return findings;
|
|
114
|
+
},
|
|
115
|
+
};
|
|
116
|
+
export const qualityRules = [
|
|
117
|
+
missingErrorHandling,
|
|
118
|
+
emptyCatch,
|
|
119
|
+
consoleLog,
|
|
120
|
+
todoFixme,
|
|
121
|
+
deepNesting,
|
|
122
|
+
];
|
|
123
|
+
//# sourceMappingURL=quality.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"quality.js","sourceRoot":"","sources":["../../src/rules/quality.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Rule } from "../types.js";
|
|
2
|
+
export declare const sqlInjection: Rule;
|
|
3
|
+
export declare const commandInjection: Rule;
|
|
4
|
+
export declare const hardcodedSecret: Rule;
|
|
5
|
+
export declare const unsafeEval: Rule;
|
|
6
|
+
export declare const pathTraversal: Rule;
|
|
7
|
+
export declare const xssRisk: Rule;
|
|
8
|
+
export declare const securityRules: Rule[];
|
|
9
|
+
//# sourceMappingURL=security.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"security.d.ts","sourceRoot":"","sources":["../../src/rules/security.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAW,MAAM,aAAa,CAAC;AAuCjD,eAAO,MAAM,YAAY,EAAE,IA8B1B,CAAC;AAEF,eAAO,MAAM,gBAAgB,EAAE,IAgC9B,CAAC;AAEF,eAAO,MAAM,eAAe,EAAE,IAsC7B,CAAC;AAEF,eAAO,MAAM,UAAU,EAAE,IA4BxB,CAAC;AAEF,eAAO,MAAM,aAAa,EAAE,IA8B3B,CAAC;AAEF,eAAO,MAAM,OAAO,EAAE,IA8BrB,CAAC;AAEF,eAAO,MAAM,aAAa,EAAE,IAAI,EAO/B,CAAC"}
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
function findMatches(content, pattern, rule, severity, message, filename) {
|
|
2
|
+
const findings = [];
|
|
3
|
+
const lines = content.split("\n");
|
|
4
|
+
for (let i = 0; i < lines.length; i++) {
|
|
5
|
+
const line = lines[i];
|
|
6
|
+
let match;
|
|
7
|
+
// Reset regex for global patterns
|
|
8
|
+
pattern.lastIndex = 0;
|
|
9
|
+
while ((match = pattern.exec(line)) !== null) {
|
|
10
|
+
findings.push({
|
|
11
|
+
rule,
|
|
12
|
+
severity,
|
|
13
|
+
message,
|
|
14
|
+
file: filename,
|
|
15
|
+
line: i + 1,
|
|
16
|
+
column: match.index + 1,
|
|
17
|
+
snippet: line.trim(),
|
|
18
|
+
});
|
|
19
|
+
// Prevent infinite loop for non-global regex
|
|
20
|
+
if (!pattern.global)
|
|
21
|
+
break;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return findings;
|
|
25
|
+
}
|
|
26
|
+
export const sqlInjection = {
|
|
27
|
+
name: "sql-injection",
|
|
28
|
+
description: "Detects SQL queries with string interpolation",
|
|
29
|
+
severity: "error",
|
|
30
|
+
languages: ["javascript", "typescript", "python"],
|
|
31
|
+
check: (content, filename) => {
|
|
32
|
+
const patterns = [
|
|
33
|
+
// Template literals in SQL
|
|
34
|
+
/(?:query|execute|sql)\s*\(\s*`[^`]*\$\{/gi,
|
|
35
|
+
// String concatenation in SQL
|
|
36
|
+
/(?:query|execute|sql)\s*\(\s*['"][^'"]*['"]\s*\+/gi,
|
|
37
|
+
// Python f-strings in SQL
|
|
38
|
+
/(?:execute|cursor\.execute)\s*\(\s*f['"][^'"]*\{/gi,
|
|
39
|
+
];
|
|
40
|
+
const findings = [];
|
|
41
|
+
for (const pattern of patterns) {
|
|
42
|
+
findings.push(...findMatches(content, pattern, "sql-injection", "error", "SQL injection risk: query uses string interpolation", filename));
|
|
43
|
+
}
|
|
44
|
+
return findings;
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
export const commandInjection = {
|
|
48
|
+
name: "command-injection",
|
|
49
|
+
description: "Detects shell commands with unsanitized input",
|
|
50
|
+
severity: "error",
|
|
51
|
+
languages: ["javascript", "typescript", "python"],
|
|
52
|
+
check: (content, filename) => {
|
|
53
|
+
const patterns = [
|
|
54
|
+
// exec with template literal
|
|
55
|
+
/(?:exec|execSync|spawn|spawnSync)\s*\(\s*`[^`]*\$\{/gi,
|
|
56
|
+
// exec with concatenation
|
|
57
|
+
/(?:exec|execSync|spawn|spawnSync)\s*\(\s*['"][^'"]*['"]\s*\+/gi,
|
|
58
|
+
// Python subprocess with f-string
|
|
59
|
+
/subprocess\.(?:run|call|Popen)\s*\(\s*f['"][^'"]*\{/gi,
|
|
60
|
+
// shell=True in Python
|
|
61
|
+
/subprocess\.(?:run|call|Popen)\s*\([^)]*shell\s*=\s*True/gi,
|
|
62
|
+
];
|
|
63
|
+
const findings = [];
|
|
64
|
+
for (const pattern of patterns) {
|
|
65
|
+
findings.push(...findMatches(content, pattern, "command-injection", "error", "Command injection risk: shell command with unsanitized input", filename));
|
|
66
|
+
}
|
|
67
|
+
return findings;
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
export const hardcodedSecret = {
|
|
71
|
+
name: "hardcoded-secret",
|
|
72
|
+
description: "Detects hardcoded API keys, passwords, tokens",
|
|
73
|
+
severity: "error",
|
|
74
|
+
languages: ["javascript", "typescript", "python", "ruby", "go"],
|
|
75
|
+
check: (content, filename) => {
|
|
76
|
+
const patterns = [
|
|
77
|
+
// API keys
|
|
78
|
+
/(?:api[_-]?key|apikey)\s*[:=]\s*['"][a-zA-Z0-9_\-]{20,}['"]/gi,
|
|
79
|
+
// AWS keys
|
|
80
|
+
/(?:AKIA|ABIA|ACCA|ASIA)[A-Z0-9]{16}/g,
|
|
81
|
+
// Generic secrets
|
|
82
|
+
/(?:password|passwd|pwd|secret|token)\s*[:=]\s*['"][^'"]{8,}['"]/gi,
|
|
83
|
+
// Bearer tokens
|
|
84
|
+
/['"]Bearer\s+[a-zA-Z0-9_\-\.]+['"]/g,
|
|
85
|
+
// Private keys
|
|
86
|
+
/-----BEGIN\s+(?:RSA\s+)?PRIVATE\s+KEY-----/g,
|
|
87
|
+
// GitHub tokens
|
|
88
|
+
/gh[pousr]_[A-Za-z0-9_]{36,}/g,
|
|
89
|
+
// Slack tokens
|
|
90
|
+
/xox[baprs]-[A-Za-z0-9-]+/g,
|
|
91
|
+
];
|
|
92
|
+
const findings = [];
|
|
93
|
+
for (const pattern of patterns) {
|
|
94
|
+
findings.push(...findMatches(content, pattern, "hardcoded-secret", "error", "Hardcoded secret detected", filename));
|
|
95
|
+
}
|
|
96
|
+
return findings;
|
|
97
|
+
},
|
|
98
|
+
};
|
|
99
|
+
export const unsafeEval = {
|
|
100
|
+
name: "unsafe-eval",
|
|
101
|
+
description: "Detects use of eval() or Function()",
|
|
102
|
+
severity: "error",
|
|
103
|
+
languages: ["javascript", "typescript"],
|
|
104
|
+
check: (content, filename) => {
|
|
105
|
+
const patterns = [
|
|
106
|
+
/\beval\s*\(/g,
|
|
107
|
+
/new\s+Function\s*\(/g,
|
|
108
|
+
/setTimeout\s*\(\s*['"`]/g,
|
|
109
|
+
/setInterval\s*\(\s*['"`]/g,
|
|
110
|
+
];
|
|
111
|
+
const findings = [];
|
|
112
|
+
for (const pattern of patterns) {
|
|
113
|
+
findings.push(...findMatches(content, pattern, "unsafe-eval", "error", "Unsafe eval() or Function() usage detected", filename));
|
|
114
|
+
}
|
|
115
|
+
return findings;
|
|
116
|
+
},
|
|
117
|
+
};
|
|
118
|
+
export const pathTraversal = {
|
|
119
|
+
name: "path-traversal",
|
|
120
|
+
description: "Detects unsanitized file path operations",
|
|
121
|
+
severity: "error",
|
|
122
|
+
languages: ["javascript", "typescript", "python"],
|
|
123
|
+
check: (content, filename) => {
|
|
124
|
+
const patterns = [
|
|
125
|
+
// Direct path concatenation
|
|
126
|
+
/(?:readFile|writeFile|unlink|rmdir|mkdir)(?:Sync)?\s*\(\s*(?:req\.|request\.|params\.|query\.)/gi,
|
|
127
|
+
// Python path with user input
|
|
128
|
+
/open\s*\(\s*(?:request\.|args\.|kwargs\.)/gi,
|
|
129
|
+
// Path join with user input
|
|
130
|
+
/path\.join\s*\([^)]*(?:req\.|request\.|params\.|query\.)/gi,
|
|
131
|
+
];
|
|
132
|
+
const findings = [];
|
|
133
|
+
for (const pattern of patterns) {
|
|
134
|
+
findings.push(...findMatches(content, pattern, "path-traversal", "error", "Path traversal risk: file operation with user input", filename));
|
|
135
|
+
}
|
|
136
|
+
return findings;
|
|
137
|
+
},
|
|
138
|
+
};
|
|
139
|
+
export const xssRisk = {
|
|
140
|
+
name: "xss-risk",
|
|
141
|
+
description: "Detects potential XSS in HTML generation",
|
|
142
|
+
severity: "warning",
|
|
143
|
+
languages: ["javascript", "typescript"],
|
|
144
|
+
check: (content, filename) => {
|
|
145
|
+
const patterns = [
|
|
146
|
+
// innerHTML with variable
|
|
147
|
+
/\.innerHTML\s*=\s*[^'"]/g,
|
|
148
|
+
// document.write
|
|
149
|
+
/document\.write\s*\(/g,
|
|
150
|
+
// dangerouslySetInnerHTML
|
|
151
|
+
/dangerouslySetInnerHTML\s*=\s*\{\s*\{\s*__html\s*:/g,
|
|
152
|
+
];
|
|
153
|
+
const findings = [];
|
|
154
|
+
for (const pattern of patterns) {
|
|
155
|
+
findings.push(...findMatches(content, pattern, "xss-risk", "warning", "Potential XSS risk: unsafe HTML manipulation", filename));
|
|
156
|
+
}
|
|
157
|
+
return findings;
|
|
158
|
+
},
|
|
159
|
+
};
|
|
160
|
+
export const securityRules = [
|
|
161
|
+
sqlInjection,
|
|
162
|
+
commandInjection,
|
|
163
|
+
hardcodedSecret,
|
|
164
|
+
unsafeEval,
|
|
165
|
+
pathTraversal,
|
|
166
|
+
xssRisk,
|
|
167
|
+
];
|
|
168
|
+
//# sourceMappingURL=security.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"security.js","sourceRoot":"","sources":["../../src/rules/security.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export type Severity = "info" | "warning" | "error";
|
|
2
|
+
export interface Finding {
|
|
3
|
+
rule: string;
|
|
4
|
+
severity: Severity;
|
|
5
|
+
message: string;
|
|
6
|
+
file: string;
|
|
7
|
+
line: number;
|
|
8
|
+
column: number;
|
|
9
|
+
snippet?: string;
|
|
10
|
+
}
|
|
11
|
+
export interface Rule {
|
|
12
|
+
name: string;
|
|
13
|
+
description: string;
|
|
14
|
+
severity: Severity;
|
|
15
|
+
languages: string[];
|
|
16
|
+
check: (content: string, filename: string) => Finding[];
|
|
17
|
+
}
|
|
18
|
+
export interface Config {
|
|
19
|
+
rules: Record<string, Severity | "off">;
|
|
20
|
+
ignore: string[];
|
|
21
|
+
languages: string[];
|
|
22
|
+
}
|
|
23
|
+
export interface AuditResult {
|
|
24
|
+
findings: Finding[];
|
|
25
|
+
filesScanned: number;
|
|
26
|
+
errorCount: number;
|
|
27
|
+
warningCount: number;
|
|
28
|
+
infoCount: number;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC;AAEpD,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,QAAQ,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,IAAI;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,QAAQ,CAAC;IACnB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,KAAK,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,OAAO,EAAE,CAAC;CACzD;AAED,MAAM,WAAW,MAAM;IACrB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,GAAG,KAAK,CAAC,CAAC;IACxC,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,SAAS,EAAE,MAAM,EAAE,CAAC;CACrB;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;CACnB"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
package/package.json
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@claude-tools-i-use/ai-code-audit",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Security and quality linter for AI-generated code",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"ai-code-audit": "dist/cli.js",
|
|
9
|
+
"aca": "dist/cli.js"
|
|
10
|
+
},
|
|
11
|
+
"files": [
|
|
12
|
+
"dist"
|
|
13
|
+
],
|
|
14
|
+
"scripts": {
|
|
15
|
+
"build": "tsc",
|
|
16
|
+
"dev": "tsc --watch",
|
|
17
|
+
"start": "node dist/cli.js",
|
|
18
|
+
"test": "node --test",
|
|
19
|
+
"clean": "rm -rf dist",
|
|
20
|
+
"prepublishOnly": "npm run build"
|
|
21
|
+
},
|
|
22
|
+
"keywords": [
|
|
23
|
+
"ai",
|
|
24
|
+
"security",
|
|
25
|
+
"lint",
|
|
26
|
+
"audit",
|
|
27
|
+
"code-review",
|
|
28
|
+
"owasp"
|
|
29
|
+
],
|
|
30
|
+
"author": "Josh Duffy",
|
|
31
|
+
"license": "MIT",
|
|
32
|
+
"repository": {
|
|
33
|
+
"type": "git",
|
|
34
|
+
"url": "https://github.com/joshduffy/claude-tools.git",
|
|
35
|
+
"directory": "packages/ai-code-audit"
|
|
36
|
+
},
|
|
37
|
+
"homepage": "https://joshduffy.dev/tools",
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"@types/node": "^22.10.0",
|
|
40
|
+
"typescript": "^5.7.0"
|
|
41
|
+
},
|
|
42
|
+
"engines": {
|
|
43
|
+
"node": ">=18.0.0"
|
|
44
|
+
}
|
|
45
|
+
}
|