@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,4 @@
1
+ import type { Rule } from '@guardrail-ai/core';
2
+ declare const overlyBroadCatchRule: Rule;
3
+ export default overlyBroadCatchRule;
4
+ //# sourceMappingURL=overly-broad-catch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"overly-broad-catch.d.ts","sourceRoot":"","sources":["../src/overly-broad-catch.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAA0B,MAAM,oBAAoB,CAAC;AAEvE,QAAA,MAAM,oBAAoB,EAAE,IA+C3B,CAAC;AAEF,eAAe,oBAAoB,CAAC"}
@@ -0,0 +1,48 @@
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 overlyBroadCatchRule = {
8
+ id: 'ai-codegen/overly-broad-catch',
9
+ name: 'Overly Broad Catch',
10
+ description: 'Detects catch blocks that only log errors without proper handling or rethrowing',
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
+ CatchClause(path) {
18
+ const body = path.node.body.body;
19
+ // Empty catch — already handled by dead-code rule
20
+ if (body.length === 0)
21
+ return;
22
+ // Only a single console.log/console.error statement
23
+ if (body.length === 1) {
24
+ const stmt = body[0];
25
+ if (stmt.type === 'ExpressionStatement' &&
26
+ stmt.expression.type === 'CallExpression' &&
27
+ stmt.expression.callee.type === 'MemberExpression' &&
28
+ stmt.expression.callee.object.type === 'Identifier' &&
29
+ stmt.expression.callee.object.name === 'console') {
30
+ violations.push({
31
+ ruleId: 'ai-codegen/overly-broad-catch',
32
+ severity: 'warning',
33
+ message: 'Catch block only logs the error without proper handling. Consider rethrowing, returning an error state, or implementing recovery logic.',
34
+ location: {
35
+ file: filePath,
36
+ line: path.node.loc?.start.line ?? 0,
37
+ column: path.node.loc?.start.column ?? 0,
38
+ },
39
+ });
40
+ }
41
+ }
42
+ },
43
+ });
44
+ return violations;
45
+ },
46
+ };
47
+ exports.default = overlyBroadCatchRule;
48
+ //# sourceMappingURL=overly-broad-catch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"overly-broad-catch.js","sourceRoot":"","sources":["../src/overly-broad-catch.ts"],"names":[],"mappings":";;;;;AAAA,+DAAuC;AAGvC,MAAM,oBAAoB,GAAS;IACjC,EAAE,EAAE,+BAA+B;IACnC,IAAI,EAAE,oBAAoB;IAC1B,WAAW,EACT,iFAAiF;IACnF,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,WAAW,CAAC,IAAI;gBACd,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;gBAEjC,kDAAkD;gBAClD,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;oBAAE,OAAO;gBAE9B,oDAAoD;gBACpD,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;oBACtB,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;oBACrB,IACE,IAAI,CAAC,IAAI,KAAK,qBAAqB;wBACnC,IAAI,CAAC,UAAU,CAAC,IAAI,KAAK,gBAAgB;wBACzC,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,KAAK,kBAAkB;wBAClD,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,KAAK,YAAY;wBACnD,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,KAAK,SAAS,EAChD,CAAC;wBACD,UAAU,CAAC,IAAI,CAAC;4BACd,MAAM,EAAE,+BAA+B;4BACvC,QAAQ,EAAE,SAAS;4BACnB,OAAO,EACL,yIAAyI;4BAC3I,QAAQ,EAAE;gCACR,IAAI,EAAE,QAAQ;gCACd,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,IAAI,CAAC;gCACpC,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,MAAM,IAAI,CAAC;6BACzC;yBACF,CAAC,CAAC;oBACL,CAAC;gBACH,CAAC;YACH,CAAC;SACF,CAAC,CAAC;QAEH,OAAO,UAAU,CAAC;IACpB,CAAC;CACF,CAAC;AAEF,kBAAe,oBAAoB,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { Rule } from '@guardrail-ai/core';
2
+ declare const placeholderCodeRule: Rule;
3
+ export default placeholderCodeRule;
4
+ //# sourceMappingURL=placeholder-code.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"placeholder-code.d.ts","sourceRoot":"","sources":["../src/placeholder-code.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAA0B,MAAM,oBAAoB,CAAC;AAUvE,QAAA,MAAM,mBAAmB,EAAE,IAmD1B,CAAC;AAEF,eAAe,mBAAmB,CAAC"}
@@ -0,0 +1,58 @@
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 COMMENT_PATTERNS = /\b(TODO|FIXME|HACK|PLACEHOLDER|XXX|TEMP|implement\s*(this|later|here)|add\s*(logic|code|implementation)\s*here|replace\s*(this|with)|your[_\s-]*(code|logic|implementation)\s*here)\b/i;
8
+ const STRING_PATTERNS = /^(placeholder|example\.com|your[_-]api[_-]key[_-]here|your[_-].*[_-]here|test123|lorem\s*ipsum|foo|bar|baz|changeme|replace[_-]me)$/i;
9
+ const URL_PATTERNS = /^https?:\/\/example\.(com|org|net)/;
10
+ const placeholderCodeRule = {
11
+ id: 'ai-codegen/placeholder-code',
12
+ name: 'Placeholder Code',
13
+ description: 'Detects TODO/FIXME comments, placeholder strings, and example.com URLs left by AI generators',
14
+ severity: 'warning',
15
+ category: 'ai-codegen',
16
+ detect(context) {
17
+ const violations = [];
18
+ const { ast, filePath } = context;
19
+ // Check comments
20
+ if (ast.comments) {
21
+ for (const comment of ast.comments) {
22
+ if (COMMENT_PATTERNS.test(comment.value)) {
23
+ violations.push({
24
+ ruleId: 'ai-codegen/placeholder-code',
25
+ severity: 'warning',
26
+ message: `Placeholder comment found: "${comment.value.trim().substring(0, 60)}..."`,
27
+ location: {
28
+ file: filePath,
29
+ line: comment.loc?.start.line ?? 0,
30
+ column: comment.loc?.start.column ?? 0,
31
+ },
32
+ });
33
+ }
34
+ }
35
+ }
36
+ // Check string literals
37
+ (0, traverse_1.default)(ast, {
38
+ StringLiteral(path) {
39
+ const val = path.node.value;
40
+ if (STRING_PATTERNS.test(val) || URL_PATTERNS.test(val)) {
41
+ violations.push({
42
+ ruleId: 'ai-codegen/placeholder-code',
43
+ severity: 'warning',
44
+ message: `Placeholder string "${val.substring(0, 40)}" — likely needs to be replaced with real values.`,
45
+ location: {
46
+ file: filePath,
47
+ line: path.node.loc?.start.line ?? 0,
48
+ column: path.node.loc?.start.column ?? 0,
49
+ },
50
+ });
51
+ }
52
+ },
53
+ });
54
+ return violations;
55
+ },
56
+ };
57
+ exports.default = placeholderCodeRule;
58
+ //# sourceMappingURL=placeholder-code.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"placeholder-code.js","sourceRoot":"","sources":["../src/placeholder-code.ts"],"names":[],"mappings":";;;;;AAAA,+DAAuC;AAGvC,MAAM,gBAAgB,GACpB,wLAAwL,CAAC;AAE3L,MAAM,eAAe,GACnB,sIAAsI,CAAC;AAEzI,MAAM,YAAY,GAAG,oCAAoC,CAAC;AAE1D,MAAM,mBAAmB,GAAS;IAChC,EAAE,EAAE,6BAA6B;IACjC,IAAI,EAAE,kBAAkB;IACxB,WAAW,EACT,8FAA8F;IAChG,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,iBAAiB;QACjB,IAAI,GAAG,CAAC,QAAQ,EAAE,CAAC;YACjB,KAAK,MAAM,OAAO,IAAI,GAAG,CAAC,QAAQ,EAAE,CAAC;gBACnC,IAAI,gBAAgB,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;oBACzC,UAAU,CAAC,IAAI,CAAC;wBACd,MAAM,EAAE,6BAA6B;wBACrC,QAAQ,EAAE,SAAS;wBACnB,OAAO,EAAE,+BAA+B,OAAO,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM;wBACnF,QAAQ,EAAE;4BACR,IAAI,EAAE,QAAQ;4BACd,IAAI,EAAE,OAAO,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,IAAI,CAAC;4BAClC,MAAM,EAAE,OAAO,CAAC,GAAG,EAAE,KAAK,CAAC,MAAM,IAAI,CAAC;yBACvC;qBACF,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;QACH,CAAC;QAED,wBAAwB;QACxB,IAAA,kBAAQ,EAAC,GAAG,EAAE;YACZ,aAAa,CAAC,IAAI;gBAChB,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC;gBAC5B,IAAI,eAAe,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;oBACxD,UAAU,CAAC,IAAI,CAAC;wBACd,MAAM,EAAE,6BAA6B;wBACrC,QAAQ,EAAE,SAAS;wBACnB,OAAO,EAAE,uBAAuB,GAAG,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,CAAC,mDAAmD;wBACvG,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,mBAAmB,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { Rule } from '@guardrail-ai/core';
2
+ declare const promiseWithoutCatchRule: Rule;
3
+ export default promiseWithoutCatchRule;
4
+ //# sourceMappingURL=promise-without-catch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"promise-without-catch.d.ts","sourceRoot":"","sources":["../src/promise-without-catch.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAA0B,MAAM,oBAAoB,CAAC;AAEvE,QAAA,MAAM,uBAAuB,EAAE,IA8E9B,CAAC;AAEF,eAAe,uBAAuB,CAAC"}
@@ -0,0 +1,72 @@
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 promiseWithoutCatchRule = {
8
+ id: 'ai-codegen/promise-without-catch',
9
+ name: 'Promise Without Catch',
10
+ description: 'Detects .then() chains without a .catch() handler',
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
+ // Look for .then() calls
20
+ if (callee.type !== 'MemberExpression' ||
21
+ callee.property.type !== 'Identifier' ||
22
+ callee.property.name !== 'then') {
23
+ return;
24
+ }
25
+ // Walk up the chain to see if there's a .catch() anywhere
26
+ let current = path.parentPath;
27
+ let hasCatch = false;
28
+ // Check if this .then() is itself chained with .catch()
29
+ while (current) {
30
+ if (current.isCallExpression() &&
31
+ current.node.callee.type === 'MemberExpression' &&
32
+ current.node.callee.property.type === 'Identifier' &&
33
+ current.node.callee.property.name === 'catch') {
34
+ hasCatch = true;
35
+ break;
36
+ }
37
+ // If the parent is a member expression accessing .then/.catch/.finally, keep walking
38
+ if (current.isMemberExpression() &&
39
+ current.parentPath?.isCallExpression()) {
40
+ current = current.parentPath;
41
+ continue;
42
+ }
43
+ break;
44
+ }
45
+ // Also check if the .then() is inside a try block
46
+ if (!hasCatch) {
47
+ for (const anc of path.getAncestry()) {
48
+ if (anc.isTryStatement()) {
49
+ hasCatch = true;
50
+ break;
51
+ }
52
+ }
53
+ }
54
+ if (!hasCatch) {
55
+ violations.push({
56
+ ruleId: 'ai-codegen/promise-without-catch',
57
+ severity: 'warning',
58
+ message: '.then() chain without .catch() handler. Add error handling to prevent unhandled rejections.',
59
+ location: {
60
+ file: filePath,
61
+ line: path.node.loc?.start.line ?? 0,
62
+ column: path.node.loc?.start.column ?? 0,
63
+ },
64
+ });
65
+ }
66
+ },
67
+ });
68
+ return violations;
69
+ },
70
+ };
71
+ exports.default = promiseWithoutCatchRule;
72
+ //# sourceMappingURL=promise-without-catch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"promise-without-catch.js","sourceRoot":"","sources":["../src/promise-without-catch.ts"],"names":[],"mappings":";;;;;AAAA,+DAAuC;AAGvC,MAAM,uBAAuB,GAAS;IACpC,EAAE,EAAE,kCAAkC;IACtC,IAAI,EAAE,uBAAuB;IAC7B,WAAW,EAAE,mDAAmD;IAChE,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,yBAAyB;gBACzB,IACE,MAAM,CAAC,IAAI,KAAK,kBAAkB;oBAClC,MAAM,CAAC,QAAQ,CAAC,IAAI,KAAK,YAAY;oBACrC,MAAM,CAAC,QAAQ,CAAC,IAAI,KAAK,MAAM,EAC/B,CAAC;oBACD,OAAO;gBACT,CAAC;gBAED,0DAA0D;gBAC1D,IAAI,OAAO,GAAG,IAAI,CAAC,UAAU,CAAC;gBAC9B,IAAI,QAAQ,GAAG,KAAK,CAAC;gBAErB,wDAAwD;gBACxD,OAAO,OAAO,EAAE,CAAC;oBACf,IACE,OAAO,CAAC,gBAAgB,EAAE;wBAC1B,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,KAAK,kBAAkB;wBAC/C,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,KAAK,YAAY;wBAClD,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,KAAK,OAAO,EAC7C,CAAC;wBACD,QAAQ,GAAG,IAAI,CAAC;wBAChB,MAAM;oBACR,CAAC;oBACD,qFAAqF;oBACrF,IACE,OAAO,CAAC,kBAAkB,EAAE;wBAC5B,OAAO,CAAC,UAAU,EAAE,gBAAgB,EAAE,EACtC,CAAC;wBACD,OAAO,GAAG,OAAO,CAAC,UAAU,CAAC;wBAC7B,SAAS;oBACX,CAAC;oBACD,MAAM;gBACR,CAAC;gBAED,kDAAkD;gBAClD,IAAI,CAAC,QAAQ,EAAE,CAAC;oBACd,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC;wBACrC,IAAI,GAAG,CAAC,cAAc,EAAE,EAAE,CAAC;4BACzB,QAAQ,GAAG,IAAI,CAAC;4BAChB,MAAM;wBACR,CAAC;oBACH,CAAC;gBACH,CAAC;gBAED,IAAI,CAAC,QAAQ,EAAE,CAAC;oBACd,UAAU,CAAC,IAAI,CAAC;wBACd,MAAM,EAAE,kCAAkC;wBAC1C,QAAQ,EAAE,SAAS;wBACnB,OAAO,EACL,6FAA6F;wBAC/F,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,uBAAuB,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { Rule } from '@guardrail-ai/core';
2
+ declare const sqlInjectionRule: Rule;
3
+ export default sqlInjectionRule;
4
+ //# sourceMappingURL=sql-injection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sql-injection.d.ts","sourceRoot":"","sources":["../src/sql-injection.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,IAAI,EAA0B,MAAM,oBAAoB,CAAC;AAwFvE,QAAA,MAAM,gBAAgB,EAAE,IA0CvB,CAAC;AAEF,eAAe,gBAAgB,CAAC"}
@@ -0,0 +1,108 @@
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 SQL injection vulnerabilities from string concatenation
9
+ * or template literals used in database query calls.
10
+ *
11
+ * Catches patterns like:
12
+ * db.query("SELECT * FROM users WHERE id = " + userId)
13
+ * db.query(`SELECT * FROM users WHERE id = ${userId}`)
14
+ * connection.execute("DELETE FROM " + table)
15
+ */
16
+ const SQL_KEYWORDS = /\b(SELECT|INSERT|UPDATE|DELETE|DROP|CREATE|ALTER|EXEC|EXECUTE|UNION|WHERE|FROM|INTO|VALUES|SET|TABLE|DATABASE)\b/i;
17
+ const QUERY_METHOD_NAMES = new Set([
18
+ 'query',
19
+ 'execute',
20
+ 'exec',
21
+ 'raw',
22
+ 'rawQuery',
23
+ 'prepare',
24
+ 'run',
25
+ ]);
26
+ function containsSqlKeyword(value) {
27
+ return SQL_KEYWORDS.test(value);
28
+ }
29
+ function isQueryCall(path) {
30
+ const callee = path.node.callee;
31
+ // db.query(...)
32
+ if (callee.type === 'MemberExpression' &&
33
+ callee.property.type === 'Identifier' &&
34
+ QUERY_METHOD_NAMES.has(callee.property.name)) {
35
+ return true;
36
+ }
37
+ // query(...)
38
+ if (callee.type === 'Identifier' &&
39
+ QUERY_METHOD_NAMES.has(callee.name)) {
40
+ return true;
41
+ }
42
+ return false;
43
+ }
44
+ function hasDynamicParts(node) {
45
+ // Template literal with expressions
46
+ if (node.type === 'TemplateLiteral' &&
47
+ node.expressions.length > 0) {
48
+ return true;
49
+ }
50
+ // String concatenation with non-literal
51
+ if (node.type === 'BinaryExpression' &&
52
+ node.operator === '+') {
53
+ return true;
54
+ }
55
+ return false;
56
+ }
57
+ function extractStaticSqlParts(node) {
58
+ if (node.type === 'StringLiteral') {
59
+ return node.value;
60
+ }
61
+ if (node.type === 'TemplateLiteral') {
62
+ return node.quasis.map((q) => q.value.raw).join('');
63
+ }
64
+ if (node.type === 'BinaryExpression' && node.operator === '+') {
65
+ return (extractStaticSqlParts(node.left) +
66
+ extractStaticSqlParts(node.right));
67
+ }
68
+ return '';
69
+ }
70
+ const sqlInjectionRule = {
71
+ id: 'security/sql-injection',
72
+ name: 'SQL Injection',
73
+ description: 'Detects potential SQL injection from string concatenation or template literals in database queries',
74
+ severity: 'critical',
75
+ category: 'security',
76
+ detect(context) {
77
+ const violations = [];
78
+ const { ast, filePath } = context;
79
+ (0, traverse_1.default)(ast, {
80
+ CallExpression(path) {
81
+ if (!isQueryCall(path))
82
+ return;
83
+ const args = path.node.arguments;
84
+ if (args.length === 0)
85
+ return;
86
+ const firstArg = args[0];
87
+ if (firstArg.type === 'SpreadElement')
88
+ return;
89
+ const staticSql = extractStaticSqlParts(firstArg);
90
+ if (containsSqlKeyword(staticSql) && hasDynamicParts(firstArg)) {
91
+ violations.push({
92
+ ruleId: 'security/sql-injection',
93
+ severity: 'critical',
94
+ message: 'Potential SQL injection: dynamic values in SQL query string. Use parameterized queries instead.',
95
+ location: {
96
+ file: filePath,
97
+ line: firstArg.loc?.start.line ?? 0,
98
+ column: firstArg.loc?.start.column ?? 0,
99
+ },
100
+ });
101
+ }
102
+ },
103
+ });
104
+ return violations;
105
+ },
106
+ };
107
+ exports.default = sqlInjectionRule;
108
+ //# sourceMappingURL=sql-injection.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sql-injection.js","sourceRoot":"","sources":["../src/sql-injection.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { Rule } from '@guardrail-ai/core';
2
+ declare const unsafeRegexRule: Rule;
3
+ export default unsafeRegexRule;
4
+ //# sourceMappingURL=unsafe-regex.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"unsafe-regex.d.ts","sourceRoot":"","sources":["../src/unsafe-regex.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAA0B,MAAM,oBAAoB,CAAC;AAgBvE,QAAA,MAAM,eAAe,EAAE,IA4DtB,CAAC;AAEF,eAAe,eAAe,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
+ /**
8
+ * Detects regex patterns vulnerable to ReDoS (Regular Expression Denial of Service).
9
+ * Flags patterns with nested quantifiers like (a+)+ or (a|b|c)* that cause exponential backtracking.
10
+ */
11
+ const REDOS_PATTERNS = [
12
+ /\(.+\+\)\+/, // (x+)+
13
+ /\(.+\*\)\*/, // (x*)*
14
+ /\(.+\+\)\*/, // (x+)*
15
+ /\(.+\*\)\+/, // (x*)+
16
+ /\(.+\{.+\}\)\+/, // (x{n})+
17
+ /\(.+\{.+\}\)\*/, // (x{n})*
18
+ ];
19
+ const unsafeRegexRule = {
20
+ id: 'security/unsafe-regex',
21
+ name: 'Unsafe Regex',
22
+ description: 'Detects regex patterns vulnerable to ReDoS (catastrophic backtracking)',
23
+ severity: 'high',
24
+ category: 'security',
25
+ detect(context) {
26
+ const violations = [];
27
+ const { ast, filePath } = context;
28
+ (0, traverse_1.default)(ast, {
29
+ RegExpLiteral(path) {
30
+ const pattern = path.node.pattern;
31
+ for (const redos of REDOS_PATTERNS) {
32
+ if (redos.test(pattern)) {
33
+ violations.push({
34
+ ruleId: 'security/unsafe-regex',
35
+ severity: 'high',
36
+ message: `Regex "/${pattern}/" is vulnerable to ReDoS. Simplify the pattern or add input length limits.`,
37
+ location: {
38
+ file: filePath,
39
+ line: path.node.loc?.start.line ?? 0,
40
+ column: path.node.loc?.start.column ?? 0,
41
+ },
42
+ });
43
+ break;
44
+ }
45
+ }
46
+ },
47
+ NewExpression(path) {
48
+ if (path.node.callee.type === 'Identifier' &&
49
+ path.node.callee.name === 'RegExp' &&
50
+ path.node.arguments.length > 0 &&
51
+ path.node.arguments[0].type === 'StringLiteral') {
52
+ const pattern = path.node.arguments[0].value;
53
+ for (const redos of REDOS_PATTERNS) {
54
+ if (redos.test(pattern)) {
55
+ violations.push({
56
+ ruleId: 'security/unsafe-regex',
57
+ severity: 'high',
58
+ message: `Regex pattern "${pattern}" is vulnerable to ReDoS. Simplify the pattern or add input length limits.`,
59
+ location: {
60
+ file: filePath,
61
+ line: path.node.loc?.start.line ?? 0,
62
+ column: path.node.loc?.start.column ?? 0,
63
+ },
64
+ });
65
+ break;
66
+ }
67
+ }
68
+ }
69
+ },
70
+ });
71
+ return violations;
72
+ },
73
+ };
74
+ exports.default = unsafeRegexRule;
75
+ //# sourceMappingURL=unsafe-regex.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"unsafe-regex.js","sourceRoot":"","sources":["../src/unsafe-regex.ts"],"names":[],"mappings":";;;;;AAAA,+DAAuC;AAGvC;;;GAGG;AAEH,MAAM,cAAc,GAAG;IACrB,YAAY,EAAM,QAAQ;IAC1B,YAAY,EAAM,QAAQ;IAC1B,YAAY,EAAM,QAAQ;IAC1B,YAAY,EAAM,QAAQ;IAC1B,gBAAgB,EAAE,UAAU;IAC5B,gBAAgB,EAAE,UAAU;CAC7B,CAAC;AAEF,MAAM,eAAe,GAAS;IAC5B,EAAE,EAAE,uBAAuB;IAC3B,IAAI,EAAE,cAAc;IACpB,WAAW,EAAE,wEAAwE;IACrF,QAAQ,EAAE,MAAM;IAChB,QAAQ,EAAE,UAAU;IAEpB,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,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC;gBAClC,KAAK,MAAM,KAAK,IAAI,cAAc,EAAE,CAAC;oBACnC,IAAI,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;wBACxB,UAAU,CAAC,IAAI,CAAC;4BACd,MAAM,EAAE,uBAAuB;4BAC/B,QAAQ,EAAE,MAAM;4BAChB,OAAO,EAAE,WAAW,OAAO,6EAA6E;4BACxG,QAAQ,EAAE;gCACR,IAAI,EAAE,QAAQ;gCACd,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,IAAI,CAAC;gCACpC,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,MAAM,IAAI,CAAC;6BACzC;yBACF,CAAC,CAAC;wBACH,MAAM;oBACR,CAAC;gBACH,CAAC;YACH,CAAC;YAED,aAAa,CAAC,IAAI;gBAChB,IACE,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,KAAK,YAAY;oBACtC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,KAAK,QAAQ;oBAClC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC;oBAC9B,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,eAAe,EAC/C,CAAC;oBACD,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;oBAC7C,KAAK,MAAM,KAAK,IAAI,cAAc,EAAE,CAAC;wBACnC,IAAI,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;4BACxB,UAAU,CAAC,IAAI,CAAC;gCACd,MAAM,EAAE,uBAAuB;gCAC/B,QAAQ,EAAE,MAAM;gCAChB,OAAO,EAAE,kBAAkB,OAAO,4EAA4E;gCAC9G,QAAQ,EAAE;oCACR,IAAI,EAAE,QAAQ;oCACd,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,IAAI,CAAC;oCACpC,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,MAAM,IAAI,CAAC;iCACzC;6BACF,CAAC,CAAC;4BACH,MAAM;wBACR,CAAC;oBACH,CAAC;gBACH,CAAC;YACH,CAAC;SACF,CAAC,CAAC;QAEH,OAAO,UAAU,CAAC;IACpB,CAAC;CACF,CAAC;AAEF,kBAAe,eAAe,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { Rule } from '@guardrail-ai/core';
2
+ declare const unusedImportsRule: Rule;
3
+ export default unusedImportsRule;
4
+ //# sourceMappingURL=unused-imports.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"unused-imports.d.ts","sourceRoot":"","sources":["../src/unused-imports.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAA0B,MAAM,oBAAoB,CAAC;AAEvE,QAAA,MAAM,iBAAiB,EAAE,IAmDxB,CAAC;AAEF,eAAe,iBAAiB,CAAC"}
@@ -0,0 +1,56 @@
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 unusedImportsRule = {
8
+ id: 'ai-codegen/unused-imports',
9
+ name: 'Unused Imports',
10
+ description: 'Detects imported identifiers that are never referenced in the file',
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
+ ImportDeclaration(path) {
18
+ for (const specifier of path.node.specifiers) {
19
+ const localName = specifier.local.name;
20
+ const binding = path.scope.getBinding(localName);
21
+ if (binding && binding.references === 0) {
22
+ violations.push({
23
+ ruleId: 'ai-codegen/unused-imports',
24
+ severity: 'warning',
25
+ message: `"${localName}" is imported but never used.`,
26
+ location: {
27
+ file: filePath,
28
+ line: specifier.loc?.start.line ?? 0,
29
+ column: specifier.loc?.start.column ?? 0,
30
+ },
31
+ fix: path.node.specifiers.length === 1
32
+ ? {
33
+ description: `Remove unused import of "${localName}"`,
34
+ range: {
35
+ start: {
36
+ line: path.node.loc?.start.line ?? 0,
37
+ column: path.node.loc?.start.column ?? 0,
38
+ },
39
+ end: {
40
+ line: path.node.loc?.end.line ?? 0,
41
+ column: path.node.loc?.end.column ?? 0,
42
+ },
43
+ },
44
+ replacement: '',
45
+ }
46
+ : undefined,
47
+ });
48
+ }
49
+ }
50
+ },
51
+ });
52
+ return violations;
53
+ },
54
+ };
55
+ exports.default = unusedImportsRule;
56
+ //# sourceMappingURL=unused-imports.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"unused-imports.js","sourceRoot":"","sources":["../src/unused-imports.ts"],"names":[],"mappings":";;;;;AAAA,+DAAuC;AAGvC,MAAM,iBAAiB,GAAS;IAC9B,EAAE,EAAE,2BAA2B;IAC/B,IAAI,EAAE,gBAAgB;IACtB,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,iBAAiB,CAAC,IAAI;gBACpB,KAAK,MAAM,SAAS,IAAI,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC;oBAC7C,MAAM,SAAS,GAAG,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC;oBACvC,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;oBAEjD,IAAI,OAAO,IAAI,OAAO,CAAC,UAAU,KAAK,CAAC,EAAE,CAAC;wBACxC,UAAU,CAAC,IAAI,CAAC;4BACd,MAAM,EAAE,2BAA2B;4BACnC,QAAQ,EAAE,SAAS;4BACnB,OAAO,EAAE,IAAI,SAAS,+BAA+B;4BACrD,QAAQ,EAAE;gCACR,IAAI,EAAE,QAAQ;gCACd,IAAI,EAAE,SAAS,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,IAAI,CAAC;gCACpC,MAAM,EAAE,SAAS,CAAC,GAAG,EAAE,KAAK,CAAC,MAAM,IAAI,CAAC;6BACzC;4BACD,GAAG,EAAE,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,KAAK,CAAC;gCACpC,CAAC,CAAC;oCACE,WAAW,EAAE,4BAA4B,SAAS,GAAG;oCACrD,KAAK,EAAE;wCACL,KAAK,EAAE;4CACL,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,IAAI,CAAC;4CACpC,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,MAAM,IAAI,CAAC;yCACzC;wCACD,GAAG,EAAE;4CACH,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,IAAI,CAAC;4CAClC,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,MAAM,IAAI,CAAC;yCACvC;qCACF;oCACD,WAAW,EAAE,EAAE;iCAChB;gCACH,CAAC,CAAC,SAAS;yBACd,CAAC,CAAC;oBACL,CAAC;gBACH,CAAC;YACH,CAAC;SACF,CAAC,CAAC;QAEH,OAAO,UAAU,CAAC;IACpB,CAAC;CACF,CAAC;AAEF,kBAAe,iBAAiB,CAAC"}
package/package.json ADDED
@@ -0,0 +1,32 @@
1
+ {
2
+ "name": "@guardrail-ai/rules",
3
+ "version": "0.1.0",
4
+ "description": "Built-in detection rules for Guardrail (19 rules across security, performance, quality, and AI-codegen)",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "files": ["dist", "README.md"],
8
+ "publishConfig": {
9
+ "access": "public"
10
+ },
11
+ "repository": {
12
+ "type": "git",
13
+ "url": "https://github.com/Manavarya09/Guardrail.git",
14
+ "directory": "packages/rules"
15
+ },
16
+ "homepage": "https://github.com/Manavarya09/Guardrail",
17
+ "bugs": "https://github.com/Manavarya09/Guardrail/issues",
18
+ "keywords": ["guardrail", "security-rules", "ai-codegen", "static-analysis"],
19
+ "scripts": {
20
+ "build": "tsc -p tsconfig.json",
21
+ "prepublishOnly": "npm run build"
22
+ },
23
+ "dependencies": {
24
+ "@guardrail-ai/core": "^0.1.0",
25
+ "@babel/traverse": "^7.23.6",
26
+ "@babel/types": "^7.23.6"
27
+ },
28
+ "devDependencies": {
29
+ "@types/babel__traverse": "^7.20.4"
30
+ },
31
+ "license": "MIT"
32
+ }