@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.
Files changed (122) hide show
  1. package/dist/__tests__/advanced-rules.test.d.ts +2 -0
  2. package/dist/__tests__/advanced-rules.test.d.ts.map +1 -0
  3. package/dist/__tests__/advanced-rules.test.js +59 -0
  4. package/dist/__tests__/advanced-rules.test.js.map +1 -0
  5. package/dist/__tests__/dead-code.test.d.ts +2 -0
  6. package/dist/__tests__/dead-code.test.d.ts.map +1 -0
  7. package/dist/__tests__/dead-code.test.js +66 -0
  8. package/dist/__tests__/dead-code.test.js.map +1 -0
  9. package/dist/__tests__/duplicate-logic.test.d.ts +2 -0
  10. package/dist/__tests__/duplicate-logic.test.d.ts.map +1 -0
  11. package/dist/__tests__/duplicate-logic.test.js +47 -0
  12. package/dist/__tests__/duplicate-logic.test.js.map +1 -0
  13. package/dist/__tests__/hardcoded-api-key.test.d.ts +2 -0
  14. package/dist/__tests__/hardcoded-api-key.test.d.ts.map +1 -0
  15. package/dist/__tests__/hardcoded-api-key.test.js +44 -0
  16. package/dist/__tests__/hardcoded-api-key.test.js.map +1 -0
  17. package/dist/__tests__/inefficient-loop.test.d.ts +2 -0
  18. package/dist/__tests__/inefficient-loop.test.d.ts.map +1 -0
  19. package/dist/__tests__/inefficient-loop.test.js +49 -0
  20. package/dist/__tests__/inefficient-loop.test.js.map +1 -0
  21. package/dist/__tests__/new-rules.test.d.ts +2 -0
  22. package/dist/__tests__/new-rules.test.d.ts.map +1 -0
  23. package/dist/__tests__/new-rules.test.js +193 -0
  24. package/dist/__tests__/new-rules.test.js.map +1 -0
  25. package/dist/__tests__/sql-injection.test.d.ts +2 -0
  26. package/dist/__tests__/sql-injection.test.d.ts.map +1 -0
  27. package/dist/__tests__/sql-injection.test.js +40 -0
  28. package/dist/__tests__/sql-injection.test.js.map +1 -0
  29. package/dist/any-type-abuse.d.ts +4 -0
  30. package/dist/any-type-abuse.d.ts.map +1 -0
  31. package/dist/any-type-abuse.js +37 -0
  32. package/dist/any-type-abuse.js.map +1 -0
  33. package/dist/console-log-spam.d.ts +4 -0
  34. package/dist/console-log-spam.d.ts.map +1 -0
  35. package/dist/console-log-spam.js +60 -0
  36. package/dist/console-log-spam.js.map +1 -0
  37. package/dist/data/hallucinated-packages.json +212 -0
  38. package/dist/dead-code.d.ts +10 -0
  39. package/dist/dead-code.d.ts.map +1 -0
  40. package/dist/dead-code.js +152 -0
  41. package/dist/dead-code.js.map +1 -0
  42. package/dist/duplicate-logic.d.ts +4 -0
  43. package/dist/duplicate-logic.d.ts.map +1 -0
  44. package/dist/duplicate-logic.js +90 -0
  45. package/dist/duplicate-logic.js.map +1 -0
  46. package/dist/env-var-leak.d.ts +4 -0
  47. package/dist/env-var-leak.d.ts.map +1 -0
  48. package/dist/env-var-leak.js +86 -0
  49. package/dist/env-var-leak.js.map +1 -0
  50. package/dist/fetch-without-error-handling.d.ts +4 -0
  51. package/dist/fetch-without-error-handling.d.ts.map +1 -0
  52. package/dist/fetch-without-error-handling.js +62 -0
  53. package/dist/fetch-without-error-handling.js.map +1 -0
  54. package/dist/hallucinated-import.d.ts +4 -0
  55. package/dist/hallucinated-import.d.ts.map +1 -0
  56. package/dist/hallucinated-import.js +75 -0
  57. package/dist/hallucinated-import.js.map +1 -0
  58. package/dist/hardcoded-api-key.d.ts +4 -0
  59. package/dist/hardcoded-api-key.d.ts.map +1 -0
  60. package/dist/hardcoded-api-key.js +129 -0
  61. package/dist/hardcoded-api-key.js.map +1 -0
  62. package/dist/hardcoded-localhost.d.ts +4 -0
  63. package/dist/hardcoded-localhost.d.ts.map +1 -0
  64. package/dist/hardcoded-localhost.js +53 -0
  65. package/dist/hardcoded-localhost.js.map +1 -0
  66. package/dist/index.d.ts +26 -0
  67. package/dist/index.d.ts.map +1 -0
  68. package/dist/index.js +83 -0
  69. package/dist/index.js.map +1 -0
  70. package/dist/inefficient-loop.d.ts +4 -0
  71. package/dist/inefficient-loop.d.ts.map +1 -0
  72. package/dist/inefficient-loop.js +104 -0
  73. package/dist/inefficient-loop.js.map +1 -0
  74. package/dist/insecure-cors.d.ts +4 -0
  75. package/dist/insecure-cors.d.ts.map +1 -0
  76. package/dist/insecure-cors.js +89 -0
  77. package/dist/insecure-cors.js.map +1 -0
  78. package/dist/magic-numbers.d.ts +4 -0
  79. package/dist/magic-numbers.d.ts.map +1 -0
  80. package/dist/magic-numbers.js +53 -0
  81. package/dist/magic-numbers.js.map +1 -0
  82. package/dist/n-plus-one-query.d.ts +4 -0
  83. package/dist/n-plus-one-query.d.ts.map +1 -0
  84. package/dist/n-plus-one-query.js +95 -0
  85. package/dist/n-plus-one-query.js.map +1 -0
  86. package/dist/no-eval.d.ts +4 -0
  87. package/dist/no-eval.d.ts.map +1 -0
  88. package/dist/no-eval.js +53 -0
  89. package/dist/no-eval.js.map +1 -0
  90. package/dist/no-rate-limiting.d.ts +4 -0
  91. package/dist/no-rate-limiting.d.ts.map +1 -0
  92. package/dist/no-rate-limiting.js +72 -0
  93. package/dist/no-rate-limiting.js.map +1 -0
  94. package/dist/no-secrets-in-logs.d.ts +4 -0
  95. package/dist/no-secrets-in-logs.d.ts.map +1 -0
  96. package/dist/no-secrets-in-logs.js +71 -0
  97. package/dist/no-secrets-in-logs.js.map +1 -0
  98. package/dist/overly-broad-catch.d.ts +4 -0
  99. package/dist/overly-broad-catch.d.ts.map +1 -0
  100. package/dist/overly-broad-catch.js +48 -0
  101. package/dist/overly-broad-catch.js.map +1 -0
  102. package/dist/placeholder-code.d.ts +4 -0
  103. package/dist/placeholder-code.d.ts.map +1 -0
  104. package/dist/placeholder-code.js +58 -0
  105. package/dist/placeholder-code.js.map +1 -0
  106. package/dist/promise-without-catch.d.ts +4 -0
  107. package/dist/promise-without-catch.d.ts.map +1 -0
  108. package/dist/promise-without-catch.js +72 -0
  109. package/dist/promise-without-catch.js.map +1 -0
  110. package/dist/sql-injection.d.ts +4 -0
  111. package/dist/sql-injection.d.ts.map +1 -0
  112. package/dist/sql-injection.js +108 -0
  113. package/dist/sql-injection.js.map +1 -0
  114. package/dist/unsafe-regex.d.ts +4 -0
  115. package/dist/unsafe-regex.d.ts.map +1 -0
  116. package/dist/unsafe-regex.js +75 -0
  117. package/dist/unsafe-regex.js.map +1 -0
  118. package/dist/unused-imports.d.ts +4 -0
  119. package/dist/unused-imports.d.ts.map +1 -0
  120. package/dist/unused-imports.js +56 -0
  121. package/dist/unused-imports.js.map +1 -0
  122. 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,4 @@
1
+ import type { Rule } from '@guardrail-ai/core';
2
+ declare const fetchWithoutErrorHandlingRule: Rule;
3
+ export default fetchWithoutErrorHandlingRule;
4
+ //# sourceMappingURL=fetch-without-error-handling.d.ts.map
@@ -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,4 @@
1
+ import type { Rule } from '@guardrail-ai/core';
2
+ declare const hallucinatedImportRule: Rule;
3
+ export default hallucinatedImportRule;
4
+ //# sourceMappingURL=hallucinated-import.d.ts.map
@@ -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,4 @@
1
+ import type { Rule } from '@guardrail-ai/core';
2
+ declare const hardcodedApiKeyRule: Rule;
3
+ export default hardcodedApiKeyRule;
4
+ //# sourceMappingURL=hardcoded-api-key.d.ts.map
@@ -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,4 @@
1
+ import type { Rule } from '@guardrail-ai/core';
2
+ declare const hardcodedLocalhostRule: Rule;
3
+ export default hardcodedLocalhostRule;
4
+ //# sourceMappingURL=hardcoded-localhost.d.ts.map
@@ -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"}
@@ -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,4 @@
1
+ import type { Rule } from '@guardrail-ai/core';
2
+ declare const inefficientLoopRule: Rule;
3
+ export default inefficientLoopRule;
4
+ //# sourceMappingURL=inefficient-loop.d.ts.map
@@ -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"}