camouf 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 (167) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +346 -0
  3. package/dist/cli/commands/analyze.d.ts +8 -0
  4. package/dist/cli/commands/analyze.d.ts.map +1 -0
  5. package/dist/cli/commands/analyze.js +81 -0
  6. package/dist/cli/commands/analyze.js.map +1 -0
  7. package/dist/cli/commands/init.d.ts +9 -0
  8. package/dist/cli/commands/init.d.ts.map +1 -0
  9. package/dist/cli/commands/init.js +104 -0
  10. package/dist/cli/commands/init.js.map +1 -0
  11. package/dist/cli/commands/report.d.ts +8 -0
  12. package/dist/cli/commands/report.d.ts.map +1 -0
  13. package/dist/cli/commands/report.js +63 -0
  14. package/dist/cli/commands/report.js.map +1 -0
  15. package/dist/cli/commands/validate.d.ts +9 -0
  16. package/dist/cli/commands/validate.d.ts.map +1 -0
  17. package/dist/cli/commands/validate.js +87 -0
  18. package/dist/cli/commands/validate.js.map +1 -0
  19. package/dist/cli/commands/watch.d.ts +9 -0
  20. package/dist/cli/commands/watch.d.ts.map +1 -0
  21. package/dist/cli/commands/watch.js +93 -0
  22. package/dist/cli/commands/watch.js.map +1 -0
  23. package/dist/cli/index.d.ts +9 -0
  24. package/dist/cli/index.d.ts.map +1 -0
  25. package/dist/cli/index.js +48 -0
  26. package/dist/cli/index.js.map +1 -0
  27. package/dist/cli/version.d.ts +16 -0
  28. package/dist/cli/version.d.ts.map +1 -0
  29. package/dist/cli/version.js +16 -0
  30. package/dist/cli/version.js.map +1 -0
  31. package/dist/core/analyzer/architecture-visualizer.d.ts +25 -0
  32. package/dist/core/analyzer/architecture-visualizer.d.ts.map +1 -0
  33. package/dist/core/analyzer/architecture-visualizer.js +333 -0
  34. package/dist/core/analyzer/architecture-visualizer.js.map +1 -0
  35. package/dist/core/analyzer/dependency-analyzer.d.ts +49 -0
  36. package/dist/core/analyzer/dependency-analyzer.d.ts.map +1 -0
  37. package/dist/core/analyzer/dependency-analyzer.js +242 -0
  38. package/dist/core/analyzer/dependency-analyzer.js.map +1 -0
  39. package/dist/core/config/config-schema.d.ts +280 -0
  40. package/dist/core/config/config-schema.d.ts.map +1 -0
  41. package/dist/core/config/config-schema.js +199 -0
  42. package/dist/core/config/config-schema.js.map +1 -0
  43. package/dist/core/config/configuration-manager.d.ts +82 -0
  44. package/dist/core/config/configuration-manager.d.ts.map +1 -0
  45. package/dist/core/config/configuration-manager.js +306 -0
  46. package/dist/core/config/configuration-manager.js.map +1 -0
  47. package/dist/core/logger.d.ts +27 -0
  48. package/dist/core/logger.d.ts.map +1 -0
  49. package/dist/core/logger.js +86 -0
  50. package/dist/core/logger.js.map +1 -0
  51. package/dist/core/parsers/go-parser.d.ts +16 -0
  52. package/dist/core/parsers/go-parser.d.ts.map +1 -0
  53. package/dist/core/parsers/go-parser.js +117 -0
  54. package/dist/core/parsers/go-parser.js.map +1 -0
  55. package/dist/core/parsers/java-parser.d.ts +22 -0
  56. package/dist/core/parsers/java-parser.d.ts.map +1 -0
  57. package/dist/core/parsers/java-parser.js +114 -0
  58. package/dist/core/parsers/java-parser.js.map +1 -0
  59. package/dist/core/parsers/javascript-parser.d.ts +14 -0
  60. package/dist/core/parsers/javascript-parser.d.ts.map +1 -0
  61. package/dist/core/parsers/javascript-parser.js +19 -0
  62. package/dist/core/parsers/javascript-parser.js.map +1 -0
  63. package/dist/core/parsers/parser-registry.d.ts +45 -0
  64. package/dist/core/parsers/parser-registry.d.ts.map +1 -0
  65. package/dist/core/parsers/parser-registry.js +121 -0
  66. package/dist/core/parsers/parser-registry.js.map +1 -0
  67. package/dist/core/parsers/parser.interface.d.ts +49 -0
  68. package/dist/core/parsers/parser.interface.d.ts.map +1 -0
  69. package/dist/core/parsers/parser.interface.js +7 -0
  70. package/dist/core/parsers/parser.interface.js.map +1 -0
  71. package/dist/core/parsers/python-parser.d.ts +22 -0
  72. package/dist/core/parsers/python-parser.d.ts.map +1 -0
  73. package/dist/core/parsers/python-parser.js +136 -0
  74. package/dist/core/parsers/python-parser.js.map +1 -0
  75. package/dist/core/parsers/rust-parser.d.ts +16 -0
  76. package/dist/core/parsers/rust-parser.d.ts.map +1 -0
  77. package/dist/core/parsers/rust-parser.js +176 -0
  78. package/dist/core/parsers/rust-parser.js.map +1 -0
  79. package/dist/core/parsers/typescript-parser.d.ts +29 -0
  80. package/dist/core/parsers/typescript-parser.d.ts.map +1 -0
  81. package/dist/core/parsers/typescript-parser.js +251 -0
  82. package/dist/core/parsers/typescript-parser.js.map +1 -0
  83. package/dist/core/reporter/report-generator.d.ts +31 -0
  84. package/dist/core/reporter/report-generator.d.ts.map +1 -0
  85. package/dist/core/reporter/report-generator.js +417 -0
  86. package/dist/core/reporter/report-generator.js.map +1 -0
  87. package/dist/core/reporter/violation-reporter.d.ts +62 -0
  88. package/dist/core/reporter/violation-reporter.d.ts.map +1 -0
  89. package/dist/core/reporter/violation-reporter.js +265 -0
  90. package/dist/core/reporter/violation-reporter.js.map +1 -0
  91. package/dist/core/rules/builtin/api-versioning.rule.d.ts +28 -0
  92. package/dist/core/rules/builtin/api-versioning.rule.d.ts.map +1 -0
  93. package/dist/core/rules/builtin/api-versioning.rule.js +103 -0
  94. package/dist/core/rules/builtin/api-versioning.rule.js.map +1 -0
  95. package/dist/core/rules/builtin/circular-dependencies.rule.d.ts +26 -0
  96. package/dist/core/rules/builtin/circular-dependencies.rule.d.ts.map +1 -0
  97. package/dist/core/rules/builtin/circular-dependencies.rule.js +99 -0
  98. package/dist/core/rules/builtin/circular-dependencies.rule.js.map +1 -0
  99. package/dist/core/rules/builtin/data-flow-integrity.rule.d.ts +27 -0
  100. package/dist/core/rules/builtin/data-flow-integrity.rule.d.ts.map +1 -0
  101. package/dist/core/rules/builtin/data-flow-integrity.rule.js +111 -0
  102. package/dist/core/rules/builtin/data-flow-integrity.rule.js.map +1 -0
  103. package/dist/core/rules/builtin/ddd-boundaries.rule.d.ts +31 -0
  104. package/dist/core/rules/builtin/ddd-boundaries.rule.d.ts.map +1 -0
  105. package/dist/core/rules/builtin/ddd-boundaries.rule.js +141 -0
  106. package/dist/core/rules/builtin/ddd-boundaries.rule.js.map +1 -0
  107. package/dist/core/rules/builtin/distributed-transactions.rule.d.ts +27 -0
  108. package/dist/core/rules/builtin/distributed-transactions.rule.d.ts.map +1 -0
  109. package/dist/core/rules/builtin/distributed-transactions.rule.js +134 -0
  110. package/dist/core/rules/builtin/distributed-transactions.rule.js.map +1 -0
  111. package/dist/core/rules/builtin/index.d.ts +16 -0
  112. package/dist/core/rules/builtin/index.d.ts.map +1 -0
  113. package/dist/core/rules/builtin/index.js +16 -0
  114. package/dist/core/rules/builtin/index.js.map +1 -0
  115. package/dist/core/rules/builtin/layer-dependencies.rule.d.ts +30 -0
  116. package/dist/core/rules/builtin/layer-dependencies.rule.d.ts.map +1 -0
  117. package/dist/core/rules/builtin/layer-dependencies.rule.js +102 -0
  118. package/dist/core/rules/builtin/layer-dependencies.rule.js.map +1 -0
  119. package/dist/core/rules/builtin/performance-antipatterns.rule.d.ts +29 -0
  120. package/dist/core/rules/builtin/performance-antipatterns.rule.d.ts.map +1 -0
  121. package/dist/core/rules/builtin/performance-antipatterns.rule.js +148 -0
  122. package/dist/core/rules/builtin/performance-antipatterns.rule.js.map +1 -0
  123. package/dist/core/rules/builtin/resilience-patterns.rule.d.ts +29 -0
  124. package/dist/core/rules/builtin/resilience-patterns.rule.d.ts.map +1 -0
  125. package/dist/core/rules/builtin/resilience-patterns.rule.js +123 -0
  126. package/dist/core/rules/builtin/resilience-patterns.rule.js.map +1 -0
  127. package/dist/core/rules/builtin/security-context.rule.d.ts +32 -0
  128. package/dist/core/rules/builtin/security-context.rule.d.ts.map +1 -0
  129. package/dist/core/rules/builtin/security-context.rule.js +145 -0
  130. package/dist/core/rules/builtin/security-context.rule.js.map +1 -0
  131. package/dist/core/rules/builtin/type-safety.rule.d.ts +32 -0
  132. package/dist/core/rules/builtin/type-safety.rule.d.ts.map +1 -0
  133. package/dist/core/rules/builtin/type-safety.rule.js +175 -0
  134. package/dist/core/rules/builtin/type-safety.rule.js.map +1 -0
  135. package/dist/core/rules/rule-engine.d.ts +72 -0
  136. package/dist/core/rules/rule-engine.d.ts.map +1 -0
  137. package/dist/core/rules/rule-engine.js +225 -0
  138. package/dist/core/rules/rule-engine.js.map +1 -0
  139. package/dist/core/rules/rule.interface.d.ts +169 -0
  140. package/dist/core/rules/rule.interface.d.ts.map +1 -0
  141. package/dist/core/rules/rule.interface.js +38 -0
  142. package/dist/core/rules/rule.interface.js.map +1 -0
  143. package/dist/core/scanner/project-detector.d.ts +51 -0
  144. package/dist/core/scanner/project-detector.d.ts.map +1 -0
  145. package/dist/core/scanner/project-detector.js +310 -0
  146. package/dist/core/scanner/project-detector.js.map +1 -0
  147. package/dist/core/scanner/project-scanner.d.ts +101 -0
  148. package/dist/core/scanner/project-scanner.d.ts.map +1 -0
  149. package/dist/core/scanner/project-scanner.js +321 -0
  150. package/dist/core/scanner/project-scanner.js.map +1 -0
  151. package/dist/core/watcher/file-watcher.d.ts +48 -0
  152. package/dist/core/watcher/file-watcher.d.ts.map +1 -0
  153. package/dist/core/watcher/file-watcher.js +124 -0
  154. package/dist/core/watcher/file-watcher.js.map +1 -0
  155. package/dist/types/config.types.d.ts +163 -0
  156. package/dist/types/config.types.d.ts.map +1 -0
  157. package/dist/types/config.types.js +36 -0
  158. package/dist/types/config.types.js.map +1 -0
  159. package/dist/types/core.types.d.ts +247 -0
  160. package/dist/types/core.types.d.ts.map +1 -0
  161. package/dist/types/core.types.js +7 -0
  162. package/dist/types/core.types.js.map +1 -0
  163. package/dist/types/index.d.ts +7 -0
  164. package/dist/types/index.d.ts.map +1 -0
  165. package/dist/types/index.js +7 -0
  166. package/dist/types/index.js.map +1 -0
  167. package/package.json +90 -0
@@ -0,0 +1,102 @@
1
+ /**
2
+ * Layer Dependencies Rule
3
+ *
4
+ * Validates architectural layer dependencies (e.g., presentation -> business -> data).
5
+ */
6
+ export class LayerDependenciesRule {
7
+ id = 'layer-dependencies';
8
+ name = 'Layer Dependencies';
9
+ description = 'Validates architectural layer dependencies';
10
+ severity = 'error';
11
+ tags = ['architecture', 'layers', 'dependencies'];
12
+ config = {
13
+ enabled: true,
14
+ severity: 'error',
15
+ strictMode: true,
16
+ layers: [
17
+ {
18
+ name: 'presentation',
19
+ patterns: ['controller', 'handler', 'view', 'component', 'page'],
20
+ allowedDependencies: ['application', 'domain'],
21
+ },
22
+ {
23
+ name: 'application',
24
+ patterns: ['service', 'usecase', 'application'],
25
+ allowedDependencies: ['domain', 'infrastructure'],
26
+ },
27
+ {
28
+ name: 'domain',
29
+ patterns: ['entity', 'domain', 'model', 'aggregate', 'value-object'],
30
+ allowedDependencies: [],
31
+ },
32
+ {
33
+ name: 'infrastructure',
34
+ patterns: ['repository', 'adapter', 'infrastructure', 'persistence'],
35
+ allowedDependencies: ['domain'],
36
+ },
37
+ ],
38
+ };
39
+ configure(options) {
40
+ this.config = { ...this.config, ...options };
41
+ }
42
+ async check(context) {
43
+ const violations = [];
44
+ for (const nodeId of context.graph.nodes()) {
45
+ const node = context.getNodeData(nodeId);
46
+ if (!node)
47
+ continue;
48
+ const filePath = node.data.relativePath;
49
+ const sourceLayer = this.detectLayer(filePath);
50
+ if (!sourceLayer)
51
+ continue;
52
+ const successors = context.graph.successors(nodeId);
53
+ if (!successors)
54
+ continue;
55
+ for (const successor of successors) {
56
+ const targetNode = context.getNodeData(successor);
57
+ if (!targetNode)
58
+ continue;
59
+ const targetPath = targetNode.data.relativePath;
60
+ const targetLayer = this.detectLayer(targetPath);
61
+ if (!targetLayer)
62
+ continue;
63
+ if (sourceLayer.name === targetLayer.name)
64
+ continue;
65
+ if (!this.isDependencyAllowed(sourceLayer, targetLayer.name)) {
66
+ violations.push(this.createViolation(filePath, `Invalid layer dependency: ${sourceLayer.name} -> ${targetLayer.name}`, 1, `${sourceLayer.name} layer can only depend on: ${sourceLayer.allowedDependencies.join(', ') || 'none'}`));
67
+ }
68
+ }
69
+ }
70
+ return { violations };
71
+ }
72
+ detectLayer(filePath) {
73
+ const normalizedPath = filePath.toLowerCase().replace(/\\/g, '/');
74
+ for (const layer of this.config.layers || []) {
75
+ for (const pattern of layer.patterns) {
76
+ if (normalizedPath.includes(pattern)) {
77
+ return layer;
78
+ }
79
+ }
80
+ }
81
+ return null;
82
+ }
83
+ isDependencyAllowed(sourceLayer, targetLayerName) {
84
+ if (!this.config.strictMode) {
85
+ return true;
86
+ }
87
+ return sourceLayer.allowedDependencies.includes(targetLayerName);
88
+ }
89
+ createViolation(file, message, line, suggestion) {
90
+ return {
91
+ id: `${this.id}-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
92
+ ruleId: this.id,
93
+ ruleName: this.name,
94
+ severity: 'error',
95
+ message,
96
+ file,
97
+ line,
98
+ suggestion,
99
+ };
100
+ }
101
+ }
102
+ //# sourceMappingURL=layer-dependencies.rule.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"layer-dependencies.rule.js","sourceRoot":"","sources":["../../../../src/core/rules/builtin/layer-dependencies.rule.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAgBH,MAAM,OAAO,qBAAqB;IACvB,EAAE,GAAG,oBAAoB,CAAC;IAC1B,IAAI,GAAG,oBAAoB,CAAC;IAC5B,WAAW,GAAG,4CAA4C,CAAC;IAC3D,QAAQ,GAAG,OAAgB,CAAC;IAC5B,IAAI,GAAG,CAAC,cAAc,EAAE,QAAQ,EAAE,cAAc,CAAC,CAAC;IAEnD,MAAM,GAA4B;QACxC,OAAO,EAAE,IAAI;QACb,QAAQ,EAAE,OAAO;QACjB,UAAU,EAAE,IAAI;QAChB,MAAM,EAAE;YACN;gBACE,IAAI,EAAE,cAAc;gBACpB,QAAQ,EAAE,CAAC,YAAY,EAAE,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,CAAC;gBAChE,mBAAmB,EAAE,CAAC,aAAa,EAAE,QAAQ,CAAC;aAC/C;YACD;gBACE,IAAI,EAAE,aAAa;gBACnB,QAAQ,EAAE,CAAC,SAAS,EAAE,SAAS,EAAE,aAAa,CAAC;gBAC/C,mBAAmB,EAAE,CAAC,QAAQ,EAAE,gBAAgB,CAAC;aAClD;YACD;gBACE,IAAI,EAAE,QAAQ;gBACd,QAAQ,EAAE,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,WAAW,EAAE,cAAc,CAAC;gBACpE,mBAAmB,EAAE,EAAE;aACxB;YACD;gBACE,IAAI,EAAE,gBAAgB;gBACtB,QAAQ,EAAE,CAAC,YAAY,EAAE,SAAS,EAAE,gBAAgB,EAAE,aAAa,CAAC;gBACpE,mBAAmB,EAAE,CAAC,QAAQ,CAAC;aAChC;SACF;KACF,CAAC;IAEF,SAAS,CAAC,OAAyC;QACjD,IAAI,CAAC,MAAM,GAAG,EAAE,GAAG,IAAI,CAAC,MAAM,EAAE,GAAG,OAAO,EAAE,CAAC;IAC/C,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,OAAoB;QAC9B,MAAM,UAAU,GAAgB,EAAE,CAAC;QAEnC,KAAK,MAAM,MAAM,IAAI,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,EAAE,CAAC;YAC3C,MAAM,IAAI,GAAG,OAAO,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;YACzC,IAAI,CAAC,IAAI;gBAAE,SAAS;YAEpB,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC;YACxC,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC;YAC/C,IAAI,CAAC,WAAW;gBAAE,SAAS;YAE3B,MAAM,UAAU,GAAG,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;YACpD,IAAI,CAAC,UAAU;gBAAE,SAAS;YAE1B,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;gBACnC,MAAM,UAAU,GAAG,OAAO,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC;gBAClD,IAAI,CAAC,UAAU;oBAAE,SAAS;gBAE1B,MAAM,UAAU,GAAG,UAAU,CAAC,IAAI,CAAC,YAAY,CAAC;gBAChD,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC;gBACjD,IAAI,CAAC,WAAW;oBAAE,SAAS;gBAE3B,IAAI,WAAW,CAAC,IAAI,KAAK,WAAW,CAAC,IAAI;oBAAE,SAAS;gBAEpD,IAAI,CAAC,IAAI,CAAC,mBAAmB,CAAC,WAAW,EAAE,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC;oBAC7D,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,eAAe,CAClC,QAAQ,EACR,6BAA6B,WAAW,CAAC,IAAI,OAAO,WAAW,CAAC,IAAI,EAAE,EACtE,CAAC,EACD,GAAG,WAAW,CAAC,IAAI,8BAA8B,WAAW,CAAC,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,MAAM,EAAE,CACxG,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;QACH,CAAC;QAED,OAAO,EAAE,UAAU,EAAE,CAAC;IACxB,CAAC;IAEO,WAAW,CAAC,QAAgB;QAClC,MAAM,cAAc,GAAG,QAAQ,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;QAElE,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,IAAI,EAAE,EAAE,CAAC;YAC7C,KAAK,MAAM,OAAO,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;gBACrC,IAAI,cAAc,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;oBACrC,OAAO,KAAK,CAAC;gBACf,CAAC;YACH,CAAC;QACH,CAAC;QAED,OAAO,IAAI,CAAC;IACd,CAAC;IAEO,mBAAmB,CAAC,WAAwB,EAAE,eAAuB;QAC3E,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC;YAC5B,OAAO,IAAI,CAAC;QACd,CAAC;QACD,OAAO,WAAW,CAAC,mBAAmB,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAC;IACnE,CAAC;IAEO,eAAe,CAAC,IAAY,EAAE,OAAe,EAAE,IAAY,EAAE,UAAmB;QACtF,OAAO;YACL,EAAE,EAAE,GAAG,IAAI,CAAC,EAAE,IAAI,IAAI,CAAC,GAAG,EAAE,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE;YACzE,MAAM,EAAE,IAAI,CAAC,EAAE;YACf,QAAQ,EAAE,IAAI,CAAC,IAAI;YACnB,QAAQ,EAAE,OAAO;YACjB,OAAO;YACP,IAAI;YACJ,IAAI;YACJ,UAAU;SACX,CAAC;IACJ,CAAC;CACF"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Performance Anti-patterns Rule
3
+ *
4
+ * Detects common performance anti-patterns in code.
5
+ */
6
+ import { IRule, RuleContext, RuleConfig, RuleResult } from '../rule.interface.js';
7
+ interface PerformanceConfig extends RuleConfig {
8
+ checkN1Queries?: boolean;
9
+ checkUnboundedLoops?: boolean;
10
+ checkMemoryLeaks?: boolean;
11
+ maxLoopDepth?: number;
12
+ }
13
+ export declare class PerformanceAntipatternsRule implements IRule {
14
+ readonly id = "performance-antipatterns";
15
+ readonly name = "Performance Anti-patterns";
16
+ readonly description = "Detects common performance anti-patterns in code";
17
+ readonly severity: "warning";
18
+ readonly tags: string[];
19
+ private config;
20
+ configure(options: Partial<PerformanceConfig>): void;
21
+ check(context: RuleContext): Promise<RuleResult>;
22
+ private checkN1QueryPattern;
23
+ private checkUnboundedLoops;
24
+ private checkMemoryLeakPatterns;
25
+ private checkSyncOperations;
26
+ private createViolation;
27
+ }
28
+ export {};
29
+ //# sourceMappingURL=performance-antipatterns.rule.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"performance-antipatterns.rule.d.ts","sourceRoot":"","sources":["../../../../src/core/rules/builtin/performance-antipatterns.rule.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAGlF,UAAU,iBAAkB,SAAQ,UAAU;IAC5C,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,qBAAa,2BAA4B,YAAW,KAAK;IACvD,QAAQ,CAAC,EAAE,8BAA8B;IACzC,QAAQ,CAAC,IAAI,+BAA+B;IAC5C,QAAQ,CAAC,WAAW,sDAAsD;IAC1E,QAAQ,CAAC,QAAQ,EAAG,SAAS,CAAU;IACvC,QAAQ,CAAC,IAAI,WAAqD;IAElE,OAAO,CAAC,MAAM,CAOZ;IAEF,SAAS,CAAC,OAAO,EAAE,OAAO,CAAC,iBAAiB,CAAC,GAAG,IAAI;IAI9C,KAAK,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC;IA0BtD,OAAO,CAAC,mBAAmB;IAmC3B,OAAO,CAAC,mBAAmB;IAoC3B,OAAO,CAAC,uBAAuB;IA+C/B,OAAO,CAAC,mBAAmB;IAuB3B,OAAO,CAAC,eAAe;CAYxB"}
@@ -0,0 +1,148 @@
1
+ /**
2
+ * Performance Anti-patterns Rule
3
+ *
4
+ * Detects common performance anti-patterns in code.
5
+ */
6
+ export class PerformanceAntipatternsRule {
7
+ id = 'performance-antipatterns';
8
+ name = 'Performance Anti-patterns';
9
+ description = 'Detects common performance anti-patterns in code';
10
+ severity = 'warning';
11
+ tags = ['performance', 'optimization', 'best-practices'];
12
+ config = {
13
+ enabled: true,
14
+ severity: 'warning',
15
+ checkN1Queries: true,
16
+ checkUnboundedLoops: true,
17
+ checkMemoryLeaks: true,
18
+ maxLoopDepth: 3,
19
+ };
20
+ configure(options) {
21
+ this.config = { ...this.config, ...options };
22
+ }
23
+ async check(context) {
24
+ const violations = [];
25
+ for (const nodeId of context.graph.nodes()) {
26
+ const node = context.getNodeData(nodeId);
27
+ if (!node)
28
+ continue;
29
+ const filePath = node.data.relativePath;
30
+ const content = context.fileContents?.get(filePath);
31
+ if (!content)
32
+ continue;
33
+ if (this.config.checkN1Queries) {
34
+ this.checkN1QueryPattern(filePath, content, violations);
35
+ }
36
+ if (this.config.checkUnboundedLoops) {
37
+ this.checkUnboundedLoops(filePath, content, violations);
38
+ }
39
+ if (this.config.checkMemoryLeaks) {
40
+ this.checkMemoryLeakPatterns(filePath, content, violations);
41
+ }
42
+ this.checkSyncOperations(filePath, content, violations);
43
+ }
44
+ return { violations };
45
+ }
46
+ checkN1QueryPattern(filePath, content, violations) {
47
+ const lines = content.split('\n');
48
+ let inLoop = false;
49
+ let loopStartLine = 0;
50
+ for (let i = 0; i < lines.length; i++) {
51
+ const line = lines[i];
52
+ // Detect loop start
53
+ if (/\b(for|while|forEach|map|reduce|filter)\s*[\(\[]/.test(line)) {
54
+ inLoop = true;
55
+ loopStartLine = i + 1;
56
+ }
57
+ // Detect query/fetch inside loop
58
+ if (inLoop) {
59
+ if (/\.find\(|\.findOne\(|\.query\(|\.execute\(|await\s+fetch\(|axios\.\w+\(/.test(line)) {
60
+ violations.push(this.createViolation(filePath, 'Potential N+1 query pattern detected', i + 1, 'Consider using batch queries, eager loading, or data loaders'));
61
+ }
62
+ // Detect loop end (simplified)
63
+ const openBraces = (line.match(/{/g) || []).length;
64
+ const closeBraces = (line.match(/}/g) || []).length;
65
+ if (closeBraces > openBraces) {
66
+ inLoop = false;
67
+ }
68
+ }
69
+ }
70
+ }
71
+ checkUnboundedLoops(filePath, content, violations) {
72
+ const lines = content.split('\n');
73
+ let currentDepth = 0;
74
+ const maxDepth = this.config.maxLoopDepth || 3;
75
+ for (let i = 0; i < lines.length; i++) {
76
+ const line = lines[i];
77
+ if (/\b(for|while|do)\s*[\(\{]/.test(line)) {
78
+ currentDepth++;
79
+ if (currentDepth > maxDepth) {
80
+ violations.push(this.createViolation(filePath, `Deep nested loops detected (depth: ${currentDepth})`, i + 1, 'Consider refactoring to reduce loop nesting or use different algorithms'));
81
+ }
82
+ }
83
+ // Check for while(true) or infinite loops
84
+ if (/while\s*\(\s*true\s*\)|for\s*\(\s*;\s*;\s*\)/.test(line)) {
85
+ violations.push(this.createViolation(filePath, 'Potentially infinite loop detected', i + 1, 'Ensure proper exit conditions exist'));
86
+ }
87
+ if (line.includes('}')) {
88
+ currentDepth = Math.max(0, currentDepth - 1);
89
+ }
90
+ }
91
+ }
92
+ checkMemoryLeakPatterns(filePath, content, violations) {
93
+ const lines = content.split('\n');
94
+ for (let i = 0; i < lines.length; i++) {
95
+ const line = lines[i];
96
+ // Check for event listeners without cleanup
97
+ if (/addEventListener\s*\(|\.on\s*\(/.test(line)) {
98
+ // Look for corresponding removeEventListener in the file
99
+ if (!content.includes('removeEventListener') && !content.includes('.off(')) {
100
+ violations.push(this.createViolation(filePath, 'Event listener without apparent cleanup', i + 1, 'Ensure event listeners are removed in cleanup/unmount'));
101
+ }
102
+ }
103
+ // Check for setInterval without clearInterval
104
+ if (/setInterval\s*\(/.test(line)) {
105
+ if (!content.includes('clearInterval')) {
106
+ violations.push(this.createViolation(filePath, 'setInterval without clearInterval', i + 1, 'Store interval ID and clear it during cleanup'));
107
+ }
108
+ }
109
+ // Check for large array accumulation in loops
110
+ if (/\.push\s*\(/.test(line) && /while|for/.test(content.substring(Math.max(0, content.indexOf(line) - 200), content.indexOf(line)))) {
111
+ // Check if there's no size limit
112
+ if (!/\.length\s*[<>]|\.slice\(|\.splice\(/.test(content)) {
113
+ violations.push(this.createViolation(filePath, 'Array accumulation in loop without apparent size limit', i + 1, 'Consider adding size limits or using streaming'));
114
+ break;
115
+ }
116
+ }
117
+ }
118
+ }
119
+ checkSyncOperations(filePath, content, violations) {
120
+ const lines = content.split('\n');
121
+ const syncPatterns = [
122
+ { pattern: /readFileSync\s*\(/, name: 'readFileSync' },
123
+ { pattern: /writeFileSync\s*\(/, name: 'writeFileSync' },
124
+ { pattern: /execSync\s*\(/, name: 'execSync' },
125
+ { pattern: /spawnSync\s*\(/, name: 'spawnSync' },
126
+ ];
127
+ for (let i = 0; i < lines.length; i++) {
128
+ for (const { pattern, name } of syncPatterns) {
129
+ if (pattern.test(lines[i])) {
130
+ violations.push(this.createViolation(filePath, `Synchronous operation '${name}' may block event loop`, i + 1, `Consider using async version or worker threads`));
131
+ }
132
+ }
133
+ }
134
+ }
135
+ createViolation(file, message, line, suggestion) {
136
+ return {
137
+ id: `${this.id}-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
138
+ ruleId: this.id,
139
+ ruleName: this.name,
140
+ severity: 'warning',
141
+ message,
142
+ file,
143
+ line,
144
+ suggestion,
145
+ };
146
+ }
147
+ }
148
+ //# sourceMappingURL=performance-antipatterns.rule.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"performance-antipatterns.rule.js","sourceRoot":"","sources":["../../../../src/core/rules/builtin/performance-antipatterns.rule.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Resilience Patterns Rule
3
+ *
4
+ * Validates resilience patterns like circuit breaker, retry, and timeout.
5
+ */
6
+ import { IRule, RuleContext, RuleConfig, RuleResult } from '../rule.interface.js';
7
+ interface ResilienceConfig extends RuleConfig {
8
+ requireCircuitBreaker?: boolean;
9
+ requireRetry?: boolean;
10
+ requireTimeout?: boolean;
11
+ externalCallPatterns?: string[];
12
+ }
13
+ export declare class ResiliencePatternsRule implements IRule {
14
+ readonly id = "resilience-patterns";
15
+ readonly name = "Resilience Patterns";
16
+ readonly description = "Validates resilience patterns like circuit breaker, retry, and timeout";
17
+ readonly severity: "warning";
18
+ readonly tags: string[];
19
+ private config;
20
+ configure(options: Partial<ResilienceConfig>): void;
21
+ check(context: RuleContext): Promise<RuleResult>;
22
+ private checkExternalCalls;
23
+ private checkResiliencePatterns;
24
+ private checkErrorHandling;
25
+ private hasTimeout;
26
+ private createViolation;
27
+ }
28
+ export {};
29
+ //# sourceMappingURL=resilience-patterns.rule.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resilience-patterns.rule.d.ts","sourceRoot":"","sources":["../../../../src/core/rules/builtin/resilience-patterns.rule.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAIlF,UAAU,gBAAiB,SAAQ,UAAU;IAC3C,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,oBAAoB,CAAC,EAAE,MAAM,EAAE,CAAC;CACjC;AAED,qBAAa,sBAAuB,YAAW,KAAK;IAClD,QAAQ,CAAC,EAAE,yBAAyB;IACpC,QAAQ,CAAC,IAAI,yBAAyB;IACtC,QAAQ,CAAC,WAAW,4EAA4E;IAChG,QAAQ,CAAC,QAAQ,EAAG,SAAS,CAAU;IACvC,QAAQ,CAAC,IAAI,WAA6C;IAE1D,OAAO,CAAC,MAAM,CAOZ;IAEF,SAAS,CAAC,OAAO,EAAE,OAAO,CAAC,gBAAgB,CAAC,GAAG,IAAI;IAI7C,KAAK,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC;IAmBtD,OAAO,CAAC,kBAAkB;IA4B1B,OAAO,CAAC,uBAAuB;IA0C/B,OAAO,CAAC,kBAAkB;IAgC1B,OAAO,CAAC,UAAU;IAYlB,OAAO,CAAC,eAAe;CAYxB"}
@@ -0,0 +1,123 @@
1
+ /**
2
+ * Resilience Patterns Rule
3
+ *
4
+ * Validates resilience patterns like circuit breaker, retry, and timeout.
5
+ */
6
+ import * as path from 'path';
7
+ export class ResiliencePatternsRule {
8
+ id = 'resilience-patterns';
9
+ name = 'Resilience Patterns';
10
+ description = 'Validates resilience patterns like circuit breaker, retry, and timeout';
11
+ severity = 'warning';
12
+ tags = ['resilience', 'reliability', 'patterns'];
13
+ config = {
14
+ enabled: true,
15
+ severity: 'warning',
16
+ requireCircuitBreaker: true,
17
+ requireRetry: true,
18
+ requireTimeout: true,
19
+ externalCallPatterns: ['fetch', 'axios', 'http', 'request', 'got'],
20
+ };
21
+ configure(options) {
22
+ this.config = { ...this.config, ...options };
23
+ }
24
+ async check(context) {
25
+ const violations = [];
26
+ for (const nodeId of context.graph.nodes()) {
27
+ const node = context.getNodeData(nodeId);
28
+ if (!node)
29
+ continue;
30
+ const filePath = node.data.relativePath;
31
+ const content = context.fileContents?.get(filePath);
32
+ if (!content)
33
+ continue;
34
+ this.checkExternalCalls(filePath, content, violations);
35
+ this.checkResiliencePatterns(filePath, content, violations);
36
+ this.checkErrorHandling(filePath, content, violations);
37
+ }
38
+ return { violations };
39
+ }
40
+ checkExternalCalls(filePath, content, violations) {
41
+ const lines = content.split('\n');
42
+ const callPatterns = this.config.externalCallPatterns || [];
43
+ for (let i = 0; i < lines.length; i++) {
44
+ const line = lines[i];
45
+ for (const pattern of callPatterns) {
46
+ const regex = new RegExp(`\\b${pattern}\\s*[\\(.]`, 'i');
47
+ if (regex.test(line)) {
48
+ // Check for timeout in surrounding context
49
+ const contextStart = Math.max(0, i - 10);
50
+ const contextEnd = Math.min(lines.length, i + 10);
51
+ const context = lines.slice(contextStart, contextEnd).join('\n');
52
+ if (this.config.requireTimeout && !this.hasTimeout(context)) {
53
+ violations.push(this.createViolation(filePath, `External call without timeout configuration`, i + 1, 'Add timeout to external service calls'));
54
+ }
55
+ }
56
+ }
57
+ }
58
+ }
59
+ checkResiliencePatterns(filePath, content, violations) {
60
+ const fileName = path.basename(filePath).toLowerCase();
61
+ // Skip if not a service or client file
62
+ if (!fileName.includes('service') && !fileName.includes('client') && !fileName.includes('adapter')) {
63
+ return;
64
+ }
65
+ const hasExternalCalls = this.config.externalCallPatterns?.some(p => content.toLowerCase().includes(p));
66
+ if (!hasExternalCalls)
67
+ return;
68
+ const hasCircuitBreaker = content.includes('circuitBreaker') ||
69
+ content.includes('CircuitBreaker') ||
70
+ content.includes('@CircuitBreaker');
71
+ const hasRetry = content.includes('retry') ||
72
+ content.includes('Retry') ||
73
+ content.includes('@Retryable') ||
74
+ content.includes('maxRetries');
75
+ if (this.config.requireCircuitBreaker && !hasCircuitBreaker) {
76
+ violations.push(this.createViolation(filePath, 'Service with external calls missing circuit breaker', 1, 'Implement circuit breaker pattern for fault tolerance'));
77
+ }
78
+ if (this.config.requireRetry && !hasRetry) {
79
+ violations.push(this.createViolation(filePath, 'Service with external calls missing retry logic', 1, 'Implement retry with exponential backoff for transient failures'));
80
+ }
81
+ }
82
+ checkErrorHandling(filePath, content, violations) {
83
+ const lines = content.split('\n');
84
+ for (let i = 0; i < lines.length; i++) {
85
+ const line = lines[i];
86
+ // Check for empty catch blocks
87
+ if (/catch\s*\([^)]*\)\s*\{\s*\}/.test(line) ||
88
+ (/catch\s*\([^)]*\)\s*\{/.test(line) && lines[i + 1]?.trim() === '}')) {
89
+ violations.push(this.createViolation(filePath, 'Empty catch block swallows errors silently', i + 1, 'Log the error or handle it appropriately'));
90
+ }
91
+ // Check for catch blocks that only console.log
92
+ if (/catch\s*\([^)]*\)\s*\{/.test(line)) {
93
+ const nextLines = lines.slice(i + 1, i + 4).join('\n');
94
+ if (/console\.(log|error)/.test(nextLines) && !/throw|return|reject/.test(nextLines)) {
95
+ violations.push(this.createViolation(filePath, 'Catch block only logs error without proper handling', i + 1, 'Consider rethrowing, returning error result, or using circuit breaker'));
96
+ }
97
+ }
98
+ }
99
+ }
100
+ hasTimeout(context) {
101
+ const timeoutPatterns = [
102
+ /timeout/i,
103
+ /AbortController/,
104
+ /signal/,
105
+ /deadline/i,
106
+ /\d+\s*\*\s*1000/, // Common timeout patterns like 30 * 1000
107
+ ];
108
+ return timeoutPatterns.some(p => p.test(context));
109
+ }
110
+ createViolation(file, message, line, suggestion) {
111
+ return {
112
+ id: `${this.id}-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
113
+ ruleId: this.id,
114
+ ruleName: this.name,
115
+ severity: 'warning',
116
+ message,
117
+ file,
118
+ line,
119
+ suggestion,
120
+ };
121
+ }
122
+ }
123
+ //# sourceMappingURL=resilience-patterns.rule.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resilience-patterns.rule.js","sourceRoot":"","sources":["../../../../src/core/rules/builtin/resilience-patterns.rule.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Security Context Rule
3
+ *
4
+ * Validates security context propagation and authorization patterns.
5
+ */
6
+ import { IRule, RuleContext, RuleConfig, RuleResult } from '../rule.interface.js';
7
+ interface SecurityContextConfig extends RuleConfig {
8
+ requireAuthentication?: boolean;
9
+ requireAuthorization?: boolean;
10
+ sensitiveRoutes?: string[];
11
+ publicRoutes?: string[];
12
+ }
13
+ export declare class SecurityContextRule implements IRule {
14
+ readonly id = "security-context";
15
+ readonly name = "Security Context Propagation";
16
+ readonly description = "Validates security context propagation and authorization patterns";
17
+ readonly severity: "error";
18
+ readonly tags: string[];
19
+ private config;
20
+ configure(options: Partial<SecurityContextConfig>): void;
21
+ check(context: RuleContext): Promise<RuleResult>;
22
+ private isSecurityRelevantFile;
23
+ private checkAuthenticationMiddleware;
24
+ private checkAuthorizationDecorators;
25
+ private checkSecurityHeaders;
26
+ private checkSensitiveDataHandling;
27
+ private isPublicRoute;
28
+ private isSensitiveRoute;
29
+ private createViolation;
30
+ }
31
+ export {};
32
+ //# sourceMappingURL=security-context.rule.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"security-context.rule.d.ts","sourceRoot":"","sources":["../../../../src/core/rules/builtin/security-context.rule.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAIlF,UAAU,qBAAsB,SAAQ,UAAU;IAChD,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;CACzB;AAED,qBAAa,mBAAoB,YAAW,KAAK;IAC/C,QAAQ,CAAC,EAAE,sBAAsB;IACjC,QAAQ,CAAC,IAAI,kCAAkC;IAC/C,QAAQ,CAAC,WAAW,uEAAuE;IAC3F,QAAQ,CAAC,QAAQ,EAAG,OAAO,CAAU;IACrC,QAAQ,CAAC,IAAI,WAAmD;IAEhE,OAAO,CAAC,MAAM,CAOZ;IAEF,SAAS,CAAC,OAAO,EAAE,OAAO,CAAC,qBAAqB,CAAC,GAAG,IAAI;IAIlD,KAAK,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC;IAwBtD,OAAO,CAAC,sBAAsB;IAK9B,OAAO,CAAC,6BAA6B;IAsDrC,OAAO,CAAC,4BAA4B;IAyBpC,OAAO,CAAC,oBAAoB;IAmB5B,OAAO,CAAC,0BAA0B;IAuBlC,OAAO,CAAC,aAAa;IAIrB,OAAO,CAAC,gBAAgB;IAIxB,OAAO,CAAC,eAAe;CAYxB"}
@@ -0,0 +1,145 @@
1
+ /**
2
+ * Security Context Rule
3
+ *
4
+ * Validates security context propagation and authorization patterns.
5
+ */
6
+ import * as path from 'path';
7
+ export class SecurityContextRule {
8
+ id = 'security-context';
9
+ name = 'Security Context Propagation';
10
+ description = 'Validates security context propagation and authorization patterns';
11
+ severity = 'error';
12
+ tags = ['security', 'authentication', 'authorization'];
13
+ config = {
14
+ enabled: true,
15
+ severity: 'error',
16
+ requireAuthentication: true,
17
+ requireAuthorization: true,
18
+ sensitiveRoutes: ['/admin', '/api/users', '/api/settings'],
19
+ publicRoutes: ['/health', '/public', '/auth/login'],
20
+ };
21
+ configure(options) {
22
+ this.config = { ...this.config, ...options };
23
+ }
24
+ async check(context) {
25
+ const violations = [];
26
+ for (const nodeId of context.graph.nodes()) {
27
+ const node = context.getNodeData(nodeId);
28
+ if (!node)
29
+ continue;
30
+ const filePath = node.data.relativePath;
31
+ const content = context.fileContents?.get(filePath);
32
+ if (!content)
33
+ continue;
34
+ const fileName = path.basename(filePath).toLowerCase();
35
+ if (this.isSecurityRelevantFile(fileName)) {
36
+ this.checkAuthenticationMiddleware(filePath, content, violations);
37
+ this.checkAuthorizationDecorators(filePath, content, violations);
38
+ this.checkSecurityHeaders(filePath, content, violations);
39
+ this.checkSensitiveDataHandling(filePath, content, violations);
40
+ }
41
+ }
42
+ return { violations };
43
+ }
44
+ isSecurityRelevantFile(fileName) {
45
+ const relevantPatterns = ['controller', 'handler', 'router', 'middleware', 'guard', 'auth'];
46
+ return relevantPatterns.some(p => fileName.includes(p));
47
+ }
48
+ checkAuthenticationMiddleware(filePath, content, violations) {
49
+ const lines = content.split('\n');
50
+ // Look for routes/endpoints
51
+ const routePatterns = [
52
+ /@(?:Get|Post|Put|Delete|Patch)\s*\(\s*['"]([^'"]+)['"]\s*\)/,
53
+ /router\.(?:get|post|put|delete|patch)\s*\(\s*['"]([^'"]+)['"]/,
54
+ ];
55
+ for (let i = 0; i < lines.length; i++) {
56
+ const line = lines[i];
57
+ for (const pattern of routePatterns) {
58
+ const match = line.match(pattern);
59
+ if (match) {
60
+ const route = match[1];
61
+ // Check if it's a public route
62
+ if (this.isPublicRoute(route))
63
+ continue;
64
+ // Look for auth guards/middleware in surrounding context
65
+ const contextStart = Math.max(0, i - 5);
66
+ const contextEnd = Math.min(lines.length, i + 2);
67
+ const context = lines.slice(contextStart, contextEnd).join('\n');
68
+ const hasAuth = /@UseGuards|@Auth|authenticate|isAuthenticated|requireAuth|@Public\(false\)/.test(context);
69
+ if (!hasAuth && this.config.requireAuthentication) {
70
+ violations.push(this.createViolation(filePath, `Route '${route}' without authentication guard`, i + 1, 'Add authentication middleware or guard'));
71
+ }
72
+ // Check for authorization on sensitive routes
73
+ if (this.isSensitiveRoute(route)) {
74
+ const hasAuthorization = /@Roles|@Permissions|@Authorize|authorize|checkPermission/.test(context);
75
+ if (!hasAuthorization && this.config.requireAuthorization) {
76
+ violations.push(this.createViolation(filePath, `Sensitive route '${route}' without authorization`, i + 1, 'Add role-based or permission-based authorization'));
77
+ }
78
+ }
79
+ }
80
+ }
81
+ }
82
+ }
83
+ checkAuthorizationDecorators(filePath, content, violations) {
84
+ const lines = content.split('\n');
85
+ // Check for direct database access in controllers without authorization
86
+ if (filePath.toLowerCase().includes('controller')) {
87
+ for (let i = 0; i < lines.length; i++) {
88
+ const line = lines[i];
89
+ if (/repository\.|\.find\(|\.save\(|\.delete\(|\.update\(/.test(line)) {
90
+ // Check if there's authorization above
91
+ const contextAbove = lines.slice(Math.max(0, i - 10), i).join('\n');
92
+ if (!/@Roles|@Permissions|authorize|checkPermission/.test(contextAbove)) {
93
+ violations.push(this.createViolation(filePath, 'Direct data access in controller without authorization check', i + 1, 'Add authorization check before data operations'));
94
+ }
95
+ }
96
+ }
97
+ }
98
+ }
99
+ checkSecurityHeaders(filePath, content, violations) {
100
+ // Check for response handling without security headers
101
+ if (content.includes('res.send') || content.includes('res.json')) {
102
+ const hasHelmet = content.includes('helmet') || content.includes('Helmet');
103
+ const hasSecurityHeaders = content.includes('X-Content-Type-Options') ||
104
+ content.includes('X-Frame-Options') ||
105
+ content.includes('Content-Security-Policy');
106
+ if (!hasHelmet && !hasSecurityHeaders) {
107
+ violations.push(this.createViolation(filePath, 'Response handling without security headers', 1, 'Use helmet middleware or set security headers manually'));
108
+ }
109
+ }
110
+ }
111
+ checkSensitiveDataHandling(filePath, content, violations) {
112
+ const lines = content.split('\n');
113
+ const sensitiveFields = ['password', 'token', 'secret', 'apiKey', 'creditCard', 'ssn'];
114
+ for (let i = 0; i < lines.length; i++) {
115
+ const line = lines[i].toLowerCase();
116
+ for (const field of sensitiveFields) {
117
+ if (line.includes(field)) {
118
+ // Check if it's being exposed in response
119
+ if (/res\.(json|send)\s*\(/.test(lines[i]) || /return\s+\{/.test(lines[i])) {
120
+ violations.push(this.createViolation(filePath, `Potential sensitive data '${field}' in response`, i + 1, 'Exclude sensitive fields from API responses using DTOs or serialization'));
121
+ }
122
+ }
123
+ }
124
+ }
125
+ }
126
+ isPublicRoute(route) {
127
+ return this.config.publicRoutes?.some(p => route.startsWith(p)) || false;
128
+ }
129
+ isSensitiveRoute(route) {
130
+ return this.config.sensitiveRoutes?.some(p => route.startsWith(p)) || false;
131
+ }
132
+ createViolation(file, message, line, suggestion) {
133
+ return {
134
+ id: `${this.id}-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
135
+ ruleId: this.id,
136
+ ruleName: this.name,
137
+ severity: 'error',
138
+ message,
139
+ file,
140
+ line,
141
+ suggestion,
142
+ };
143
+ }
144
+ }
145
+ //# sourceMappingURL=security-context.rule.js.map