@guardrail-ai/rules 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/dist/__tests__/advanced-rules.test.d.ts +2 -0
- package/dist/__tests__/advanced-rules.test.d.ts.map +1 -0
- package/dist/__tests__/advanced-rules.test.js +59 -0
- package/dist/__tests__/advanced-rules.test.js.map +1 -0
- package/dist/__tests__/dead-code.test.d.ts +2 -0
- package/dist/__tests__/dead-code.test.d.ts.map +1 -0
- package/dist/__tests__/dead-code.test.js +66 -0
- package/dist/__tests__/dead-code.test.js.map +1 -0
- package/dist/__tests__/duplicate-logic.test.d.ts +2 -0
- package/dist/__tests__/duplicate-logic.test.d.ts.map +1 -0
- package/dist/__tests__/duplicate-logic.test.js +47 -0
- package/dist/__tests__/duplicate-logic.test.js.map +1 -0
- package/dist/__tests__/hardcoded-api-key.test.d.ts +2 -0
- package/dist/__tests__/hardcoded-api-key.test.d.ts.map +1 -0
- package/dist/__tests__/hardcoded-api-key.test.js +44 -0
- package/dist/__tests__/hardcoded-api-key.test.js.map +1 -0
- package/dist/__tests__/inefficient-loop.test.d.ts +2 -0
- package/dist/__tests__/inefficient-loop.test.d.ts.map +1 -0
- package/dist/__tests__/inefficient-loop.test.js +49 -0
- package/dist/__tests__/inefficient-loop.test.js.map +1 -0
- package/dist/__tests__/new-rules.test.d.ts +2 -0
- package/dist/__tests__/new-rules.test.d.ts.map +1 -0
- package/dist/__tests__/new-rules.test.js +193 -0
- package/dist/__tests__/new-rules.test.js.map +1 -0
- package/dist/__tests__/sql-injection.test.d.ts +2 -0
- package/dist/__tests__/sql-injection.test.d.ts.map +1 -0
- package/dist/__tests__/sql-injection.test.js +40 -0
- package/dist/__tests__/sql-injection.test.js.map +1 -0
- package/dist/any-type-abuse.d.ts +4 -0
- package/dist/any-type-abuse.d.ts.map +1 -0
- package/dist/any-type-abuse.js +37 -0
- package/dist/any-type-abuse.js.map +1 -0
- package/dist/console-log-spam.d.ts +4 -0
- package/dist/console-log-spam.d.ts.map +1 -0
- package/dist/console-log-spam.js +60 -0
- package/dist/console-log-spam.js.map +1 -0
- package/dist/data/hallucinated-packages.json +212 -0
- package/dist/dead-code.d.ts +10 -0
- package/dist/dead-code.d.ts.map +1 -0
- package/dist/dead-code.js +152 -0
- package/dist/dead-code.js.map +1 -0
- package/dist/duplicate-logic.d.ts +4 -0
- package/dist/duplicate-logic.d.ts.map +1 -0
- package/dist/duplicate-logic.js +90 -0
- package/dist/duplicate-logic.js.map +1 -0
- package/dist/env-var-leak.d.ts +4 -0
- package/dist/env-var-leak.d.ts.map +1 -0
- package/dist/env-var-leak.js +86 -0
- package/dist/env-var-leak.js.map +1 -0
- package/dist/fetch-without-error-handling.d.ts +4 -0
- package/dist/fetch-without-error-handling.d.ts.map +1 -0
- package/dist/fetch-without-error-handling.js +62 -0
- package/dist/fetch-without-error-handling.js.map +1 -0
- package/dist/hallucinated-import.d.ts +4 -0
- package/dist/hallucinated-import.d.ts.map +1 -0
- package/dist/hallucinated-import.js +75 -0
- package/dist/hallucinated-import.js.map +1 -0
- package/dist/hardcoded-api-key.d.ts +4 -0
- package/dist/hardcoded-api-key.d.ts.map +1 -0
- package/dist/hardcoded-api-key.js +129 -0
- package/dist/hardcoded-api-key.js.map +1 -0
- package/dist/hardcoded-localhost.d.ts +4 -0
- package/dist/hardcoded-localhost.d.ts.map +1 -0
- package/dist/hardcoded-localhost.js +53 -0
- package/dist/hardcoded-localhost.js.map +1 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +83 -0
- package/dist/index.js.map +1 -0
- package/dist/inefficient-loop.d.ts +4 -0
- package/dist/inefficient-loop.d.ts.map +1 -0
- package/dist/inefficient-loop.js +104 -0
- package/dist/inefficient-loop.js.map +1 -0
- package/dist/insecure-cors.d.ts +4 -0
- package/dist/insecure-cors.d.ts.map +1 -0
- package/dist/insecure-cors.js +89 -0
- package/dist/insecure-cors.js.map +1 -0
- package/dist/magic-numbers.d.ts +4 -0
- package/dist/magic-numbers.d.ts.map +1 -0
- package/dist/magic-numbers.js +53 -0
- package/dist/magic-numbers.js.map +1 -0
- package/dist/n-plus-one-query.d.ts +4 -0
- package/dist/n-plus-one-query.d.ts.map +1 -0
- package/dist/n-plus-one-query.js +95 -0
- package/dist/n-plus-one-query.js.map +1 -0
- package/dist/no-eval.d.ts +4 -0
- package/dist/no-eval.d.ts.map +1 -0
- package/dist/no-eval.js +53 -0
- package/dist/no-eval.js.map +1 -0
- package/dist/no-rate-limiting.d.ts +4 -0
- package/dist/no-rate-limiting.d.ts.map +1 -0
- package/dist/no-rate-limiting.js +72 -0
- package/dist/no-rate-limiting.js.map +1 -0
- package/dist/no-secrets-in-logs.d.ts +4 -0
- package/dist/no-secrets-in-logs.d.ts.map +1 -0
- package/dist/no-secrets-in-logs.js +71 -0
- package/dist/no-secrets-in-logs.js.map +1 -0
- package/dist/overly-broad-catch.d.ts +4 -0
- package/dist/overly-broad-catch.d.ts.map +1 -0
- package/dist/overly-broad-catch.js +48 -0
- package/dist/overly-broad-catch.js.map +1 -0
- package/dist/placeholder-code.d.ts +4 -0
- package/dist/placeholder-code.d.ts.map +1 -0
- package/dist/placeholder-code.js +58 -0
- package/dist/placeholder-code.js.map +1 -0
- package/dist/promise-without-catch.d.ts +4 -0
- package/dist/promise-without-catch.d.ts.map +1 -0
- package/dist/promise-without-catch.js +72 -0
- package/dist/promise-without-catch.js.map +1 -0
- package/dist/sql-injection.d.ts +4 -0
- package/dist/sql-injection.d.ts.map +1 -0
- package/dist/sql-injection.js +108 -0
- package/dist/sql-injection.js.map +1 -0
- package/dist/unsafe-regex.d.ts +4 -0
- package/dist/unsafe-regex.d.ts.map +1 -0
- package/dist/unsafe-regex.js +75 -0
- package/dist/unsafe-regex.js.map +1 -0
- package/dist/unused-imports.d.ts +4 -0
- package/dist/unused-imports.d.ts.map +1 -0
- package/dist/unused-imports.js +56 -0
- package/dist/unused-imports.js.map +1 -0
- package/package.json +32 -0
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const traverse_1 = __importDefault(require("@babel/traverse"));
|
|
7
|
+
const LOG_METHODS = new Set(['log', 'debug', 'info', 'warn', 'error', 'trace']);
|
|
8
|
+
const RESPONSE_METHODS = new Set(['json', 'send', 'write', 'end']);
|
|
9
|
+
const envVarLeakRule = {
|
|
10
|
+
id: 'security/env-var-leak',
|
|
11
|
+
name: 'Environment Variable Leak',
|
|
12
|
+
description: 'Detects process.env values being passed to console.log or HTTP response methods',
|
|
13
|
+
severity: 'high',
|
|
14
|
+
category: 'security',
|
|
15
|
+
detect(context) {
|
|
16
|
+
const violations = [];
|
|
17
|
+
const { ast, filePath } = context;
|
|
18
|
+
(0, traverse_1.default)(ast, {
|
|
19
|
+
CallExpression(path) {
|
|
20
|
+
const callee = path.node.callee;
|
|
21
|
+
// Check if this is console.log(process.env.X) or res.json(process.env.X)
|
|
22
|
+
if (callee.type !== 'MemberExpression')
|
|
23
|
+
return;
|
|
24
|
+
if (callee.property.type !== 'Identifier')
|
|
25
|
+
return;
|
|
26
|
+
const isLogCall = callee.object.type === 'Identifier' &&
|
|
27
|
+
callee.object.name === 'console' &&
|
|
28
|
+
LOG_METHODS.has(callee.property.name);
|
|
29
|
+
const isResponseCall = RESPONSE_METHODS.has(callee.property.name);
|
|
30
|
+
if (!isLogCall && !isResponseCall)
|
|
31
|
+
return;
|
|
32
|
+
// Check if any argument references process.env
|
|
33
|
+
for (const arg of path.node.arguments) {
|
|
34
|
+
if (arg.type === 'SpreadElement')
|
|
35
|
+
continue;
|
|
36
|
+
if (containsProcessEnv(arg)) {
|
|
37
|
+
violations.push({
|
|
38
|
+
ruleId: 'security/env-var-leak',
|
|
39
|
+
severity: 'high',
|
|
40
|
+
message: `process.env value passed to ${isLogCall ? 'console' : 'response'} — may leak secrets.`,
|
|
41
|
+
location: {
|
|
42
|
+
file: filePath,
|
|
43
|
+
line: path.node.loc?.start.line ?? 0,
|
|
44
|
+
column: path.node.loc?.start.column ?? 0,
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
break;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
});
|
|
52
|
+
return violations;
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
function containsProcessEnv(node) {
|
|
56
|
+
if (!node || typeof node !== 'object')
|
|
57
|
+
return false;
|
|
58
|
+
// process.env.X
|
|
59
|
+
if (node.type === 'MemberExpression' &&
|
|
60
|
+
node.object?.type === 'MemberExpression' &&
|
|
61
|
+
node.object.object?.type === 'Identifier' &&
|
|
62
|
+
node.object.object.name === 'process' &&
|
|
63
|
+
node.object.property?.type === 'Identifier' &&
|
|
64
|
+
node.object.property.name === 'env') {
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
// Recurse into child nodes
|
|
68
|
+
for (const key of Object.keys(node)) {
|
|
69
|
+
if (key === 'loc' || key === 'start' || key === 'end' || key === 'type')
|
|
70
|
+
continue;
|
|
71
|
+
const child = node[key];
|
|
72
|
+
if (Array.isArray(child)) {
|
|
73
|
+
for (const item of child) {
|
|
74
|
+
if (containsProcessEnv(item))
|
|
75
|
+
return true;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
else if (child && typeof child === 'object' && child.type) {
|
|
79
|
+
if (containsProcessEnv(child))
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
exports.default = envVarLeakRule;
|
|
86
|
+
//# sourceMappingURL=env-var-leak.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env-var-leak.js","sourceRoot":"","sources":["../src/env-var-leak.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fetch-without-error-handling.d.ts","sourceRoot":"","sources":["../src/fetch-without-error-handling.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAA0B,MAAM,oBAAoB,CAAC;AAEvE,QAAA,MAAM,6BAA6B,EAAE,IAgEpC,CAAC;AAEF,eAAe,6BAA6B,CAAC"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const traverse_1 = __importDefault(require("@babel/traverse"));
|
|
7
|
+
const fetchWithoutErrorHandlingRule = {
|
|
8
|
+
id: 'ai-codegen/fetch-without-error-handling',
|
|
9
|
+
name: 'Fetch Without Error Handling',
|
|
10
|
+
description: 'Detects fetch() calls not wrapped in try/catch or without .catch()',
|
|
11
|
+
severity: 'warning',
|
|
12
|
+
category: 'ai-codegen',
|
|
13
|
+
detect(context) {
|
|
14
|
+
const violations = [];
|
|
15
|
+
const { ast, filePath } = context;
|
|
16
|
+
(0, traverse_1.default)(ast, {
|
|
17
|
+
CallExpression(path) {
|
|
18
|
+
const callee = path.node.callee;
|
|
19
|
+
// Match fetch() or window.fetch()
|
|
20
|
+
const isFetch = (callee.type === 'Identifier' && callee.name === 'fetch') ||
|
|
21
|
+
(callee.type === 'MemberExpression' &&
|
|
22
|
+
callee.property.type === 'Identifier' &&
|
|
23
|
+
callee.property.name === 'fetch');
|
|
24
|
+
if (!isFetch)
|
|
25
|
+
return;
|
|
26
|
+
// Check if it's inside a try block
|
|
27
|
+
let inTry = false;
|
|
28
|
+
let hasCatch = false;
|
|
29
|
+
// Walk up ancestors
|
|
30
|
+
const ancestors = path.getAncestry();
|
|
31
|
+
for (const anc of ancestors) {
|
|
32
|
+
if (anc.isTryStatement()) {
|
|
33
|
+
inTry = true;
|
|
34
|
+
break;
|
|
35
|
+
}
|
|
36
|
+
if (anc.isCallExpression() &&
|
|
37
|
+
anc.node.callee.type === 'MemberExpression' &&
|
|
38
|
+
anc.node.callee.property.type === 'Identifier' &&
|
|
39
|
+
anc.node.callee.property.name === 'catch') {
|
|
40
|
+
hasCatch = true;
|
|
41
|
+
break;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
if (!inTry && !hasCatch) {
|
|
45
|
+
violations.push({
|
|
46
|
+
ruleId: 'ai-codegen/fetch-without-error-handling',
|
|
47
|
+
severity: 'warning',
|
|
48
|
+
message: 'fetch() call without error handling. Wrap in try/catch or chain .catch().',
|
|
49
|
+
location: {
|
|
50
|
+
file: filePath,
|
|
51
|
+
line: path.node.loc?.start.line ?? 0,
|
|
52
|
+
column: path.node.loc?.start.column ?? 0,
|
|
53
|
+
},
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
});
|
|
58
|
+
return violations;
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
exports.default = fetchWithoutErrorHandlingRule;
|
|
62
|
+
//# sourceMappingURL=fetch-without-error-handling.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fetch-without-error-handling.js","sourceRoot":"","sources":["../src/fetch-without-error-handling.ts"],"names":[],"mappings":";;;;;AAAA,+DAAuC;AAGvC,MAAM,6BAA6B,GAAS;IAC1C,EAAE,EAAE,yCAAyC;IAC7C,IAAI,EAAE,8BAA8B;IACpC,WAAW,EAAE,oEAAoE;IACjF,QAAQ,EAAE,SAAS;IACnB,QAAQ,EAAE,YAAY;IAEtB,MAAM,CAAC,OAAoB;QACzB,MAAM,UAAU,GAAgB,EAAE,CAAC;QACnC,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC;QAElC,IAAA,kBAAQ,EAAC,GAAG,EAAE;YACZ,cAAc,CAAC,IAAI;gBACjB,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC;gBAEhC,kCAAkC;gBAClC,MAAM,OAAO,GACX,CAAC,MAAM,CAAC,IAAI,KAAK,YAAY,IAAI,MAAM,CAAC,IAAI,KAAK,OAAO,CAAC;oBACzD,CAAC,MAAM,CAAC,IAAI,KAAK,kBAAkB;wBACjC,MAAM,CAAC,QAAQ,CAAC,IAAI,KAAK,YAAY;wBACrC,MAAM,CAAC,QAAQ,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC;gBAEtC,IAAI,CAAC,OAAO;oBAAE,OAAO;gBAErB,mCAAmC;gBACnC,IAAI,KAAK,GAAG,KAAK,CAAC;gBAClB,IAAI,QAAQ,GAAG,KAAK,CAAC;gBAErB,oBAAoB;gBACpB,MAAM,SAAS,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;gBACrC,KAAK,MAAM,GAAG,IAAI,SAAS,EAAE,CAAC;oBAC5B,IAAI,GAAG,CAAC,cAAc,EAAE,EAAE,CAAC;wBACzB,KAAK,GAAG,IAAI,CAAC;wBACb,MAAM;oBACR,CAAC;oBACD,IACE,GAAG,CAAC,gBAAgB,EAAE;wBACtB,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,KAAK,kBAAkB;wBAC3C,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,KAAK,YAAY;wBAC9C,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,KAAK,OAAO,EACzC,CAAC;wBACD,QAAQ,GAAG,IAAI,CAAC;wBAChB,MAAM;oBACR,CAAC;gBACH,CAAC;gBAED,IAAI,CAAC,KAAK,IAAI,CAAC,QAAQ,EAAE,CAAC;oBACxB,UAAU,CAAC,IAAI,CAAC;wBACd,MAAM,EAAE,yCAAyC;wBACjD,QAAQ,EAAE,SAAS;wBACnB,OAAO,EACL,2EAA2E;wBAC7E,QAAQ,EAAE;4BACR,IAAI,EAAE,QAAQ;4BACd,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,IAAI,CAAC;4BACpC,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,MAAM,IAAI,CAAC;yBACzC;qBACF,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;SACF,CAAC,CAAC;QAEH,OAAO,UAAU,CAAC;IACpB,CAAC;CACF,CAAC;AAEF,kBAAe,6BAA6B,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hallucinated-import.d.ts","sourceRoot":"","sources":["../src/hallucinated-import.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAA0B,MAAM,oBAAoB,CAAC;AAuBvE,QAAA,MAAM,sBAAsB,EAAE,IAuD7B,CAAC;AAEF,eAAe,sBAAsB,CAAC"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const traverse_1 = __importDefault(require("@babel/traverse"));
|
|
7
|
+
const hallucinated_packages_json_1 = __importDefault(require("./data/hallucinated-packages.json"));
|
|
8
|
+
const HALLUCINATED_SET = new Set(hallucinated_packages_json_1.default);
|
|
9
|
+
// Heuristic: packages ending in -utils, -helpers, -tools with generic prefixes
|
|
10
|
+
const SUSPICIOUS_SUFFIX = /^[a-z]+-(?:utils|helpers|tools|lib|common|shared|base)$/;
|
|
11
|
+
function isSuspicious(source) {
|
|
12
|
+
// Skip relative imports and builtins
|
|
13
|
+
if (source.startsWith('.') || source.startsWith('/'))
|
|
14
|
+
return false;
|
|
15
|
+
// Get bare package name (strip deep imports)
|
|
16
|
+
const pkg = source.startsWith('@')
|
|
17
|
+
? source.split('/').slice(0, 2).join('/')
|
|
18
|
+
: source.split('/')[0];
|
|
19
|
+
if (HALLUCINATED_SET.has(pkg))
|
|
20
|
+
return true;
|
|
21
|
+
if (SUSPICIOUS_SUFFIX.test(pkg))
|
|
22
|
+
return true;
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
const hallucinatedImportRule = {
|
|
26
|
+
id: 'ai-codegen/hallucinated-import',
|
|
27
|
+
name: 'Hallucinated Import',
|
|
28
|
+
description: 'Detects imports of npm packages commonly hallucinated by AI code generators',
|
|
29
|
+
severity: 'high',
|
|
30
|
+
category: 'ai-codegen',
|
|
31
|
+
detect(context) {
|
|
32
|
+
const violations = [];
|
|
33
|
+
const { ast, filePath } = context;
|
|
34
|
+
(0, traverse_1.default)(ast, {
|
|
35
|
+
ImportDeclaration(path) {
|
|
36
|
+
const source = path.node.source.value;
|
|
37
|
+
if (isSuspicious(source)) {
|
|
38
|
+
violations.push({
|
|
39
|
+
ruleId: 'ai-codegen/hallucinated-import',
|
|
40
|
+
severity: 'high',
|
|
41
|
+
message: `Potentially hallucinated import "${source}". Verify this package exists on npm.`,
|
|
42
|
+
location: {
|
|
43
|
+
file: filePath,
|
|
44
|
+
line: path.node.loc?.start.line ?? 0,
|
|
45
|
+
column: path.node.loc?.start.column ?? 0,
|
|
46
|
+
},
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
CallExpression(path) {
|
|
51
|
+
if (path.node.callee.type === 'Identifier' &&
|
|
52
|
+
path.node.callee.name === 'require' &&
|
|
53
|
+
path.node.arguments.length === 1 &&
|
|
54
|
+
path.node.arguments[0].type === 'StringLiteral') {
|
|
55
|
+
const source = path.node.arguments[0].value;
|
|
56
|
+
if (isSuspicious(source)) {
|
|
57
|
+
violations.push({
|
|
58
|
+
ruleId: 'ai-codegen/hallucinated-import',
|
|
59
|
+
severity: 'high',
|
|
60
|
+
message: `Potentially hallucinated require "${source}". Verify this package exists on npm.`,
|
|
61
|
+
location: {
|
|
62
|
+
file: filePath,
|
|
63
|
+
line: path.node.loc?.start.line ?? 0,
|
|
64
|
+
column: path.node.loc?.start.column ?? 0,
|
|
65
|
+
},
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
});
|
|
71
|
+
return violations;
|
|
72
|
+
},
|
|
73
|
+
};
|
|
74
|
+
exports.default = hallucinatedImportRule;
|
|
75
|
+
//# sourceMappingURL=hallucinated-import.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hallucinated-import.js","sourceRoot":"","sources":["../src/hallucinated-import.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hardcoded-api-key.d.ts","sourceRoot":"","sources":["../src/hardcoded-api-key.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAA0B,MAAM,oBAAoB,CAAC;AAgCvE,QAAA,MAAM,mBAAmB,EAAE,IAiH1B,CAAC;AAEF,eAAe,mBAAmB,CAAC"}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const traverse_1 = __importDefault(require("@babel/traverse"));
|
|
7
|
+
/**
|
|
8
|
+
* Detects hardcoded API keys, secrets, and tokens in source code.
|
|
9
|
+
*
|
|
10
|
+
* Catches patterns like:
|
|
11
|
+
* const API_KEY = "sk-abc123..."
|
|
12
|
+
* headers: { Authorization: "Bearer eyJ..." }
|
|
13
|
+
* password = "hardcoded"
|
|
14
|
+
*/
|
|
15
|
+
const SUSPICIOUS_NAMES = /(?:api[_-]?key|secret|token|password|passwd|credentials|auth|bearer|private[_-]?key|access[_-]?key|client[_-]?secret)/i;
|
|
16
|
+
const KEY_PATTERNS = [
|
|
17
|
+
/^sk-[a-zA-Z0-9]{20,}$/, // OpenAI-style
|
|
18
|
+
/^ghp_[a-zA-Z0-9]{36}$/, // GitHub PAT
|
|
19
|
+
/^github_pat_[a-zA-Z0-9_]{80,}$/, // GitHub fine-grained PAT
|
|
20
|
+
/^glpat-[a-zA-Z0-9\-_]{20,}$/, // GitLab PAT
|
|
21
|
+
/^xox[bposa]-[a-zA-Z0-9\-]{10,}$/, // Slack tokens
|
|
22
|
+
/^AKIA[0-9A-Z]{16}$/, // AWS Access Key
|
|
23
|
+
/^eyJ[a-zA-Z0-9\-_]+\.[a-zA-Z0-9\-_]+\.[a-zA-Z0-9\-_]+$/, // JWT
|
|
24
|
+
/^Bearer\s+[a-zA-Z0-9\-_.]+$/, // Bearer token
|
|
25
|
+
];
|
|
26
|
+
const MIN_SUSPICIOUS_LENGTH = 8;
|
|
27
|
+
function looksLikeSecret(value) {
|
|
28
|
+
if (value.length < MIN_SUSPICIOUS_LENGTH)
|
|
29
|
+
return false;
|
|
30
|
+
return KEY_PATTERNS.some((pattern) => pattern.test(value));
|
|
31
|
+
}
|
|
32
|
+
const hardcodedApiKeyRule = {
|
|
33
|
+
id: 'security/hardcoded-api-key',
|
|
34
|
+
name: 'Hardcoded API Key',
|
|
35
|
+
description: 'Detects hardcoded API keys, secrets, and tokens that should be stored in environment variables',
|
|
36
|
+
severity: 'critical',
|
|
37
|
+
category: 'security',
|
|
38
|
+
detect(context) {
|
|
39
|
+
const violations = [];
|
|
40
|
+
const { ast, filePath } = context;
|
|
41
|
+
(0, traverse_1.default)(ast, {
|
|
42
|
+
VariableDeclarator(path) {
|
|
43
|
+
const { id, init } = path.node;
|
|
44
|
+
if (id.type === 'Identifier' &&
|
|
45
|
+
init?.type === 'StringLiteral' &&
|
|
46
|
+
SUSPICIOUS_NAMES.test(id.name)) {
|
|
47
|
+
const value = init.value;
|
|
48
|
+
if (value.length >= MIN_SUSPICIOUS_LENGTH) {
|
|
49
|
+
violations.push({
|
|
50
|
+
ruleId: 'security/hardcoded-api-key',
|
|
51
|
+
severity: 'critical',
|
|
52
|
+
message: `Hardcoded secret in variable "${id.name}". Use environment variables instead.`,
|
|
53
|
+
location: {
|
|
54
|
+
file: filePath,
|
|
55
|
+
line: id.loc?.start.line ?? 0,
|
|
56
|
+
column: id.loc?.start.column ?? 0,
|
|
57
|
+
},
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
AssignmentExpression(path) {
|
|
63
|
+
const { left, right } = path.node;
|
|
64
|
+
if (left.type === 'MemberExpression' &&
|
|
65
|
+
left.property.type === 'Identifier' &&
|
|
66
|
+
SUSPICIOUS_NAMES.test(left.property.name) &&
|
|
67
|
+
right.type === 'StringLiteral' &&
|
|
68
|
+
right.value.length >= MIN_SUSPICIOUS_LENGTH) {
|
|
69
|
+
violations.push({
|
|
70
|
+
ruleId: 'security/hardcoded-api-key',
|
|
71
|
+
severity: 'critical',
|
|
72
|
+
message: `Hardcoded secret assigned to "${left.property.name}". Use environment variables instead.`,
|
|
73
|
+
location: {
|
|
74
|
+
file: filePath,
|
|
75
|
+
line: left.loc?.start.line ?? 0,
|
|
76
|
+
column: left.loc?.start.column ?? 0,
|
|
77
|
+
},
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
StringLiteral(path) {
|
|
82
|
+
if (looksLikeSecret(path.node.value)) {
|
|
83
|
+
// Avoid double-reporting if already caught above
|
|
84
|
+
const parent = path.parent;
|
|
85
|
+
if (parent.type === 'VariableDeclarator' ||
|
|
86
|
+
parent.type === 'AssignmentExpression') {
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
violations.push({
|
|
90
|
+
ruleId: 'security/hardcoded-api-key',
|
|
91
|
+
severity: 'critical',
|
|
92
|
+
message: `String literal looks like a hardcoded secret or token. Use environment variables instead.`,
|
|
93
|
+
location: {
|
|
94
|
+
file: filePath,
|
|
95
|
+
line: path.node.loc?.start.line ?? 0,
|
|
96
|
+
column: path.node.loc?.start.column ?? 0,
|
|
97
|
+
},
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
},
|
|
101
|
+
ObjectProperty(path) {
|
|
102
|
+
const { key, value } = path.node;
|
|
103
|
+
const keyName = key.type === 'Identifier'
|
|
104
|
+
? key.name
|
|
105
|
+
: key.type === 'StringLiteral'
|
|
106
|
+
? key.value
|
|
107
|
+
: null;
|
|
108
|
+
if (keyName &&
|
|
109
|
+
SUSPICIOUS_NAMES.test(keyName) &&
|
|
110
|
+
value.type === 'StringLiteral' &&
|
|
111
|
+
value.value.length >= MIN_SUSPICIOUS_LENGTH) {
|
|
112
|
+
violations.push({
|
|
113
|
+
ruleId: 'security/hardcoded-api-key',
|
|
114
|
+
severity: 'critical',
|
|
115
|
+
message: `Hardcoded secret in property "${keyName}". Use environment variables instead.`,
|
|
116
|
+
location: {
|
|
117
|
+
file: filePath,
|
|
118
|
+
line: key.loc?.start.line ?? 0,
|
|
119
|
+
column: key.loc?.start.column ?? 0,
|
|
120
|
+
},
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
},
|
|
124
|
+
});
|
|
125
|
+
return violations;
|
|
126
|
+
},
|
|
127
|
+
};
|
|
128
|
+
exports.default = hardcodedApiKeyRule;
|
|
129
|
+
//# sourceMappingURL=hardcoded-api-key.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hardcoded-api-key.js","sourceRoot":"","sources":["../src/hardcoded-api-key.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hardcoded-localhost.d.ts","sourceRoot":"","sources":["../src/hardcoded-localhost.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAA0B,MAAM,oBAAoB,CAAC;AAKvE,QAAA,MAAM,sBAAsB,EAAE,IAiD7B,CAAC;AAEF,eAAe,sBAAsB,CAAC"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const traverse_1 = __importDefault(require("@babel/traverse"));
|
|
7
|
+
const LOCALHOST_PATTERN = /https?:\/\/(localhost|127\.0\.0\.1|0\.0\.0\.0)(:\d+)?/;
|
|
8
|
+
const hardcodedLocalhostRule = {
|
|
9
|
+
id: 'ai-codegen/hardcoded-localhost',
|
|
10
|
+
name: 'Hardcoded Localhost',
|
|
11
|
+
description: 'Detects hardcoded localhost/127.0.0.1 URLs that should use environment variables',
|
|
12
|
+
severity: 'warning',
|
|
13
|
+
category: 'ai-codegen',
|
|
14
|
+
detect(context) {
|
|
15
|
+
const violations = [];
|
|
16
|
+
const { ast, filePath } = context;
|
|
17
|
+
(0, traverse_1.default)(ast, {
|
|
18
|
+
StringLiteral(path) {
|
|
19
|
+
if (LOCALHOST_PATTERN.test(path.node.value)) {
|
|
20
|
+
violations.push({
|
|
21
|
+
ruleId: 'ai-codegen/hardcoded-localhost',
|
|
22
|
+
severity: 'warning',
|
|
23
|
+
message: `Hardcoded localhost URL "${path.node.value.substring(0, 50)}". Use an environment variable for the base URL.`,
|
|
24
|
+
location: {
|
|
25
|
+
file: filePath,
|
|
26
|
+
line: path.node.loc?.start.line ?? 0,
|
|
27
|
+
column: path.node.loc?.start.column ?? 0,
|
|
28
|
+
},
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
TemplateLiteral(path) {
|
|
33
|
+
for (const quasi of path.node.quasis) {
|
|
34
|
+
if (LOCALHOST_PATTERN.test(quasi.value.raw)) {
|
|
35
|
+
violations.push({
|
|
36
|
+
ruleId: 'ai-codegen/hardcoded-localhost',
|
|
37
|
+
severity: 'warning',
|
|
38
|
+
message: 'Hardcoded localhost URL in template literal. Use an environment variable for the base URL.',
|
|
39
|
+
location: {
|
|
40
|
+
file: filePath,
|
|
41
|
+
line: quasi.loc?.start.line ?? 0,
|
|
42
|
+
column: quasi.loc?.start.column ?? 0,
|
|
43
|
+
},
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
return violations;
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
exports.default = hardcodedLocalhostRule;
|
|
53
|
+
//# sourceMappingURL=hardcoded-localhost.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hardcoded-localhost.js","sourceRoot":"","sources":["../src/hardcoded-localhost.ts"],"names":[],"mappings":";;;;;AAAA,+DAAuC;AAGvC,MAAM,iBAAiB,GACrB,uDAAuD,CAAC;AAE1D,MAAM,sBAAsB,GAAS;IACnC,EAAE,EAAE,gCAAgC;IACpC,IAAI,EAAE,qBAAqB;IAC3B,WAAW,EACT,kFAAkF;IACpF,QAAQ,EAAE,SAAS;IACnB,QAAQ,EAAE,YAAY;IAEtB,MAAM,CAAC,OAAoB;QACzB,MAAM,UAAU,GAAgB,EAAE,CAAC;QACnC,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC;QAElC,IAAA,kBAAQ,EAAC,GAAG,EAAE;YACZ,aAAa,CAAC,IAAI;gBAChB,IAAI,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;oBAC5C,UAAU,CAAC,IAAI,CAAC;wBACd,MAAM,EAAE,gCAAgC;wBACxC,QAAQ,EAAE,SAAS;wBACnB,OAAO,EAAE,4BAA4B,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,CAAC,kDAAkD;wBACvH,QAAQ,EAAE;4BACR,IAAI,EAAE,QAAQ;4BACd,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,IAAI,CAAC;4BACpC,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,MAAM,IAAI,CAAC;yBACzC;qBACF,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;YAED,eAAe,CAAC,IAAI;gBAClB,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;oBACrC,IAAI,iBAAiB,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;wBAC5C,UAAU,CAAC,IAAI,CAAC;4BACd,MAAM,EAAE,gCAAgC;4BACxC,QAAQ,EAAE,SAAS;4BACnB,OAAO,EACL,4FAA4F;4BAC9F,QAAQ,EAAE;gCACR,IAAI,EAAE,QAAQ;gCACd,IAAI,EAAE,KAAK,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,IAAI,CAAC;gCAChC,MAAM,EAAE,KAAK,CAAC,GAAG,EAAE,KAAK,CAAC,MAAM,IAAI,CAAC;6BACrC;yBACF,CAAC,CAAC;oBACL,CAAC;gBACH,CAAC;YACH,CAAC;SACF,CAAC,CAAC;QAEH,OAAO,UAAU,CAAC;IACpB,CAAC;CACF,CAAC;AAEF,kBAAe,sBAAsB,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { Rule } from '@guardrail-ai/core';
|
|
2
|
+
import hardcodedApiKeyRule from './hardcoded-api-key.js';
|
|
3
|
+
import sqlInjectionRule from './sql-injection.js';
|
|
4
|
+
import insecureCorsRule from './insecure-cors.js';
|
|
5
|
+
import envVarLeakRule from './env-var-leak.js';
|
|
6
|
+
import noRateLimitingRule from './no-rate-limiting.js';
|
|
7
|
+
import unsafeRegexRule from './unsafe-regex.js';
|
|
8
|
+
import noEvalRule from './no-eval.js';
|
|
9
|
+
import noSecretsInLogsRule from './no-secrets-in-logs.js';
|
|
10
|
+
import deadCodeRule from './dead-code.js';
|
|
11
|
+
import duplicateLogicRule from './duplicate-logic.js';
|
|
12
|
+
import inefficientLoopRule from './inefficient-loop.js';
|
|
13
|
+
import nPlusOneQueryRule from './n-plus-one-query.js';
|
|
14
|
+
import hallucinatedImportRule from './hallucinated-import.js';
|
|
15
|
+
import placeholderCodeRule from './placeholder-code.js';
|
|
16
|
+
import hardcodedLocalhostRule from './hardcoded-localhost.js';
|
|
17
|
+
import consoleLogSpamRule from './console-log-spam.js';
|
|
18
|
+
import overlyBroadCatchRule from './overly-broad-catch.js';
|
|
19
|
+
import unusedImportsRule from './unused-imports.js';
|
|
20
|
+
import anyTypeAbuseRule from './any-type-abuse.js';
|
|
21
|
+
import fetchWithoutErrorHandlingRule from './fetch-without-error-handling.js';
|
|
22
|
+
import promiseWithoutCatchRule from './promise-without-catch.js';
|
|
23
|
+
import magicNumbersRule from './magic-numbers.js';
|
|
24
|
+
export declare const builtinRules: Rule[];
|
|
25
|
+
export { hardcodedApiKeyRule, sqlInjectionRule, insecureCorsRule, envVarLeakRule, noRateLimitingRule, deadCodeRule, duplicateLogicRule, inefficientLoopRule, nPlusOneQueryRule, hallucinatedImportRule, placeholderCodeRule, hardcodedLocalhostRule, consoleLogSpamRule, overlyBroadCatchRule, unusedImportsRule, anyTypeAbuseRule, fetchWithoutErrorHandlingRule, promiseWithoutCatchRule, magicNumbersRule, unsafeRegexRule, noEvalRule, noSecretsInLogsRule, };
|
|
26
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAC;AAG/C,OAAO,mBAAmB,MAAM,wBAAwB,CAAC;AACzD,OAAO,gBAAgB,MAAM,oBAAoB,CAAC;AAClD,OAAO,gBAAgB,MAAM,oBAAoB,CAAC;AAClD,OAAO,cAAc,MAAM,mBAAmB,CAAC;AAC/C,OAAO,kBAAkB,MAAM,uBAAuB,CAAC;AACvD,OAAO,eAAe,MAAM,mBAAmB,CAAC;AAChD,OAAO,UAAU,MAAM,cAAc,CAAC;AACtC,OAAO,mBAAmB,MAAM,yBAAyB,CAAC;AAG1D,OAAO,YAAY,MAAM,gBAAgB,CAAC;AAC1C,OAAO,kBAAkB,MAAM,sBAAsB,CAAC;AAGtD,OAAO,mBAAmB,MAAM,uBAAuB,CAAC;AACxD,OAAO,iBAAiB,MAAM,uBAAuB,CAAC;AAGtD,OAAO,sBAAsB,MAAM,0BAA0B,CAAC;AAC9D,OAAO,mBAAmB,MAAM,uBAAuB,CAAC;AACxD,OAAO,sBAAsB,MAAM,0BAA0B,CAAC;AAC9D,OAAO,kBAAkB,MAAM,uBAAuB,CAAC;AACvD,OAAO,oBAAoB,MAAM,yBAAyB,CAAC;AAC3D,OAAO,iBAAiB,MAAM,qBAAqB,CAAC;AACpD,OAAO,gBAAgB,MAAM,qBAAqB,CAAC;AACnD,OAAO,6BAA6B,MAAM,mCAAmC,CAAC;AAC9E,OAAO,uBAAuB,MAAM,4BAA4B,CAAC;AACjE,OAAO,gBAAgB,MAAM,oBAAoB,CAAC;AAElD,eAAO,MAAM,YAAY,EAAE,IAAI,EA8B9B,CAAC;AAEF,OAAO,EACL,mBAAmB,EACnB,gBAAgB,EAChB,gBAAgB,EAChB,cAAc,EACd,kBAAkB,EAClB,YAAY,EACZ,kBAAkB,EAClB,mBAAmB,EACnB,iBAAiB,EACjB,sBAAsB,EACtB,mBAAmB,EACnB,sBAAsB,EACtB,kBAAkB,EAClB,oBAAoB,EACpB,iBAAiB,EACjB,gBAAgB,EAChB,6BAA6B,EAC7B,uBAAuB,EACvB,gBAAgB,EAChB,eAAe,EACf,UAAU,EACV,mBAAmB,GACpB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.noSecretsInLogsRule = exports.noEvalRule = exports.unsafeRegexRule = exports.magicNumbersRule = exports.promiseWithoutCatchRule = exports.fetchWithoutErrorHandlingRule = exports.anyTypeAbuseRule = exports.unusedImportsRule = exports.overlyBroadCatchRule = exports.consoleLogSpamRule = exports.hardcodedLocalhostRule = exports.placeholderCodeRule = exports.hallucinatedImportRule = exports.nPlusOneQueryRule = exports.inefficientLoopRule = exports.duplicateLogicRule = exports.deadCodeRule = exports.noRateLimitingRule = exports.envVarLeakRule = exports.insecureCorsRule = exports.sqlInjectionRule = exports.hardcodedApiKeyRule = exports.builtinRules = void 0;
|
|
7
|
+
// Security
|
|
8
|
+
const hardcoded_api_key_js_1 = __importDefault(require("./hardcoded-api-key.js"));
|
|
9
|
+
exports.hardcodedApiKeyRule = hardcoded_api_key_js_1.default;
|
|
10
|
+
const sql_injection_js_1 = __importDefault(require("./sql-injection.js"));
|
|
11
|
+
exports.sqlInjectionRule = sql_injection_js_1.default;
|
|
12
|
+
const insecure_cors_js_1 = __importDefault(require("./insecure-cors.js"));
|
|
13
|
+
exports.insecureCorsRule = insecure_cors_js_1.default;
|
|
14
|
+
const env_var_leak_js_1 = __importDefault(require("./env-var-leak.js"));
|
|
15
|
+
exports.envVarLeakRule = env_var_leak_js_1.default;
|
|
16
|
+
const no_rate_limiting_js_1 = __importDefault(require("./no-rate-limiting.js"));
|
|
17
|
+
exports.noRateLimitingRule = no_rate_limiting_js_1.default;
|
|
18
|
+
const unsafe_regex_js_1 = __importDefault(require("./unsafe-regex.js"));
|
|
19
|
+
exports.unsafeRegexRule = unsafe_regex_js_1.default;
|
|
20
|
+
const no_eval_js_1 = __importDefault(require("./no-eval.js"));
|
|
21
|
+
exports.noEvalRule = no_eval_js_1.default;
|
|
22
|
+
const no_secrets_in_logs_js_1 = __importDefault(require("./no-secrets-in-logs.js"));
|
|
23
|
+
exports.noSecretsInLogsRule = no_secrets_in_logs_js_1.default;
|
|
24
|
+
// Quality
|
|
25
|
+
const dead_code_js_1 = __importDefault(require("./dead-code.js"));
|
|
26
|
+
exports.deadCodeRule = dead_code_js_1.default;
|
|
27
|
+
const duplicate_logic_js_1 = __importDefault(require("./duplicate-logic.js"));
|
|
28
|
+
exports.duplicateLogicRule = duplicate_logic_js_1.default;
|
|
29
|
+
// Performance
|
|
30
|
+
const inefficient_loop_js_1 = __importDefault(require("./inefficient-loop.js"));
|
|
31
|
+
exports.inefficientLoopRule = inefficient_loop_js_1.default;
|
|
32
|
+
const n_plus_one_query_js_1 = __importDefault(require("./n-plus-one-query.js"));
|
|
33
|
+
exports.nPlusOneQueryRule = n_plus_one_query_js_1.default;
|
|
34
|
+
// AI-Codegen
|
|
35
|
+
const hallucinated_import_js_1 = __importDefault(require("./hallucinated-import.js"));
|
|
36
|
+
exports.hallucinatedImportRule = hallucinated_import_js_1.default;
|
|
37
|
+
const placeholder_code_js_1 = __importDefault(require("./placeholder-code.js"));
|
|
38
|
+
exports.placeholderCodeRule = placeholder_code_js_1.default;
|
|
39
|
+
const hardcoded_localhost_js_1 = __importDefault(require("./hardcoded-localhost.js"));
|
|
40
|
+
exports.hardcodedLocalhostRule = hardcoded_localhost_js_1.default;
|
|
41
|
+
const console_log_spam_js_1 = __importDefault(require("./console-log-spam.js"));
|
|
42
|
+
exports.consoleLogSpamRule = console_log_spam_js_1.default;
|
|
43
|
+
const overly_broad_catch_js_1 = __importDefault(require("./overly-broad-catch.js"));
|
|
44
|
+
exports.overlyBroadCatchRule = overly_broad_catch_js_1.default;
|
|
45
|
+
const unused_imports_js_1 = __importDefault(require("./unused-imports.js"));
|
|
46
|
+
exports.unusedImportsRule = unused_imports_js_1.default;
|
|
47
|
+
const any_type_abuse_js_1 = __importDefault(require("./any-type-abuse.js"));
|
|
48
|
+
exports.anyTypeAbuseRule = any_type_abuse_js_1.default;
|
|
49
|
+
const fetch_without_error_handling_js_1 = __importDefault(require("./fetch-without-error-handling.js"));
|
|
50
|
+
exports.fetchWithoutErrorHandlingRule = fetch_without_error_handling_js_1.default;
|
|
51
|
+
const promise_without_catch_js_1 = __importDefault(require("./promise-without-catch.js"));
|
|
52
|
+
exports.promiseWithoutCatchRule = promise_without_catch_js_1.default;
|
|
53
|
+
const magic_numbers_js_1 = __importDefault(require("./magic-numbers.js"));
|
|
54
|
+
exports.magicNumbersRule = magic_numbers_js_1.default;
|
|
55
|
+
exports.builtinRules = [
|
|
56
|
+
// Security
|
|
57
|
+
hardcoded_api_key_js_1.default,
|
|
58
|
+
sql_injection_js_1.default,
|
|
59
|
+
insecure_cors_js_1.default,
|
|
60
|
+
env_var_leak_js_1.default,
|
|
61
|
+
no_rate_limiting_js_1.default,
|
|
62
|
+
unsafe_regex_js_1.default,
|
|
63
|
+
no_eval_js_1.default,
|
|
64
|
+
no_secrets_in_logs_js_1.default,
|
|
65
|
+
// Quality
|
|
66
|
+
dead_code_js_1.default,
|
|
67
|
+
duplicate_logic_js_1.default,
|
|
68
|
+
// Performance
|
|
69
|
+
inefficient_loop_js_1.default,
|
|
70
|
+
n_plus_one_query_js_1.default,
|
|
71
|
+
// AI-Codegen
|
|
72
|
+
hallucinated_import_js_1.default,
|
|
73
|
+
placeholder_code_js_1.default,
|
|
74
|
+
hardcoded_localhost_js_1.default,
|
|
75
|
+
console_log_spam_js_1.default,
|
|
76
|
+
overly_broad_catch_js_1.default,
|
|
77
|
+
unused_imports_js_1.default,
|
|
78
|
+
any_type_abuse_js_1.default,
|
|
79
|
+
fetch_without_error_handling_js_1.default,
|
|
80
|
+
promise_without_catch_js_1.default,
|
|
81
|
+
magic_numbers_js_1.default,
|
|
82
|
+
];
|
|
83
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;AAEA,WAAW;AACX,kFAAyD;AA8DvD,8BA9DK,8BAAmB,CA8DL;AA7DrB,0EAAkD;AA8DhD,2BA9DK,0BAAgB,CA8DL;AA7DlB,0EAAkD;AA8DhD,2BA9DK,0BAAgB,CA8DL;AA7DlB,wEAA+C;AA8D7C,yBA9DK,yBAAc,CA8DL;AA7DhB,gFAAuD;AA8DrD,6BA9DK,6BAAkB,CA8DL;AA7DpB,wEAAgD;AA4E9C,0BA5EK,yBAAe,CA4EL;AA3EjB,8DAAsC;AA4EpC,qBA5EK,oBAAU,CA4EL;AA3EZ,oFAA0D;AA4ExD,8BA5EK,+BAAmB,CA4EL;AA1ErB,UAAU;AACV,kEAA0C;AAyDxC,uBAzDK,sBAAY,CAyDL;AAxDd,8EAAsD;AAyDpD,6BAzDK,4BAAkB,CAyDL;AAvDpB,cAAc;AACd,gFAAwD;AAuDtD,8BAvDK,6BAAmB,CAuDL;AAtDrB,gFAAsD;AAuDpD,4BAvDK,6BAAiB,CAuDL;AArDnB,aAAa;AACb,sFAA8D;AAqD5D,iCArDK,gCAAsB,CAqDL;AApDxB,gFAAwD;AAqDtD,8BArDK,6BAAmB,CAqDL;AApDrB,sFAA8D;AAqD5D,iCArDK,gCAAsB,CAqDL;AApDxB,gFAAuD;AAqDrD,6BArDK,6BAAkB,CAqDL;AApDpB,oFAA2D;AAqDzD,+BArDK,+BAAoB,CAqDL;AApDtB,4EAAoD;AAqDlD,4BArDK,2BAAiB,CAqDL;AApDnB,4EAAmD;AAqDjD,2BArDK,2BAAgB,CAqDL;AApDlB,wGAA8E;AAqD5E,wCArDK,yCAA6B,CAqDL;AApD/B,0FAAiE;AAqD/D,kCArDK,kCAAuB,CAqDL;AApDzB,0EAAkD;AAqDhD,2BArDK,0BAAgB,CAqDL;AAnDL,QAAA,YAAY,GAAW;IAClC,WAAW;IACX,8BAAmB;IACnB,0BAAgB;IAChB,0BAAgB;IAChB,yBAAc;IACd,6BAAkB;IAClB,yBAAe;IACf,oBAAU;IACV,+BAAmB;IAEnB,UAAU;IACV,sBAAY;IACZ,4BAAkB;IAElB,cAAc;IACd,6BAAmB;IACnB,6BAAiB;IAEjB,aAAa;IACb,gCAAsB;IACtB,6BAAmB;IACnB,gCAAsB;IACtB,6BAAkB;IAClB,+BAAoB;IACpB,2BAAiB;IACjB,2BAAgB;IAChB,yCAA6B;IAC7B,kCAAuB;IACvB,0BAAgB;CACjB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inefficient-loop.d.ts","sourceRoot":"","sources":["../src/inefficient-loop.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAA0B,MAAM,oBAAoB,CAAC;AA8CvE,QAAA,MAAM,mBAAmB,EAAE,IAyE1B,CAAC;AAEF,eAAe,mBAAmB,CAAC"}
|