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 +150 -0
- package/dist/auditor.d.ts +6 -0
- package/dist/auditor.js +197 -0
- package/dist/auditor.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +231 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +16 -0
- package/dist/index.js.map +1 -0
- package/dist/rules/ai-specific.d.ts +6 -0
- package/dist/rules/ai-specific.js +125 -0
- package/dist/rules/ai-specific.js.map +1 -0
- package/dist/rules/index.d.ts +6 -0
- package/dist/rules/index.js +15 -0
- package/dist/rules/index.js.map +1 -0
- package/dist/rules/quality.d.ts +7 -0
- package/dist/rules/quality.js +126 -0
- package/dist/rules/quality.js.map +1 -0
- package/dist/rules/security.d.ts +8 -0
- package/dist/rules/security.js +171 -0
- package/dist/rules/security.js.map +1 -0
- package/dist/types.d.ts +29 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/package.json +38 -0
- package/src/auditor.ts +226 -0
- package/src/cli.ts +274 -0
- package/src/index.ts +5 -0
- package/src/rules/ai-specific.ts +170 -0
- package/src/rules/index.ts +12 -0
- package/src/rules/quality.ts +169 -0
- package/src/rules/security.ts +247 -0
- package/src/types.ts +33 -0
- package/tsconfig.json +17 -0
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.aiSpecificRules = exports.excessiveComments = exports.typeAnyAbuse = exports.incompleteImpl = exports.aiPlaceholder = void 0;
|
|
4
|
+
function findMatches(content, pattern, rule, severity, message, filename) {
|
|
5
|
+
const findings = [];
|
|
6
|
+
const lines = content.split('\n');
|
|
7
|
+
for (let i = 0; i < lines.length; i++) {
|
|
8
|
+
const line = lines[i];
|
|
9
|
+
let match;
|
|
10
|
+
pattern.lastIndex = 0;
|
|
11
|
+
while ((match = pattern.exec(line)) !== null) {
|
|
12
|
+
findings.push({
|
|
13
|
+
rule,
|
|
14
|
+
severity,
|
|
15
|
+
message,
|
|
16
|
+
file: filename,
|
|
17
|
+
line: i + 1,
|
|
18
|
+
column: match.index + 1,
|
|
19
|
+
snippet: line.trim(),
|
|
20
|
+
});
|
|
21
|
+
if (!pattern.global)
|
|
22
|
+
break;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return findings;
|
|
26
|
+
}
|
|
27
|
+
exports.aiPlaceholder = {
|
|
28
|
+
name: 'ai-placeholder',
|
|
29
|
+
description: 'Detects placeholder text left by AI',
|
|
30
|
+
severity: 'error',
|
|
31
|
+
languages: ['javascript', 'typescript', 'python', 'ruby', 'go'],
|
|
32
|
+
check: (content, filename) => {
|
|
33
|
+
const patterns = [
|
|
34
|
+
/\/\/\s*(?:Add|TODO:?\s*add|Implement)\s+(?:your|the)\s+/gi,
|
|
35
|
+
/\/\/\s*(?:Replace|Update)\s+(?:this|with)\s+/gi,
|
|
36
|
+
/#\s*(?:Add|TODO:?\s*add|Implement)\s+(?:your|the)\s+/gi,
|
|
37
|
+
/\/\/\s*\.\.\.\s*(?:rest|more|additional|other)/gi,
|
|
38
|
+
/\/\*\s*(?:Add|Implement|Your)\s+.*\s+here\s*\*\//gi,
|
|
39
|
+
/['"](?:your-api-key|YOUR_API_KEY|api-key-here|replace-me|CHANGE_ME)['"]/gi,
|
|
40
|
+
/(?:example|placeholder|dummy)[@.](?:com|org|io)/gi,
|
|
41
|
+
];
|
|
42
|
+
const findings = [];
|
|
43
|
+
for (const pattern of patterns) {
|
|
44
|
+
findings.push(...findMatches(content, pattern, 'ai-placeholder', 'error', 'AI placeholder text detected - needs implementation', filename));
|
|
45
|
+
}
|
|
46
|
+
return findings;
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
exports.incompleteImpl = {
|
|
50
|
+
name: 'incomplete-impl',
|
|
51
|
+
description: 'Detects incomplete implementations',
|
|
52
|
+
severity: 'warning',
|
|
53
|
+
languages: ['javascript', 'typescript', 'python'],
|
|
54
|
+
check: (content, filename) => {
|
|
55
|
+
const patterns = [
|
|
56
|
+
/throw\s+new\s+Error\s*\(\s*['"](?:Not\s+implemented|TODO|FIXME)['"]/gi,
|
|
57
|
+
/raise\s+NotImplementedError/gi,
|
|
58
|
+
/pass\s*#\s*(?:TODO|FIXME)/gi,
|
|
59
|
+
/return\s+(?:null|undefined|None)\s*;?\s*\/\/\s*(?:TODO|FIXME)/gi,
|
|
60
|
+
];
|
|
61
|
+
const findings = [];
|
|
62
|
+
for (const pattern of patterns) {
|
|
63
|
+
findings.push(...findMatches(content, pattern, 'incomplete-impl', 'warning', 'Incomplete implementation detected', filename));
|
|
64
|
+
}
|
|
65
|
+
return findings;
|
|
66
|
+
},
|
|
67
|
+
};
|
|
68
|
+
exports.typeAnyAbuse = {
|
|
69
|
+
name: 'type-any-abuse',
|
|
70
|
+
description: 'Detects excessive use of any type',
|
|
71
|
+
severity: 'warning',
|
|
72
|
+
languages: ['typescript'],
|
|
73
|
+
check: (content, filename) => {
|
|
74
|
+
if (!filename.endsWith('.ts') && !filename.endsWith('.tsx')) {
|
|
75
|
+
return [];
|
|
76
|
+
}
|
|
77
|
+
const pattern = /:\s*any\b/g;
|
|
78
|
+
const findings = findMatches(content, pattern, 'type-any-abuse', 'warning', 'Unsafe "any" type usage - consider using a specific type', filename);
|
|
79
|
+
// Only report if there are many instances
|
|
80
|
+
if (findings.length > 3) {
|
|
81
|
+
return findings;
|
|
82
|
+
}
|
|
83
|
+
return [];
|
|
84
|
+
},
|
|
85
|
+
};
|
|
86
|
+
exports.excessiveComments = {
|
|
87
|
+
name: 'excessive-comments',
|
|
88
|
+
description: 'Detects over-commented obvious code',
|
|
89
|
+
severity: 'info',
|
|
90
|
+
languages: ['javascript', 'typescript'],
|
|
91
|
+
check: (content, filename) => {
|
|
92
|
+
const findings = [];
|
|
93
|
+
const lines = content.split('\n');
|
|
94
|
+
let commentLines = 0;
|
|
95
|
+
let codeLines = 0;
|
|
96
|
+
for (const line of lines) {
|
|
97
|
+
const trimmed = line.trim();
|
|
98
|
+
if (trimmed.startsWith('//') || trimmed.startsWith('/*') || trimmed.startsWith('*')) {
|
|
99
|
+
commentLines++;
|
|
100
|
+
}
|
|
101
|
+
else if (trimmed.length > 0) {
|
|
102
|
+
codeLines++;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
// If comments exceed 50% of code, flag it
|
|
106
|
+
if (codeLines > 10 && commentLines > codeLines * 0.5) {
|
|
107
|
+
findings.push({
|
|
108
|
+
rule: 'excessive-comments',
|
|
109
|
+
severity: 'info',
|
|
110
|
+
message: `High comment ratio (${commentLines} comments / ${codeLines} code lines) - may be over-documented`,
|
|
111
|
+
file: filename,
|
|
112
|
+
line: 1,
|
|
113
|
+
column: 1,
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
return findings;
|
|
117
|
+
},
|
|
118
|
+
};
|
|
119
|
+
exports.aiSpecificRules = [
|
|
120
|
+
exports.aiPlaceholder,
|
|
121
|
+
exports.incompleteImpl,
|
|
122
|
+
exports.typeAnyAbuse,
|
|
123
|
+
exports.excessiveComments,
|
|
124
|
+
];
|
|
125
|
+
//# 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,6 @@
|
|
|
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 };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.aiSpecificRules = exports.qualityRules = exports.securityRules = exports.allRules = void 0;
|
|
4
|
+
const security_js_1 = require("./security.js");
|
|
5
|
+
Object.defineProperty(exports, "securityRules", { enumerable: true, get: function () { return security_js_1.securityRules; } });
|
|
6
|
+
const quality_js_1 = require("./quality.js");
|
|
7
|
+
Object.defineProperty(exports, "qualityRules", { enumerable: true, get: function () { return quality_js_1.qualityRules; } });
|
|
8
|
+
const ai_specific_js_1 = require("./ai-specific.js");
|
|
9
|
+
Object.defineProperty(exports, "aiSpecificRules", { enumerable: true, get: function () { return ai_specific_js_1.aiSpecificRules; } });
|
|
10
|
+
exports.allRules = [
|
|
11
|
+
...security_js_1.securityRules,
|
|
12
|
+
...quality_js_1.qualityRules,
|
|
13
|
+
...ai_specific_js_1.aiSpecificRules,
|
|
14
|
+
];
|
|
15
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/rules/index.ts"],"names":[],"mappings":";;;AAAA,+CAA8C;AAWrC,8FAXA,2BAAa,OAWA;AAVtB,6CAA4C;AAUpB,6FAVf,yBAAY,OAUe;AATpC,qDAAmD;AASb,gGAT7B,gCAAe,OAS6B;AANxC,QAAA,QAAQ,GAAW;IAC9B,GAAG,2BAAa;IAChB,GAAG,yBAAY;IACf,GAAG,gCAAe;CACnB,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
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[];
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.qualityRules = exports.deepNesting = exports.todoFixme = exports.consoleLog = exports.emptyCatch = exports.missingErrorHandling = void 0;
|
|
4
|
+
function findMatches(content, pattern, rule, severity, message, filename) {
|
|
5
|
+
const findings = [];
|
|
6
|
+
const lines = content.split('\n');
|
|
7
|
+
for (let i = 0; i < lines.length; i++) {
|
|
8
|
+
const line = lines[i];
|
|
9
|
+
let match;
|
|
10
|
+
pattern.lastIndex = 0;
|
|
11
|
+
while ((match = pattern.exec(line)) !== null) {
|
|
12
|
+
findings.push({
|
|
13
|
+
rule,
|
|
14
|
+
severity,
|
|
15
|
+
message,
|
|
16
|
+
file: filename,
|
|
17
|
+
line: i + 1,
|
|
18
|
+
column: match.index + 1,
|
|
19
|
+
snippet: line.trim(),
|
|
20
|
+
});
|
|
21
|
+
if (!pattern.global)
|
|
22
|
+
break;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return findings;
|
|
26
|
+
}
|
|
27
|
+
exports.missingErrorHandling = {
|
|
28
|
+
name: 'missing-error-handling',
|
|
29
|
+
description: 'Detects async operations without try/catch',
|
|
30
|
+
severity: 'warning',
|
|
31
|
+
languages: ['javascript', 'typescript'],
|
|
32
|
+
check: (content, filename) => {
|
|
33
|
+
const findings = [];
|
|
34
|
+
const lines = content.split('\n');
|
|
35
|
+
// Look for await outside of try blocks
|
|
36
|
+
let inTry = 0;
|
|
37
|
+
for (let i = 0; i < lines.length; i++) {
|
|
38
|
+
const line = lines[i];
|
|
39
|
+
if (/\btry\s*\{/.test(line))
|
|
40
|
+
inTry++;
|
|
41
|
+
if (/\}\s*catch/.test(line))
|
|
42
|
+
inTry = Math.max(0, inTry - 1);
|
|
43
|
+
if (inTry === 0 && /\bawait\s+/.test(line)) {
|
|
44
|
+
// Check if it's in an async function without surrounding try
|
|
45
|
+
findings.push({
|
|
46
|
+
rule: 'missing-error-handling',
|
|
47
|
+
severity: 'warning',
|
|
48
|
+
message: 'Async operation without error handling',
|
|
49
|
+
file: filename,
|
|
50
|
+
line: i + 1,
|
|
51
|
+
column: line.indexOf('await') + 1,
|
|
52
|
+
snippet: line.trim(),
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return findings;
|
|
57
|
+
},
|
|
58
|
+
};
|
|
59
|
+
exports.emptyCatch = {
|
|
60
|
+
name: 'empty-catch',
|
|
61
|
+
description: 'Detects empty catch blocks that swallow errors',
|
|
62
|
+
severity: 'warning',
|
|
63
|
+
languages: ['javascript', 'typescript'],
|
|
64
|
+
check: (content, filename) => {
|
|
65
|
+
const pattern = /catch\s*\([^)]*\)\s*\{\s*\}/g;
|
|
66
|
+
return findMatches(content, pattern, 'empty-catch', 'warning', 'Empty catch block swallows errors', filename);
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
exports.consoleLog = {
|
|
70
|
+
name: 'console-log',
|
|
71
|
+
description: 'Detects console.log left in code',
|
|
72
|
+
severity: 'info',
|
|
73
|
+
languages: ['javascript', 'typescript'],
|
|
74
|
+
check: (content, filename) => {
|
|
75
|
+
const pattern = /console\.log\s*\(/g;
|
|
76
|
+
return findMatches(content, pattern, 'console-log', 'info', 'console.log statement found', filename);
|
|
77
|
+
},
|
|
78
|
+
};
|
|
79
|
+
exports.todoFixme = {
|
|
80
|
+
name: 'todo-fixme',
|
|
81
|
+
description: 'Detects TODO/FIXME comments',
|
|
82
|
+
severity: 'info',
|
|
83
|
+
languages: ['javascript', 'typescript', 'python', 'ruby', 'go'],
|
|
84
|
+
check: (content, filename) => {
|
|
85
|
+
const pattern = /\/\/\s*(?:TODO|FIXME|HACK|XXX|BUG)[\s:]/gi;
|
|
86
|
+
return findMatches(content, pattern, 'todo-fixme', 'info', 'TODO/FIXME comment found', filename);
|
|
87
|
+
},
|
|
88
|
+
};
|
|
89
|
+
exports.deepNesting = {
|
|
90
|
+
name: 'deep-nesting',
|
|
91
|
+
description: 'Detects deeply nested code (>4 levels)',
|
|
92
|
+
severity: 'warning',
|
|
93
|
+
languages: ['javascript', 'typescript'],
|
|
94
|
+
check: (content, filename) => {
|
|
95
|
+
const findings = [];
|
|
96
|
+
const lines = content.split('\n');
|
|
97
|
+
let depth = 0;
|
|
98
|
+
const MAX_DEPTH = 4;
|
|
99
|
+
for (let i = 0; i < lines.length; i++) {
|
|
100
|
+
const line = lines[i];
|
|
101
|
+
const opens = (line.match(/\{/g) || []).length;
|
|
102
|
+
const closes = (line.match(/\}/g) || []).length;
|
|
103
|
+
depth += opens - closes;
|
|
104
|
+
if (depth > MAX_DEPTH && opens > 0) {
|
|
105
|
+
findings.push({
|
|
106
|
+
rule: 'deep-nesting',
|
|
107
|
+
severity: 'warning',
|
|
108
|
+
message: `Code nested ${depth} levels deep (max: ${MAX_DEPTH})`,
|
|
109
|
+
file: filename,
|
|
110
|
+
line: i + 1,
|
|
111
|
+
column: 1,
|
|
112
|
+
snippet: line.trim(),
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
return findings;
|
|
117
|
+
},
|
|
118
|
+
};
|
|
119
|
+
exports.qualityRules = [
|
|
120
|
+
exports.missingErrorHandling,
|
|
121
|
+
exports.emptyCatch,
|
|
122
|
+
exports.consoleLog,
|
|
123
|
+
exports.todoFixme,
|
|
124
|
+
exports.deepNesting,
|
|
125
|
+
];
|
|
126
|
+
//# 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,8 @@
|
|
|
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[];
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.securityRules = exports.xssRisk = exports.pathTraversal = exports.unsafeEval = exports.hardcodedSecret = exports.commandInjection = exports.sqlInjection = void 0;
|
|
4
|
+
function findMatches(content, pattern, rule, severity, message, filename) {
|
|
5
|
+
const findings = [];
|
|
6
|
+
const lines = content.split('\n');
|
|
7
|
+
for (let i = 0; i < lines.length; i++) {
|
|
8
|
+
const line = lines[i];
|
|
9
|
+
let match;
|
|
10
|
+
// Reset regex for global patterns
|
|
11
|
+
pattern.lastIndex = 0;
|
|
12
|
+
while ((match = pattern.exec(line)) !== null) {
|
|
13
|
+
findings.push({
|
|
14
|
+
rule,
|
|
15
|
+
severity,
|
|
16
|
+
message,
|
|
17
|
+
file: filename,
|
|
18
|
+
line: i + 1,
|
|
19
|
+
column: match.index + 1,
|
|
20
|
+
snippet: line.trim(),
|
|
21
|
+
});
|
|
22
|
+
// Prevent infinite loop for non-global regex
|
|
23
|
+
if (!pattern.global)
|
|
24
|
+
break;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return findings;
|
|
28
|
+
}
|
|
29
|
+
exports.sqlInjection = {
|
|
30
|
+
name: 'sql-injection',
|
|
31
|
+
description: 'Detects SQL queries with string interpolation',
|
|
32
|
+
severity: 'error',
|
|
33
|
+
languages: ['javascript', 'typescript', 'python'],
|
|
34
|
+
check: (content, filename) => {
|
|
35
|
+
const patterns = [
|
|
36
|
+
// Template literals in SQL
|
|
37
|
+
/(?:query|execute|sql)\s*\(\s*`[^`]*\$\{/gi,
|
|
38
|
+
// String concatenation in SQL
|
|
39
|
+
/(?:query|execute|sql)\s*\(\s*['"][^'"]*['"]\s*\+/gi,
|
|
40
|
+
// Python f-strings in SQL
|
|
41
|
+
/(?:execute|cursor\.execute)\s*\(\s*f['"][^'"]*\{/gi,
|
|
42
|
+
];
|
|
43
|
+
const findings = [];
|
|
44
|
+
for (const pattern of patterns) {
|
|
45
|
+
findings.push(...findMatches(content, pattern, 'sql-injection', 'error', 'SQL injection risk: query uses string interpolation', filename));
|
|
46
|
+
}
|
|
47
|
+
return findings;
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
exports.commandInjection = {
|
|
51
|
+
name: 'command-injection',
|
|
52
|
+
description: 'Detects shell commands with unsanitized input',
|
|
53
|
+
severity: 'error',
|
|
54
|
+
languages: ['javascript', 'typescript', 'python'],
|
|
55
|
+
check: (content, filename) => {
|
|
56
|
+
const patterns = [
|
|
57
|
+
// exec with template literal
|
|
58
|
+
/(?:exec|execSync|spawn|spawnSync)\s*\(\s*`[^`]*\$\{/gi,
|
|
59
|
+
// exec with concatenation
|
|
60
|
+
/(?:exec|execSync|spawn|spawnSync)\s*\(\s*['"][^'"]*['"]\s*\+/gi,
|
|
61
|
+
// Python subprocess with f-string
|
|
62
|
+
/subprocess\.(?:run|call|Popen)\s*\(\s*f['"][^'"]*\{/gi,
|
|
63
|
+
// shell=True in Python
|
|
64
|
+
/subprocess\.(?:run|call|Popen)\s*\([^)]*shell\s*=\s*True/gi,
|
|
65
|
+
];
|
|
66
|
+
const findings = [];
|
|
67
|
+
for (const pattern of patterns) {
|
|
68
|
+
findings.push(...findMatches(content, pattern, 'command-injection', 'error', 'Command injection risk: shell command with unsanitized input', filename));
|
|
69
|
+
}
|
|
70
|
+
return findings;
|
|
71
|
+
},
|
|
72
|
+
};
|
|
73
|
+
exports.hardcodedSecret = {
|
|
74
|
+
name: 'hardcoded-secret',
|
|
75
|
+
description: 'Detects hardcoded API keys, passwords, tokens',
|
|
76
|
+
severity: 'error',
|
|
77
|
+
languages: ['javascript', 'typescript', 'python', 'ruby', 'go'],
|
|
78
|
+
check: (content, filename) => {
|
|
79
|
+
const patterns = [
|
|
80
|
+
// API keys
|
|
81
|
+
/(?:api[_-]?key|apikey)\s*[:=]\s*['"][a-zA-Z0-9_\-]{20,}['"]/gi,
|
|
82
|
+
// AWS keys
|
|
83
|
+
/(?:AKIA|ABIA|ACCA|ASIA)[A-Z0-9]{16}/g,
|
|
84
|
+
// Generic secrets
|
|
85
|
+
/(?:password|passwd|pwd|secret|token)\s*[:=]\s*['"][^'"]{8,}['"]/gi,
|
|
86
|
+
// Bearer tokens
|
|
87
|
+
/['"]Bearer\s+[a-zA-Z0-9_\-\.]+['"]/g,
|
|
88
|
+
// Private keys
|
|
89
|
+
/-----BEGIN\s+(?:RSA\s+)?PRIVATE\s+KEY-----/g,
|
|
90
|
+
// GitHub tokens
|
|
91
|
+
/gh[pousr]_[A-Za-z0-9_]{36,}/g,
|
|
92
|
+
// Slack tokens
|
|
93
|
+
/xox[baprs]-[A-Za-z0-9-]+/g,
|
|
94
|
+
];
|
|
95
|
+
const findings = [];
|
|
96
|
+
for (const pattern of patterns) {
|
|
97
|
+
findings.push(...findMatches(content, pattern, 'hardcoded-secret', 'error', 'Hardcoded secret detected', filename));
|
|
98
|
+
}
|
|
99
|
+
return findings;
|
|
100
|
+
},
|
|
101
|
+
};
|
|
102
|
+
exports.unsafeEval = {
|
|
103
|
+
name: 'unsafe-eval',
|
|
104
|
+
description: 'Detects use of eval() or Function()',
|
|
105
|
+
severity: 'error',
|
|
106
|
+
languages: ['javascript', 'typescript'],
|
|
107
|
+
check: (content, filename) => {
|
|
108
|
+
const patterns = [
|
|
109
|
+
/\beval\s*\(/g,
|
|
110
|
+
/new\s+Function\s*\(/g,
|
|
111
|
+
/setTimeout\s*\(\s*['"`]/g,
|
|
112
|
+
/setInterval\s*\(\s*['"`]/g,
|
|
113
|
+
];
|
|
114
|
+
const findings = [];
|
|
115
|
+
for (const pattern of patterns) {
|
|
116
|
+
findings.push(...findMatches(content, pattern, 'unsafe-eval', 'error', 'Unsafe eval() or Function() usage detected', filename));
|
|
117
|
+
}
|
|
118
|
+
return findings;
|
|
119
|
+
},
|
|
120
|
+
};
|
|
121
|
+
exports.pathTraversal = {
|
|
122
|
+
name: 'path-traversal',
|
|
123
|
+
description: 'Detects unsanitized file path operations',
|
|
124
|
+
severity: 'error',
|
|
125
|
+
languages: ['javascript', 'typescript', 'python'],
|
|
126
|
+
check: (content, filename) => {
|
|
127
|
+
const patterns = [
|
|
128
|
+
// Direct path concatenation
|
|
129
|
+
/(?:readFile|writeFile|unlink|rmdir|mkdir)(?:Sync)?\s*\(\s*(?:req\.|request\.|params\.|query\.)/gi,
|
|
130
|
+
// Python path with user input
|
|
131
|
+
/open\s*\(\s*(?:request\.|args\.|kwargs\.)/gi,
|
|
132
|
+
// Path join with user input
|
|
133
|
+
/path\.join\s*\([^)]*(?:req\.|request\.|params\.|query\.)/gi,
|
|
134
|
+
];
|
|
135
|
+
const findings = [];
|
|
136
|
+
for (const pattern of patterns) {
|
|
137
|
+
findings.push(...findMatches(content, pattern, 'path-traversal', 'error', 'Path traversal risk: file operation with user input', filename));
|
|
138
|
+
}
|
|
139
|
+
return findings;
|
|
140
|
+
},
|
|
141
|
+
};
|
|
142
|
+
exports.xssRisk = {
|
|
143
|
+
name: 'xss-risk',
|
|
144
|
+
description: 'Detects potential XSS in HTML generation',
|
|
145
|
+
severity: 'warning',
|
|
146
|
+
languages: ['javascript', 'typescript'],
|
|
147
|
+
check: (content, filename) => {
|
|
148
|
+
const patterns = [
|
|
149
|
+
// innerHTML with variable
|
|
150
|
+
/\.innerHTML\s*=\s*[^'"]/g,
|
|
151
|
+
// document.write
|
|
152
|
+
/document\.write\s*\(/g,
|
|
153
|
+
// dangerouslySetInnerHTML
|
|
154
|
+
/dangerouslySetInnerHTML\s*=\s*\{\s*\{\s*__html\s*:/g,
|
|
155
|
+
];
|
|
156
|
+
const findings = [];
|
|
157
|
+
for (const pattern of patterns) {
|
|
158
|
+
findings.push(...findMatches(content, pattern, 'xss-risk', 'warning', 'Potential XSS risk: unsafe HTML manipulation', filename));
|
|
159
|
+
}
|
|
160
|
+
return findings;
|
|
161
|
+
},
|
|
162
|
+
};
|
|
163
|
+
exports.securityRules = [
|
|
164
|
+
exports.sqlInjection,
|
|
165
|
+
exports.commandInjection,
|
|
166
|
+
exports.hardcodedSecret,
|
|
167
|
+
exports.unsafeEval,
|
|
168
|
+
exports.pathTraversal,
|
|
169
|
+
exports.xssRisk,
|
|
170
|
+
];
|
|
171
|
+
//# 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,29 @@
|
|
|
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
|
+
}
|
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,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "ai-code-audit",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Security and quality linter for AI-generated code",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"ai-code-audit": "dist/cli.js",
|
|
8
|
+
"aca": "dist/cli.js"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "tsc",
|
|
12
|
+
"dev": "tsc --watch",
|
|
13
|
+
"start": "node dist/cli.js",
|
|
14
|
+
"test": "node --test",
|
|
15
|
+
"prepublishOnly": "npm run build"
|
|
16
|
+
},
|
|
17
|
+
"keywords": [
|
|
18
|
+
"ai",
|
|
19
|
+
"security",
|
|
20
|
+
"lint",
|
|
21
|
+
"audit",
|
|
22
|
+
"code-review",
|
|
23
|
+
"owasp"
|
|
24
|
+
],
|
|
25
|
+
"author": "Josh Duffy",
|
|
26
|
+
"license": "MIT",
|
|
27
|
+
"repository": {
|
|
28
|
+
"type": "git",
|
|
29
|
+
"url": "https://github.com/joshduffy/ai-code-audit.git"
|
|
30
|
+
},
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"@types/node": "^20.0.0",
|
|
33
|
+
"typescript": "^5.3.0"
|
|
34
|
+
},
|
|
35
|
+
"engines": {
|
|
36
|
+
"node": ">=18.0.0"
|
|
37
|
+
}
|
|
38
|
+
}
|