@sfdxy/mule-lint 1.19.0 → 1.21.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 (154) hide show
  1. package/README.md +128 -73
  2. package/dist/package.json +1 -1
  3. package/dist/src/core/XPathHelper.d.ts.map +1 -1
  4. package/dist/src/core/XPathHelper.js +8 -0
  5. package/dist/src/core/XPathHelper.js.map +1 -1
  6. package/dist/src/engine/LintEngine.d.ts +32 -0
  7. package/dist/src/engine/LintEngine.d.ts.map +1 -1
  8. package/dist/src/engine/LintEngine.js +166 -15
  9. package/dist/src/engine/LintEngine.js.map +1 -1
  10. package/dist/src/rules/api-led/ApikitConsoleProductionRule.d.ts +22 -0
  11. package/dist/src/rules/api-led/ApikitConsoleProductionRule.d.ts.map +1 -0
  12. package/dist/src/rules/api-led/ApikitConsoleProductionRule.js +43 -0
  13. package/dist/src/rules/api-led/ApikitConsoleProductionRule.js.map +1 -0
  14. package/dist/src/rules/api-led/ApikitMainFlowStructureRule.d.ts +24 -0
  15. package/dist/src/rules/api-led/ApikitMainFlowStructureRule.d.ts.map +1 -0
  16. package/dist/src/rules/api-led/ApikitMainFlowStructureRule.js +53 -0
  17. package/dist/src/rules/api-led/ApikitMainFlowStructureRule.js.map +1 -0
  18. package/dist/src/rules/api-led/ApikitStatusCodeVariableRule.d.ts +25 -0
  19. package/dist/src/rules/api-led/ApikitStatusCodeVariableRule.d.ts.map +1 -0
  20. package/dist/src/rules/api-led/ApikitStatusCodeVariableRule.js +59 -0
  21. package/dist/src/rules/api-led/ApikitStatusCodeVariableRule.js.map +1 -0
  22. package/dist/src/rules/connector/EventListenerNullGuardRule.d.ts +24 -0
  23. package/dist/src/rules/connector/EventListenerNullGuardRule.d.ts.map +1 -0
  24. package/dist/src/rules/connector/EventListenerNullGuardRule.js +58 -0
  25. package/dist/src/rules/connector/EventListenerNullGuardRule.js.map +1 -0
  26. package/dist/src/rules/connector/ReplayChannelConfigRule.d.ts +23 -0
  27. package/dist/src/rules/connector/ReplayChannelConfigRule.d.ts.map +1 -0
  28. package/dist/src/rules/connector/ReplayChannelConfigRule.js +52 -0
  29. package/dist/src/rules/connector/ReplayChannelConfigRule.js.map +1 -0
  30. package/dist/src/rules/dataweave/DataWeaveRules.d.ts +17 -4
  31. package/dist/src/rules/dataweave/DataWeaveRules.d.ts.map +1 -1
  32. package/dist/src/rules/dataweave/DataWeaveRules.js +36 -20
  33. package/dist/src/rules/dataweave/DataWeaveRules.js.map +1 -1
  34. package/dist/src/rules/dataweave/DuplicateTransformLogicRule.d.ts +25 -0
  35. package/dist/src/rules/dataweave/DuplicateTransformLogicRule.d.ts.map +1 -0
  36. package/dist/src/rules/dataweave/DuplicateTransformLogicRule.js +63 -0
  37. package/dist/src/rules/dataweave/DuplicateTransformLogicRule.js.map +1 -0
  38. package/dist/src/rules/error-handling/CatchAllLastRule.d.ts +24 -0
  39. package/dist/src/rules/error-handling/CatchAllLastRule.d.ts.map +1 -0
  40. package/dist/src/rules/error-handling/CatchAllLastRule.js +65 -0
  41. package/dist/src/rules/error-handling/CatchAllLastRule.js.map +1 -0
  42. package/dist/src/rules/error-handling/CorrelationIdRule.d.ts +22 -1
  43. package/dist/src/rules/error-handling/CorrelationIdRule.d.ts.map +1 -1
  44. package/dist/src/rules/error-handling/CorrelationIdRule.js +107 -6
  45. package/dist/src/rules/error-handling/CorrelationIdRule.js.map +1 -1
  46. package/dist/src/rules/error-handling/ErrorHandlerTypeCoverageRule.d.ts +28 -0
  47. package/dist/src/rules/error-handling/ErrorHandlerTypeCoverageRule.d.ts.map +1 -0
  48. package/dist/src/rules/error-handling/ErrorHandlerTypeCoverageRule.js +70 -0
  49. package/dist/src/rules/error-handling/ErrorHandlerTypeCoverageRule.js.map +1 -0
  50. package/dist/src/rules/error-handling/ErrorResponseStructureRule.d.ts +23 -0
  51. package/dist/src/rules/error-handling/ErrorResponseStructureRule.d.ts.map +1 -0
  52. package/dist/src/rules/error-handling/ErrorResponseStructureRule.js +73 -0
  53. package/dist/src/rules/error-handling/ErrorResponseStructureRule.js.map +1 -0
  54. package/dist/src/rules/error-handling/GenericErrorRule.d.ts +15 -3
  55. package/dist/src/rules/error-handling/GenericErrorRule.d.ts.map +1 -1
  56. package/dist/src/rules/error-handling/GenericErrorRule.js +58 -18
  57. package/dist/src/rules/error-handling/GenericErrorRule.js.map +1 -1
  58. package/dist/src/rules/error-handling/GlobalErrorHandlerRule.d.ts +16 -5
  59. package/dist/src/rules/error-handling/GlobalErrorHandlerRule.d.ts.map +1 -1
  60. package/dist/src/rules/error-handling/GlobalErrorHandlerRule.js +64 -21
  61. package/dist/src/rules/error-handling/GlobalErrorHandlerRule.js.map +1 -1
  62. package/dist/src/rules/error-handling/HttpStatusRule.d.ts +5 -0
  63. package/dist/src/rules/error-handling/HttpStatusRule.d.ts.map +1 -1
  64. package/dist/src/rules/error-handling/HttpStatusRule.js +15 -0
  65. package/dist/src/rules/error-handling/HttpStatusRule.js.map +1 -1
  66. package/dist/src/rules/error-handling/TryScopeRule.d.ts +5 -0
  67. package/dist/src/rules/error-handling/TryScopeRule.d.ts.map +1 -1
  68. package/dist/src/rules/error-handling/TryScopeRule.js +30 -7
  69. package/dist/src/rules/error-handling/TryScopeRule.js.map +1 -1
  70. package/dist/src/rules/http/ConnectionIdleTimeoutRule.d.ts +27 -0
  71. package/dist/src/rules/http/ConnectionIdleTimeoutRule.d.ts.map +1 -0
  72. package/dist/src/rules/http/ConnectionIdleTimeoutRule.js +46 -0
  73. package/dist/src/rules/http/ConnectionIdleTimeoutRule.js.map +1 -0
  74. package/dist/src/rules/http/HttpContentTypeRule.d.ts +28 -1
  75. package/dist/src/rules/http/HttpContentTypeRule.d.ts.map +1 -1
  76. package/dist/src/rules/http/HttpContentTypeRule.js +68 -7
  77. package/dist/src/rules/http/HttpContentTypeRule.js.map +1 -1
  78. package/dist/src/rules/index.d.ts +1 -1
  79. package/dist/src/rules/index.d.ts.map +1 -1
  80. package/dist/src/rules/index.js +50 -8
  81. package/dist/src/rules/index.js.map +1 -1
  82. package/dist/src/rules/logging/LoggerPayloadRule.d.ts +15 -0
  83. package/dist/src/rules/logging/LoggerPayloadRule.d.ts.map +1 -1
  84. package/dist/src/rules/logging/LoggerPayloadRule.js +48 -4
  85. package/dist/src/rules/logging/LoggerPayloadRule.js.map +1 -1
  86. package/dist/src/rules/operations/FlowRefTargetExistsRule.d.ts +23 -0
  87. package/dist/src/rules/operations/FlowRefTargetExistsRule.d.ts.map +1 -0
  88. package/dist/src/rules/operations/FlowRefTargetExistsRule.js +58 -0
  89. package/dist/src/rules/operations/FlowRefTargetExistsRule.js.map +1 -0
  90. package/dist/src/rules/operations/UnusedFlowRule.d.ts +26 -1
  91. package/dist/src/rules/operations/UnusedFlowRule.d.ts.map +1 -1
  92. package/dist/src/rules/operations/UnusedFlowRule.js +96 -16
  93. package/dist/src/rules/operations/UnusedFlowRule.js.map +1 -1
  94. package/dist/src/rules/operations/UnusedVariableRule.d.ts +31 -0
  95. package/dist/src/rules/operations/UnusedVariableRule.d.ts.map +1 -0
  96. package/dist/src/rules/operations/UnusedVariableRule.js +103 -0
  97. package/dist/src/rules/operations/UnusedVariableRule.js.map +1 -0
  98. package/dist/src/rules/performance/ConnectionPoolingRule.d.ts +5 -0
  99. package/dist/src/rules/performance/ConnectionPoolingRule.d.ts.map +1 -1
  100. package/dist/src/rules/performance/ConnectionPoolingRule.js +18 -5
  101. package/dist/src/rules/performance/ConnectionPoolingRule.js.map +1 -1
  102. package/dist/src/rules/performance/ListenerReconnectForeverRule.d.ts +28 -0
  103. package/dist/src/rules/performance/ListenerReconnectForeverRule.d.ts.map +1 -0
  104. package/dist/src/rules/performance/ListenerReconnectForeverRule.js +56 -0
  105. package/dist/src/rules/performance/ListenerReconnectForeverRule.js.map +1 -0
  106. package/dist/src/rules/performance/ReconnectionStrategyRule.d.ts +10 -0
  107. package/dist/src/rules/performance/ReconnectionStrategyRule.d.ts.map +1 -1
  108. package/dist/src/rules/performance/ReconnectionStrategyRule.js +47 -14
  109. package/dist/src/rules/performance/ReconnectionStrategyRule.js.map +1 -1
  110. package/dist/src/rules/security/ConnectorCredentialsSecuredRule.d.ts +36 -0
  111. package/dist/src/rules/security/ConnectorCredentialsSecuredRule.d.ts.map +1 -0
  112. package/dist/src/rules/security/ConnectorCredentialsSecuredRule.js +124 -0
  113. package/dist/src/rules/security/ConnectorCredentialsSecuredRule.js.map +1 -0
  114. package/dist/src/rules/security/HardcodedCredentialsRule.d.ts +4 -0
  115. package/dist/src/rules/security/HardcodedCredentialsRule.d.ts.map +1 -1
  116. package/dist/src/rules/security/HardcodedCredentialsRule.js +15 -0
  117. package/dist/src/rules/security/HardcodedCredentialsRule.js.map +1 -1
  118. package/dist/src/rules/security/SecurePropertiesEncryptionRule.d.ts +25 -0
  119. package/dist/src/rules/security/SecurePropertiesEncryptionRule.d.ts.map +1 -0
  120. package/dist/src/rules/security/SecurePropertiesEncryptionRule.js +59 -0
  121. package/dist/src/rules/security/SecurePropertiesEncryptionRule.js.map +1 -0
  122. package/dist/src/rules/security/SecurePropertiesKeyRule.d.ts +23 -0
  123. package/dist/src/rules/security/SecurePropertiesKeyRule.d.ts.map +1 -0
  124. package/dist/src/rules/security/SecurePropertiesKeyRule.js +45 -0
  125. package/dist/src/rules/security/SecurePropertiesKeyRule.js.map +1 -0
  126. package/dist/src/rules/security/TlsKeystorePasswordRule.d.ts +25 -0
  127. package/dist/src/rules/security/TlsKeystorePasswordRule.d.ts.map +1 -0
  128. package/dist/src/rules/security/TlsKeystorePasswordRule.js +63 -0
  129. package/dist/src/rules/security/TlsKeystorePasswordRule.js.map +1 -0
  130. package/dist/src/rules/standards/ApikitRouteVariableConsistencyRule.d.ts +26 -0
  131. package/dist/src/rules/standards/ApikitRouteVariableConsistencyRule.d.ts.map +1 -0
  132. package/dist/src/rules/standards/ApikitRouteVariableConsistencyRule.js +61 -0
  133. package/dist/src/rules/standards/ApikitRouteVariableConsistencyRule.js.map +1 -0
  134. package/dist/src/rules/standards/ConfigPropertiesOrderingRule.d.ts +34 -0
  135. package/dist/src/rules/standards/ConfigPropertiesOrderingRule.d.ts.map +1 -0
  136. package/dist/src/rules/standards/ConfigPropertiesOrderingRule.js +76 -0
  137. package/dist/src/rules/standards/ConfigPropertiesOrderingRule.js.map +1 -0
  138. package/dist/src/rules/standards/MissingEnvPropertiesDeclarationRule.d.ts +25 -0
  139. package/dist/src/rules/standards/MissingEnvPropertiesDeclarationRule.d.ts.map +1 -0
  140. package/dist/src/rules/standards/MissingEnvPropertiesDeclarationRule.js +111 -0
  141. package/dist/src/rules/standards/MissingEnvPropertiesDeclarationRule.js.map +1 -0
  142. package/dist/src/rules/structure/StructureRules.d.ts +8 -1
  143. package/dist/src/rules/structure/StructureRules.d.ts.map +1 -1
  144. package/dist/src/rules/structure/StructureRules.js +11 -7
  145. package/dist/src/rules/structure/StructureRules.js.map +1 -1
  146. package/dist/src/rules/yaml/YamlRules.d.ts +6 -2
  147. package/dist/src/rules/yaml/YamlRules.d.ts.map +1 -1
  148. package/dist/src/rules/yaml/YamlRules.js +15 -11
  149. package/dist/src/rules/yaml/YamlRules.js.map +1 -1
  150. package/dist/src/types/Rule.d.ts +35 -0
  151. package/dist/src/types/Rule.d.ts.map +1 -1
  152. package/docs/best-practices/rules-catalog.md +444 -42
  153. package/docs/linter/architecture.md +119 -64
  154. package/package.json +1 -1
@@ -0,0 +1,28 @@
1
+ import { ValidationContext, Issue } from '../../types';
2
+ import { BaseRule } from '../base/BaseRule';
3
+ /**
4
+ * RES-002: Listener Reconnect-Forever
5
+ *
6
+ * HTTP listener-config elements should use reconnect-forever rather than
7
+ * bounded reconnect strategies. Unlike outbound connectors where bounded
8
+ * retries make sense, the listener is the application's entry point — if
9
+ * it can't bind to the port, the app should keep trying indefinitely.
10
+ *
11
+ * Real-world accelerator pattern:
12
+ * <http:listener-config>
13
+ * <http:listener-connection host="0.0.0.0" port="${http.port}">
14
+ * <reconnection>
15
+ * <reconnect-forever frequency="5000" />
16
+ * </reconnection>
17
+ * </http:listener-connection>
18
+ * </http:listener-config>
19
+ */
20
+ export declare class ListenerReconnectForeverRule extends BaseRule {
21
+ id: string;
22
+ name: string;
23
+ description: string;
24
+ severity: "warning";
25
+ category: "performance";
26
+ validate(doc: Document, _context: ValidationContext): Issue[];
27
+ }
28
+ //# sourceMappingURL=ListenerReconnectForeverRule.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ListenerReconnectForeverRule.d.ts","sourceRoot":"","sources":["../../../../src/rules/performance/ListenerReconnectForeverRule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACvD,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE5C;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,4BAA6B,SAAQ,QAAQ;IACxD,EAAE,SAAa;IACf,IAAI,SAAgC;IACpC,WAAW,SAAsE;IACjF,QAAQ,EAAG,SAAS,CAAU;IAC9B,QAAQ,EAAG,aAAa,CAAU;IAElC,QAAQ,CAAC,GAAG,EAAE,QAAQ,EAAE,QAAQ,EAAE,iBAAiB,GAAG,KAAK,EAAE;CA2C9D"}
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ListenerReconnectForeverRule = void 0;
4
+ const BaseRule_1 = require("../base/BaseRule");
5
+ /**
6
+ * RES-002: Listener Reconnect-Forever
7
+ *
8
+ * HTTP listener-config elements should use reconnect-forever rather than
9
+ * bounded reconnect strategies. Unlike outbound connectors where bounded
10
+ * retries make sense, the listener is the application's entry point — if
11
+ * it can't bind to the port, the app should keep trying indefinitely.
12
+ *
13
+ * Real-world accelerator pattern:
14
+ * <http:listener-config>
15
+ * <http:listener-connection host="0.0.0.0" port="${http.port}">
16
+ * <reconnection>
17
+ * <reconnect-forever frequency="5000" />
18
+ * </reconnection>
19
+ * </http:listener-connection>
20
+ * </http:listener-config>
21
+ */
22
+ class ListenerReconnectForeverRule extends BaseRule_1.BaseRule {
23
+ id = 'RES-002';
24
+ name = 'Listener Reconnect-Forever';
25
+ description = 'HTTP listener-config should use reconnect-forever for resilience';
26
+ severity = 'warning';
27
+ category = 'performance';
28
+ validate(doc, _context) {
29
+ const issues = [];
30
+ const listenerConfigs = this.select('//*[local-name()="listener-config"]', doc);
31
+ for (const config of listenerConfigs) {
32
+ const name = this.getNameAttribute(config) ?? 'HTTP Listener';
33
+ // Check if reconnect-forever exists anywhere inside the config
34
+ const hasReconnectForever = this.exists('.//*[local-name()="reconnect-forever"]', config);
35
+ if (hasReconnectForever) {
36
+ continue; // Good — has reconnect-forever
37
+ }
38
+ // Check if there's a bounded reconnect (which is suboptimal for listeners)
39
+ const hasBoundedReconnect = this.exists('.//*[local-name()="reconnect"]', config) ||
40
+ this.exists('.//*[local-name()="reconnection"]', config);
41
+ if (hasBoundedReconnect) {
42
+ issues.push(this.createIssue(config, `Listener config "${name}" uses bounded reconnect instead of reconnect-forever`, {
43
+ suggestion: 'Replace <reconnect count="..." .../> with <reconnect-forever frequency="5000" /> for HTTP listeners — the app should keep trying to bind',
44
+ }));
45
+ }
46
+ else {
47
+ issues.push(this.createIssue(config, `Listener config "${name}" has no reconnection strategy`, {
48
+ suggestion: 'Add <reconnection><reconnect-forever frequency="5000" /></reconnection> inside the listener-connection element',
49
+ }));
50
+ }
51
+ }
52
+ return issues;
53
+ }
54
+ }
55
+ exports.ListenerReconnectForeverRule = ListenerReconnectForeverRule;
56
+ //# sourceMappingURL=ListenerReconnectForeverRule.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ListenerReconnectForeverRule.js","sourceRoot":"","sources":["../../../../src/rules/performance/ListenerReconnectForeverRule.ts"],"names":[],"mappings":";;;AACA,+CAA4C;AAE5C;;;;;;;;;;;;;;;;GAgBG;AACH,MAAa,4BAA6B,SAAQ,mBAAQ;IACxD,EAAE,GAAG,SAAS,CAAC;IACf,IAAI,GAAG,4BAA4B,CAAC;IACpC,WAAW,GAAG,kEAAkE,CAAC;IACjF,QAAQ,GAAG,SAAkB,CAAC;IAC9B,QAAQ,GAAG,aAAsB,CAAC;IAElC,QAAQ,CAAC,GAAa,EAAE,QAA2B;QACjD,MAAM,MAAM,GAAY,EAAE,CAAC;QAE3B,MAAM,eAAe,GAAG,IAAI,CAAC,MAAM,CAAC,qCAAqC,EAAE,GAAG,CAAC,CAAC;QAEhF,KAAK,MAAM,MAAM,IAAI,eAAe,EAAE,CAAC;YACrC,MAAM,IAAI,GAAG,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,IAAI,eAAe,CAAC;YAE9D,+DAA+D;YAC/D,MAAM,mBAAmB,GAAG,IAAI,CAAC,MAAM,CAAC,wCAAwC,EAAE,MAAM,CAAC,CAAC;YAE1F,IAAI,mBAAmB,EAAE,CAAC;gBACxB,SAAS,CAAC,+BAA+B;YAC3C,CAAC;YAED,2EAA2E;YAC3E,MAAM,mBAAmB,GACvB,IAAI,CAAC,MAAM,CAAC,gCAAgC,EAAE,MAAM,CAAC;gBACrD,IAAI,CAAC,MAAM,CAAC,mCAAmC,EAAE,MAAM,CAAC,CAAC;YAE3D,IAAI,mBAAmB,EAAE,CAAC;gBACxB,MAAM,CAAC,IAAI,CACT,IAAI,CAAC,WAAW,CACd,MAAM,EACN,oBAAoB,IAAI,uDAAuD,EAC/E;oBACE,UAAU,EACR,0IAA0I;iBAC7I,CACF,CACF,CAAC;YACJ,CAAC;iBAAM,CAAC;gBACN,MAAM,CAAC,IAAI,CACT,IAAI,CAAC,WAAW,CAAC,MAAM,EAAE,oBAAoB,IAAI,gCAAgC,EAAE;oBACjF,UAAU,EACR,gHAAgH;iBACnH,CAAC,CACH,CAAC;YACJ,CAAC;QACH,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;CACF;AAlDD,oEAkDC"}
@@ -4,6 +4,15 @@ import { BaseRule } from '../base/BaseRule';
4
4
  * RES-001: Reconnection Strategy
5
5
  *
6
6
  * Connectors should have reconnection strategies configured for resilience.
7
+ *
8
+ * Enhanced to differentiate listener vs request configs:
9
+ * - Listeners (inbound): recommend `reconnect-forever` (service must stay alive)
10
+ * - Requests (outbound): recommend bounded `reconnect count="3"` (fail fast for callers)
11
+ *
12
+ * Per the Mule HTTP connector XSD, `<reconnection>` is a child element of
13
+ * `<http:request-connection>`, NOT a direct child of `<http:request-config>`.
14
+ * The rule uses a descendant search (`.//*`) to correctly resolve reconnection
15
+ * elements at any depth.
7
16
  */
8
17
  export declare class ReconnectionStrategyRule extends BaseRule {
9
18
  id: string;
@@ -12,5 +21,6 @@ export declare class ReconnectionStrategyRule extends BaseRule {
12
21
  severity: "warning";
13
22
  category: "performance";
14
23
  validate(doc: Document, _context: ValidationContext): Issue[];
24
+ private hasAnyReconnection;
15
25
  }
16
26
  //# sourceMappingURL=ReconnectionStrategyRule.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ReconnectionStrategyRule.d.ts","sourceRoot":"","sources":["../../../../src/rules/performance/ReconnectionStrategyRule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACvD,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE5C;;;;GAIG;AACH,qBAAa,wBAAyB,SAAQ,QAAQ;IACpD,EAAE,SAAa;IACf,IAAI,SAA2B;IAC/B,WAAW,SAA+D;IAC1E,QAAQ,EAAG,SAAS,CAAU;IAC9B,QAAQ,EAAG,aAAa,CAAU;IAElC,QAAQ,CAAC,GAAG,EAAE,QAAQ,EAAE,QAAQ,EAAE,iBAAiB,GAAG,KAAK,EAAE;CA2D9D"}
1
+ {"version":3,"file":"ReconnectionStrategyRule.d.ts","sourceRoot":"","sources":["../../../../src/rules/performance/ReconnectionStrategyRule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACvD,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE5C;;;;;;;;;;;;;GAaG;AACH,qBAAa,wBAAyB,SAAQ,QAAQ;IACpD,EAAE,SAAa;IACf,IAAI,SAA2B;IAC/B,WAAW,SAA+D;IAC1E,QAAQ,EAAG,SAAS,CAAU;IAC9B,QAAQ,EAAG,aAAa,CAAU;IAElC,QAAQ,CAAC,GAAG,EAAE,QAAQ,EAAE,QAAQ,EAAE,iBAAiB,GAAG,KAAK,EAAE;IAkG7D,OAAO,CAAC,kBAAkB;CAO3B"}
@@ -6,6 +6,15 @@ const BaseRule_1 = require("../base/BaseRule");
6
6
  * RES-001: Reconnection Strategy
7
7
  *
8
8
  * Connectors should have reconnection strategies configured for resilience.
9
+ *
10
+ * Enhanced to differentiate listener vs request configs:
11
+ * - Listeners (inbound): recommend `reconnect-forever` (service must stay alive)
12
+ * - Requests (outbound): recommend bounded `reconnect count="3"` (fail fast for callers)
13
+ *
14
+ * Per the Mule HTTP connector XSD, `<reconnection>` is a child element of
15
+ * `<http:request-connection>`, NOT a direct child of `<http:request-config>`.
16
+ * The rule uses a descendant search (`.//*`) to correctly resolve reconnection
17
+ * elements at any depth.
9
18
  */
10
19
  class ReconnectionStrategyRule extends BaseRule_1.BaseRule {
11
20
  id = 'RES-001';
@@ -15,46 +24,70 @@ class ReconnectionStrategyRule extends BaseRule_1.BaseRule {
15
24
  category = 'performance';
16
25
  validate(doc, _context) {
17
26
  const issues = [];
18
- // Specific connector configurations that benefit from reconnection strategies
19
- // Using more specific patterns to avoid false positives on generic "config" elements
20
- const connectorConfigs = [
27
+ // Listener configs (inbound) recommend reconnect-forever
28
+ const listenerConfigs = [{ pattern: 'listener-config', name: 'HTTP Listener' }];
29
+ for (const connector of listenerConfigs) {
30
+ const configs = this.select(`//*[local-name()="${connector.pattern}"]`, doc);
31
+ for (const config of configs) {
32
+ const hasReconnection = this.hasAnyReconnection(config);
33
+ if (!hasReconnection) {
34
+ const name = this.getNameAttribute(config) ?? connector.name;
35
+ issues.push(this.createIssue(config, `${connector.name} config "${name}" has no reconnection strategy`, {
36
+ suggestion: 'Add <reconnection><reconnect-forever frequency="5000"/></reconnection> for listener configs — the service should always attempt to reconnect',
37
+ }));
38
+ }
39
+ }
40
+ }
41
+ // Request/outbound configs — recommend bounded reconnect
42
+ const requestConfigs = [
21
43
  { pattern: 'request-config', name: 'HTTP Request' },
22
- { pattern: 'listener-config', name: 'HTTP Listener' },
23
44
  { pattern: 'jms-config', name: 'JMS' },
24
45
  { pattern: 'amqp-config', name: 'AMQP' },
25
46
  { pattern: 'sftp-config', name: 'SFTP' },
26
47
  { pattern: 'ftp-config', name: 'FTP' },
27
48
  { pattern: 'vm-config', name: 'VM' },
28
49
  ];
29
- for (const connector of connectorConfigs) {
50
+ for (const connector of requestConfigs) {
30
51
  const configs = this.select(`//*[local-name()="${connector.pattern}"]`, doc);
31
52
  for (const config of configs) {
32
- // Check for reconnection or reconnect child elements
33
- const hasReconnection = this.exists('.//*[local-name()="reconnection"]', config) ||
34
- this.exists('.//*[local-name()="reconnect"]', config) ||
35
- this.exists('.//*[local-name()="reconnect-forever"]', config);
53
+ const hasReconnection = this.hasAnyReconnection(config);
36
54
  if (!hasReconnection) {
37
55
  const name = this.getNameAttribute(config) ?? connector.name;
38
56
  issues.push(this.createIssue(config, `${connector.name} config "${name}" has no reconnection strategy`, {
39
- suggestion: 'Add <reconnection> or <reconnect-forever> for resilience',
57
+ suggestion: 'Add <reconnection><reconnect count="3" frequency="2000"/></reconnection> inside the connection element for outbound connectors',
40
58
  }));
41
59
  }
42
60
  }
43
61
  }
44
- // Database configs specifically - check for db namespace
62
+ // Database configs check for db namespace
45
63
  const dbConfigs = this.select('//*[local-name()="config" and starts-with(name(), "db:")]', doc);
46
64
  for (const config of dbConfigs) {
47
- const hasReconnection = this.exists('.//*[local-name()="reconnection"]', config) ||
48
- this.exists('.//*[local-name()="reconnect"]', config);
65
+ const hasReconnection = this.hasAnyReconnection(config);
49
66
  if (!hasReconnection) {
50
67
  const name = this.getNameAttribute(config) ?? 'Database';
51
68
  issues.push(this.createIssue(config, `Database config "${name}" has no reconnection strategy`, {
52
- suggestion: 'Add <reconnection> inside the connection element',
69
+ suggestion: 'Add <reconnection><reconnect count="3" frequency="2000"/></reconnection> inside the connection element',
70
+ }));
71
+ }
72
+ }
73
+ // Salesforce configs — check for sfdc-config
74
+ const sfdcConfigs = this.select('//*[local-name()="sfdc-config" or local-name()="config" and starts-with(name(), "salesforce:")]', doc);
75
+ for (const config of sfdcConfigs) {
76
+ const hasReconnection = this.hasAnyReconnection(config);
77
+ if (!hasReconnection) {
78
+ const name = this.getNameAttribute(config) ?? 'Salesforce';
79
+ issues.push(this.createIssue(config, `Salesforce config "${name}" has no reconnection strategy`, {
80
+ suggestion: 'Add <reconnection><reconnect count="3" frequency="2000"/></reconnection> inside the Salesforce connection element',
53
81
  }));
54
82
  }
55
83
  }
56
84
  return issues;
57
85
  }
86
+ hasAnyReconnection(config) {
87
+ return (this.exists('.//*[local-name()="reconnection"]', config) ||
88
+ this.exists('.//*[local-name()="reconnect"]', config) ||
89
+ this.exists('.//*[local-name()="reconnect-forever"]', config));
90
+ }
58
91
  }
59
92
  exports.ReconnectionStrategyRule = ReconnectionStrategyRule;
60
93
  //# sourceMappingURL=ReconnectionStrategyRule.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ReconnectionStrategyRule.js","sourceRoot":"","sources":["../../../../src/rules/performance/ReconnectionStrategyRule.ts"],"names":[],"mappings":";;;AACA,+CAA4C;AAE5C;;;;GAIG;AACH,MAAa,wBAAyB,SAAQ,mBAAQ;IACpD,EAAE,GAAG,SAAS,CAAC;IACf,IAAI,GAAG,uBAAuB,CAAC;IAC/B,WAAW,GAAG,2DAA2D,CAAC;IAC1E,QAAQ,GAAG,SAAkB,CAAC;IAC9B,QAAQ,GAAG,aAAsB,CAAC;IAElC,QAAQ,CAAC,GAAa,EAAE,QAA2B;QACjD,MAAM,MAAM,GAAY,EAAE,CAAC;QAE3B,8EAA8E;QAC9E,qFAAqF;QACrF,MAAM,gBAAgB,GAAG;YACvB,EAAE,OAAO,EAAE,gBAAgB,EAAE,IAAI,EAAE,cAAc,EAAE;YACnD,EAAE,OAAO,EAAE,iBAAiB,EAAE,IAAI,EAAE,eAAe,EAAE;YACrD,EAAE,OAAO,EAAE,YAAY,EAAE,IAAI,EAAE,KAAK,EAAE;YACtC,EAAE,OAAO,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,EAAE;YACxC,EAAE,OAAO,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,EAAE;YACxC,EAAE,OAAO,EAAE,YAAY,EAAE,IAAI,EAAE,KAAK,EAAE;YACtC,EAAE,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,IAAI,EAAE;SACrC,CAAC;QAEF,KAAK,MAAM,SAAS,IAAI,gBAAgB,EAAE,CAAC;YACzC,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,qBAAqB,SAAS,CAAC,OAAO,IAAI,EAAE,GAAG,CAAC,CAAC;YAE7E,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;gBAC7B,qDAAqD;gBACrD,MAAM,eAAe,GACnB,IAAI,CAAC,MAAM,CAAC,mCAAmC,EAAE,MAAM,CAAC;oBACxD,IAAI,CAAC,MAAM,CAAC,gCAAgC,EAAE,MAAM,CAAC;oBACrD,IAAI,CAAC,MAAM,CAAC,wCAAwC,EAAE,MAAM,CAAC,CAAC;gBAEhE,IAAI,CAAC,eAAe,EAAE,CAAC;oBACrB,MAAM,IAAI,GAAG,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,IAAI,SAAS,CAAC,IAAI,CAAC;oBAC7D,MAAM,CAAC,IAAI,CACT,IAAI,CAAC,WAAW,CACd,MAAM,EACN,GAAG,SAAS,CAAC,IAAI,YAAY,IAAI,gCAAgC,EACjE;wBACE,UAAU,EAAE,0DAA0D;qBACvE,CACF,CACF,CAAC;gBACJ,CAAC;YACH,CAAC;QACH,CAAC;QAED,yDAAyD;QACzD,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,CAAC,2DAA2D,EAAE,GAAG,CAAC,CAAC;QAChG,KAAK,MAAM,MAAM,IAAI,SAAS,EAAE,CAAC;YAC/B,MAAM,eAAe,GACnB,IAAI,CAAC,MAAM,CAAC,mCAAmC,EAAE,MAAM,CAAC;gBACxD,IAAI,CAAC,MAAM,CAAC,gCAAgC,EAAE,MAAM,CAAC,CAAC;YAExD,IAAI,CAAC,eAAe,EAAE,CAAC;gBACrB,MAAM,IAAI,GAAG,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,IAAI,UAAU,CAAC;gBACzD,MAAM,CAAC,IAAI,CACT,IAAI,CAAC,WAAW,CAAC,MAAM,EAAE,oBAAoB,IAAI,gCAAgC,EAAE;oBACjF,UAAU,EAAE,kDAAkD;iBAC/D,CAAC,CACH,CAAC;YACJ,CAAC;QACH,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;CACF;AAlED,4DAkEC"}
1
+ {"version":3,"file":"ReconnectionStrategyRule.js","sourceRoot":"","sources":["../../../../src/rules/performance/ReconnectionStrategyRule.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,36 @@
1
+ import { ValidationContext, Issue, IssueType } from '../../types';
2
+ import { BaseRule } from '../base/BaseRule';
3
+ /**
4
+ * SEC-007: Connector Credentials Secured
5
+ *
6
+ * Salesforce, NetSuite, Database, and other connector configurations must
7
+ * use `${secure::...}` (not plain `${...}`) for credential attributes.
8
+ *
9
+ * Plain property placeholders like `${sf.password}` store the value in
10
+ * clear text in property files. The `${secure::...}` prefix ensures the
11
+ * value is read from an encrypted secure properties file.
12
+ *
13
+ * Covered connectors and attributes:
14
+ * - Salesforce: username, password, securityToken, consumerKey, consumerSecret
15
+ * - NetSuite: consumerKey, consumerSecret, tokenId, tokenSecret
16
+ * - Database: password, user (when not using connection URL)
17
+ * - HTTP Basic Auth: username, password
18
+ * - SMTP: password
19
+ */
20
+ export declare class ConnectorCredentialsSecuredRule extends BaseRule {
21
+ id: string;
22
+ name: string;
23
+ description: string;
24
+ severity: "error";
25
+ category: "security";
26
+ issueType: IssueType;
27
+ /**
28
+ * Map of element local-name patterns to their sensitive attributes.
29
+ * We match on local-name() to be namespace-agnostic.
30
+ */
31
+ private readonly CONNECTOR_SENSITIVE_ATTRS;
32
+ validate(doc: Document, _context: ValidationContext): Issue[];
33
+ private findSensitiveAttrs;
34
+ private extractPropertyName;
35
+ }
36
+ //# sourceMappingURL=ConnectorCredentialsSecuredRule.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ConnectorCredentialsSecuredRule.d.ts","sourceRoot":"","sources":["../../../../src/rules/security/ConnectorCredentialsSecuredRule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAClE,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE5C;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,+BAAgC,SAAQ,QAAQ;IAC3D,EAAE,SAAa;IACf,IAAI,SAAmC;IACvC,WAAW,SAAsE;IACjF,QAAQ,EAAG,OAAO,CAAU;IAC5B,QAAQ,EAAG,UAAU,CAAU;IAC/B,SAAS,EAAE,SAAS,CAAmB;IAEvC;;;OAGG;IACH,OAAO,CAAC,QAAQ,CAAC,yBAAyB,CA+BxC;IAEF,QAAQ,CAAC,GAAG,EAAE,QAAQ,EAAE,QAAQ,EAAE,iBAAiB,GAAG,KAAK,EAAE;IA4D7D,OAAO,CAAC,kBAAkB;IAc1B,OAAO,CAAC,mBAAmB;CAI5B"}
@@ -0,0 +1,124 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ConnectorCredentialsSecuredRule = void 0;
4
+ const BaseRule_1 = require("../base/BaseRule");
5
+ /**
6
+ * SEC-007: Connector Credentials Secured
7
+ *
8
+ * Salesforce, NetSuite, Database, and other connector configurations must
9
+ * use `${secure::...}` (not plain `${...}`) for credential attributes.
10
+ *
11
+ * Plain property placeholders like `${sf.password}` store the value in
12
+ * clear text in property files. The `${secure::...}` prefix ensures the
13
+ * value is read from an encrypted secure properties file.
14
+ *
15
+ * Covered connectors and attributes:
16
+ * - Salesforce: username, password, securityToken, consumerKey, consumerSecret
17
+ * - NetSuite: consumerKey, consumerSecret, tokenId, tokenSecret
18
+ * - Database: password, user (when not using connection URL)
19
+ * - HTTP Basic Auth: username, password
20
+ * - SMTP: password
21
+ */
22
+ class ConnectorCredentialsSecuredRule extends BaseRule_1.BaseRule {
23
+ id = 'SEC-007';
24
+ name = 'Connector Credentials Secured';
25
+ description = 'Connector credentials must use ${secure::} property placeholders';
26
+ severity = 'error';
27
+ category = 'security';
28
+ issueType = 'vulnerability';
29
+ /**
30
+ * Map of element local-name patterns to their sensitive attributes.
31
+ * We match on local-name() to be namespace-agnostic.
32
+ */
33
+ CONNECTOR_SENSITIVE_ATTRS = {
34
+ // Salesforce connector
35
+ 'sfdc-config': ['username', 'password', 'securityToken', 'consumerKey', 'consumerSecret'],
36
+ 'salesforce-config': ['username', 'password', 'securityToken', 'consumerKey', 'consumerSecret'],
37
+ 'basic-connection': [
38
+ 'username',
39
+ 'password',
40
+ 'securityToken',
41
+ 'consumerKey',
42
+ 'consumerSecret',
43
+ 'tokenId',
44
+ 'tokenSecret',
45
+ ],
46
+ 'oauth-user-pass-connection': ['consumerKey', 'consumerSecret'],
47
+ 'oauth-jwt-connection': ['consumerKey', 'keyStorePath', 'storePassword'],
48
+ // NetSuite connector (token-based)
49
+ 'token-based-authentication-connection': [
50
+ 'consumerKey',
51
+ 'consumerSecret',
52
+ 'tokenId',
53
+ 'tokenSecret',
54
+ ],
55
+ // Database connector
56
+ 'derby-connection': ['password'],
57
+ 'generic-connection': ['password'],
58
+ 'my-sql-connection': ['password'],
59
+ 'mssql-connection': ['password'],
60
+ 'oracle-connection': ['password'],
61
+ 'data-source-connection': ['password'],
62
+ // SMTP
63
+ 'smtps-connection': ['password'],
64
+ };
65
+ validate(doc, _context) {
66
+ const issues = [];
67
+ const allElements = doc.getElementsByTagName('*');
68
+ for (let i = 0; i < allElements.length; i++) {
69
+ const element = allElements[i];
70
+ const localName = element.localName;
71
+ const sensitiveAttrs = this.findSensitiveAttrs(localName);
72
+ if (!sensitiveAttrs) {
73
+ continue;
74
+ }
75
+ for (const attrName of sensitiveAttrs) {
76
+ const value = element.getAttribute(attrName);
77
+ if (!value || value.trim() === '') {
78
+ continue;
79
+ }
80
+ // Skip DataWeave expressions — they're computed at runtime
81
+ if (value.startsWith('#[')) {
82
+ continue;
83
+ }
84
+ // Must use ${secure::...} — plain ${...} is not sufficient
85
+ if (value.includes('${') && !value.includes('${secure::')) {
86
+ issues.push(this.createIssue(element, `Credential "${attrName}" uses plain property placeholder — must use \${secure::} for encryption`, {
87
+ suggestion: `Replace ${value} with \${secure::${this.extractPropertyName(value)}}`,
88
+ }));
89
+ }
90
+ // Hardcoded value — no placeholder at all
91
+ if (!value.includes('${') && !value.startsWith('#[')) {
92
+ // Ignore booleans and numbers
93
+ if (value === 'true' || value === 'false' || !isNaN(Number(value))) {
94
+ continue;
95
+ }
96
+ issues.push(this.createIssue(element, `Credential "${attrName}" is hardcoded — must use \${secure::} property placeholder`, {
97
+ severity: 'error',
98
+ suggestion: `Use \${secure::${localName}.${attrName}} instead of the hardcoded value`,
99
+ }));
100
+ }
101
+ }
102
+ }
103
+ return issues;
104
+ }
105
+ findSensitiveAttrs(localName) {
106
+ // Exact match first
107
+ if (this.CONNECTOR_SENSITIVE_ATTRS[localName]) {
108
+ return this.CONNECTOR_SENSITIVE_ATTRS[localName];
109
+ }
110
+ // Partial match for compound names
111
+ for (const [key, attrs] of Object.entries(this.CONNECTOR_SENSITIVE_ATTRS)) {
112
+ if (localName.includes(key)) {
113
+ return attrs;
114
+ }
115
+ }
116
+ return undefined;
117
+ }
118
+ extractPropertyName(placeholder) {
119
+ const match = /\$\{([^}]+)\}/.exec(placeholder);
120
+ return match ? match[1] : placeholder;
121
+ }
122
+ }
123
+ exports.ConnectorCredentialsSecuredRule = ConnectorCredentialsSecuredRule;
124
+ //# sourceMappingURL=ConnectorCredentialsSecuredRule.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ConnectorCredentialsSecuredRule.js","sourceRoot":"","sources":["../../../../src/rules/security/ConnectorCredentialsSecuredRule.ts"],"names":[],"mappings":"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"}
@@ -4,6 +4,10 @@ import { BaseRule } from '../base/BaseRule';
4
4
  * MULE-201: Hardcoded Credentials
5
5
  *
6
6
  * Passwords and secrets should use secure property placeholders.
7
+ *
8
+ * Enhanced to cover Salesforce connector-specific sensitive attributes
9
+ * (consumerKey, storePassword, tokenId, tokenSecret) and NetSuite
10
+ * OAuth attributes (consumerSecret, tokenKey, tokenSecret).
7
11
  */
8
12
  export declare class HardcodedCredentialsRule extends BaseRule {
9
13
  id: string;
@@ -1 +1 @@
1
- {"version":3,"file":"HardcodedCredentialsRule.d.ts","sourceRoot":"","sources":["../../../../src/rules/security/HardcodedCredentialsRule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAClE,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE5C;;;;GAIG;AACH,qBAAa,wBAAyB,SAAQ,QAAQ;IACpD,EAAE,SAAc;IAChB,IAAI,SAA2B;IAC/B,WAAW,SAA+E;IAC1F,QAAQ,EAAG,OAAO,CAAU;IAC5B,QAAQ,EAAG,UAAU,CAAU;IAC/B,SAAS,EAAE,SAAS,CAAmB;IAEvC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAU9B;IAEF,QAAQ,CAAC,GAAG,EAAE,QAAQ,EAAE,QAAQ,EAAE,iBAAiB,GAAG,KAAK,EAAE;IA+B7D,OAAO,CAAC,oBAAoB;IAI5B,OAAO,CAAC,WAAW;CAoBpB"}
1
+ {"version":3,"file":"HardcodedCredentialsRule.d.ts","sourceRoot":"","sources":["../../../../src/rules/security/HardcodedCredentialsRule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAClE,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE5C;;;;;;;;GAQG;AACH,qBAAa,wBAAyB,SAAQ,QAAQ;IACpD,EAAE,SAAc;IAChB,IAAI,SAA2B;IAC/B,WAAW,SAA+E;IAC1F,QAAQ,EAAG,OAAO,CAAU;IAC5B,QAAQ,EAAG,UAAU,CAAU;IAC/B,SAAS,EAAE,SAAS,CAAmB;IAEvC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAqB9B;IAEF,QAAQ,CAAC,GAAG,EAAE,QAAQ,EAAE,QAAQ,EAAE,iBAAiB,GAAG,KAAK,EAAE;IA+B7D,OAAO,CAAC,oBAAoB;IAI5B,OAAO,CAAC,WAAW;CAoBpB"}
@@ -6,6 +6,10 @@ const BaseRule_1 = require("../base/BaseRule");
6
6
  * MULE-201: Hardcoded Credentials
7
7
  *
8
8
  * Passwords and secrets should use secure property placeholders.
9
+ *
10
+ * Enhanced to cover Salesforce connector-specific sensitive attributes
11
+ * (consumerKey, storePassword, tokenId, tokenSecret) and NetSuite
12
+ * OAuth attributes (consumerSecret, tokenKey, tokenSecret).
9
13
  */
10
14
  class HardcodedCredentialsRule extends BaseRule_1.BaseRule {
11
15
  id = 'MULE-201';
@@ -24,6 +28,17 @@ class HardcodedCredentialsRule extends BaseRule_1.BaseRule {
24
28
  'token',
25
29
  'accessToken',
26
30
  'privateKey',
31
+ // Salesforce connector attrs
32
+ 'consumerKey',
33
+ 'consumerSecret',
34
+ 'storePassword',
35
+ 'tokenId',
36
+ 'tokenSecret',
37
+ // NetSuite OAuth attrs
38
+ 'tokenKey',
39
+ // Keystore/truststore
40
+ 'keyPassword',
41
+ 'keystorePassword',
27
42
  ];
28
43
  validate(doc, _context) {
29
44
  const issues = [];
@@ -1 +1 @@
1
- {"version":3,"file":"HardcodedCredentialsRule.js","sourceRoot":"","sources":["../../../../src/rules/security/HardcodedCredentialsRule.ts"],"names":[],"mappings":";;;AACA,+CAA4C;AAE5C;;;;GAIG;AACH,MAAa,wBAAyB,SAAQ,mBAAQ;IACpD,EAAE,GAAG,UAAU,CAAC;IAChB,IAAI,GAAG,uBAAuB,CAAC;IAC/B,WAAW,GAAG,2EAA2E,CAAC;IAC1F,QAAQ,GAAG,OAAgB,CAAC;IAC5B,QAAQ,GAAG,UAAmB,CAAC;IAC/B,SAAS,GAAc,eAAe,CAAC;IAEtB,eAAe,GAAG;QACjC,UAAU;QACV,QAAQ;QACR,cAAc;QACd,eAAe;QACf,QAAQ;QACR,SAAS;QACT,OAAO;QACP,aAAa;QACb,YAAY;KACb,CAAC;IAEF,QAAQ,CAAC,GAAa,EAAE,QAA2B;QACjD,MAAM,MAAM,GAAY,EAAE,CAAC;QAC3B,MAAM,WAAW,GAAG,GAAG,CAAC,oBAAoB,CAAC,GAAG,CAAC,CAAC;QAElD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,WAAW,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YAC5C,MAAM,OAAO,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC;YAC/B,MAAM,KAAK,GAAG,OAAO,CAAC,UAAU,CAAC;YAEjC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;gBACtC,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;gBACtB,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;gBACzC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;gBAEzB,yCAAyC;gBACzC,IAAI,IAAI,CAAC,oBAAoB,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,EAAE,CAAC;oBACnE,MAAM,CAAC,IAAI,CACT,IAAI,CAAC,WAAW,CACd,OAAO,EACP,aAAa,IAAI,CAAC,IAAI,0CAA0C,EAChE;wBACE,UAAU,EAAE,kBAAkB,IAAI,CAAC,IAAI,8BAA8B;qBACtE,CACF,CACF,CAAC;gBACJ,CAAC;YACH,CAAC;QACH,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;IAEO,oBAAoB,CAAC,QAAgB;QAC3C,OAAO,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,SAAS,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;IAC9F,CAAC;IAEO,WAAW,CAAC,KAAa;QAC/B,iCAAiC;QACjC,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;YAClC,OAAO,KAAK,CAAC;QACf,CAAC;QAED,sEAAsE;QACtE,IAAI,KAAK,KAAK,MAAM,IAAI,KAAK,KAAK,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC;YACnE,OAAO,KAAK,CAAC;QACf,CAAC;QAED,+DAA+D;QAC/D,yDAAyD;QACzD,IAAI,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;YACnD,OAAO,KAAK,CAAC;QACf,CAAC;QAED,4DAA4D;QAC5D,OAAO,IAAI,CAAC;IACd,CAAC;CACF;AA3ED,4DA2EC"}
1
+ {"version":3,"file":"HardcodedCredentialsRule.js","sourceRoot":"","sources":["../../../../src/rules/security/HardcodedCredentialsRule.ts"],"names":[],"mappings":";;;AACA,+CAA4C;AAE5C;;;;;;;;GAQG;AACH,MAAa,wBAAyB,SAAQ,mBAAQ;IACpD,EAAE,GAAG,UAAU,CAAC;IAChB,IAAI,GAAG,uBAAuB,CAAC;IAC/B,WAAW,GAAG,2EAA2E,CAAC;IAC1F,QAAQ,GAAG,OAAgB,CAAC;IAC5B,QAAQ,GAAG,UAAmB,CAAC;IAC/B,SAAS,GAAc,eAAe,CAAC;IAEtB,eAAe,GAAG;QACjC,UAAU;QACV,QAAQ;QACR,cAAc;QACd,eAAe;QACf,QAAQ;QACR,SAAS;QACT,OAAO;QACP,aAAa;QACb,YAAY;QACZ,6BAA6B;QAC7B,aAAa;QACb,gBAAgB;QAChB,eAAe;QACf,SAAS;QACT,aAAa;QACb,uBAAuB;QACvB,UAAU;QACV,sBAAsB;QACtB,aAAa;QACb,kBAAkB;KACnB,CAAC;IAEF,QAAQ,CAAC,GAAa,EAAE,QAA2B;QACjD,MAAM,MAAM,GAAY,EAAE,CAAC;QAC3B,MAAM,WAAW,GAAG,GAAG,CAAC,oBAAoB,CAAC,GAAG,CAAC,CAAC;QAElD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,WAAW,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YAC5C,MAAM,OAAO,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC;YAC/B,MAAM,KAAK,GAAG,OAAO,CAAC,UAAU,CAAC;YAEjC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;gBACtC,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;gBACtB,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;gBACzC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;gBAEzB,yCAAyC;gBACzC,IAAI,IAAI,CAAC,oBAAoB,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,EAAE,CAAC;oBACnE,MAAM,CAAC,IAAI,CACT,IAAI,CAAC,WAAW,CACd,OAAO,EACP,aAAa,IAAI,CAAC,IAAI,0CAA0C,EAChE;wBACE,UAAU,EAAE,kBAAkB,IAAI,CAAC,IAAI,8BAA8B;qBACtE,CACF,CACF,CAAC;gBACJ,CAAC;YACH,CAAC;QACH,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;IAEO,oBAAoB,CAAC,QAAgB;QAC3C,OAAO,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,SAAS,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;IAC9F,CAAC;IAEO,WAAW,CAAC,KAAa;QAC/B,iCAAiC;QACjC,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;YAClC,OAAO,KAAK,CAAC;QACf,CAAC;QAED,sEAAsE;QACtE,IAAI,KAAK,KAAK,MAAM,IAAI,KAAK,KAAK,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC;YACnE,OAAO,KAAK,CAAC;QACf,CAAC;QAED,+DAA+D;QAC/D,yDAAyD;QACzD,IAAI,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;YACnD,OAAO,KAAK,CAAC;QACf,CAAC;QAED,4DAA4D;QAC5D,OAAO,IAAI,CAAC;IACd,CAAC;CACF;AAtFD,4DAsFC"}
@@ -0,0 +1,25 @@
1
+ import { ValidationContext, Issue, IssueType } from '../../types';
2
+ import { BaseRule } from '../base/BaseRule';
3
+ /**
4
+ * SEC-010: Secure Properties Encryption Algorithm
5
+ *
6
+ * When `<secure-properties:config>` specifies an encryption algorithm, it
7
+ * should use a strong algorithm (AES, Blowfish) and not a weak or
8
+ * deprecated one (DES, RC2, RC4).
9
+ *
10
+ * Also validates that when secure properties are used, the `encrypt`
11
+ * element exists (i.e., properties are actually encrypted, not just
12
+ * marked as "secure" with no encryption).
13
+ */
14
+ export declare class SecurePropertiesEncryptionRule extends BaseRule {
15
+ id: string;
16
+ name: string;
17
+ description: string;
18
+ severity: "warning";
19
+ category: "security";
20
+ issueType: IssueType;
21
+ private readonly WEAK_ALGORITHMS;
22
+ private readonly STRONG_ALGORITHMS;
23
+ validate(doc: Document, _context: ValidationContext): Issue[];
24
+ }
25
+ //# sourceMappingURL=SecurePropertiesEncryptionRule.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SecurePropertiesEncryptionRule.d.ts","sourceRoot":"","sources":["../../../../src/rules/security/SecurePropertiesEncryptionRule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAClE,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE5C;;;;;;;;;;GAUG;AACH,qBAAa,8BAA+B,SAAQ,QAAQ;IAC1D,EAAE,SAAa;IACf,IAAI,SAAkC;IACtC,WAAW,SAA6D;IACxE,QAAQ,EAAG,SAAS,CAAU;IAC9B,QAAQ,EAAG,UAAU,CAAU;IAC/B,SAAS,EAAE,SAAS,CAAmB;IAEvC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAmC;IACnE,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAuB;IAEzD,QAAQ,CAAC,GAAG,EAAE,QAAQ,EAAE,QAAQ,EAAE,iBAAiB,GAAG,KAAK,EAAE;CAsD9D"}
@@ -0,0 +1,59 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SecurePropertiesEncryptionRule = void 0;
4
+ const BaseRule_1 = require("../base/BaseRule");
5
+ /**
6
+ * SEC-010: Secure Properties Encryption Algorithm
7
+ *
8
+ * When `<secure-properties:config>` specifies an encryption algorithm, it
9
+ * should use a strong algorithm (AES, Blowfish) and not a weak or
10
+ * deprecated one (DES, RC2, RC4).
11
+ *
12
+ * Also validates that when secure properties are used, the `encrypt`
13
+ * element exists (i.e., properties are actually encrypted, not just
14
+ * marked as "secure" with no encryption).
15
+ */
16
+ class SecurePropertiesEncryptionRule extends BaseRule_1.BaseRule {
17
+ id = 'SEC-010';
18
+ name = 'Secure Properties Encryption';
19
+ description = 'Secure properties must use strong encryption algorithms';
20
+ severity = 'warning';
21
+ category = 'security';
22
+ issueType = 'vulnerability';
23
+ WEAK_ALGORITHMS = ['DES', 'DESede', 'RC2', 'RC4'];
24
+ STRONG_ALGORITHMS = ['AES', 'Blowfish'];
25
+ validate(doc, _context) {
26
+ const issues = [];
27
+ // Match secure-properties:config or secure-configuration-properties
28
+ const secureConfigs = this.select('//*[local-name()="config" and contains(namespace-uri(), "secure-properties")] | ' +
29
+ '//*[local-name()="secure-configuration-properties"]', doc);
30
+ for (const config of secureConfigs) {
31
+ // Check for encrypt element presence
32
+ const encryptElements = this.select('.//*[local-name()="encrypt"]', config);
33
+ if (encryptElements.length === 0) {
34
+ const docName = this.getDocName(config) ?? 'Secure Properties Config';
35
+ issues.push(this.createIssue(config, `"${docName}" has no <encrypt> element — properties may not be encrypted`, {
36
+ severity: 'warning',
37
+ suggestion: 'Add <secure-properties:encrypt algorithm="AES" mode="CBC"/> to enable encryption',
38
+ }));
39
+ continue;
40
+ }
41
+ // Check encryption algorithm
42
+ for (const encrypt of encryptElements) {
43
+ const algorithm = this.getAttribute(encrypt, 'algorithm');
44
+ if (!algorithm) {
45
+ continue;
46
+ }
47
+ if (this.WEAK_ALGORITHMS.includes(algorithm)) {
48
+ issues.push(this.createIssue(encrypt, `Weak encryption algorithm "${algorithm}" — use ${this.STRONG_ALGORITHMS.join(' or ')} instead`, {
49
+ severity: 'error',
50
+ suggestion: `Replace algorithm="${algorithm}" with algorithm="AES"`,
51
+ }));
52
+ }
53
+ }
54
+ }
55
+ return issues;
56
+ }
57
+ }
58
+ exports.SecurePropertiesEncryptionRule = SecurePropertiesEncryptionRule;
59
+ //# sourceMappingURL=SecurePropertiesEncryptionRule.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SecurePropertiesEncryptionRule.js","sourceRoot":"","sources":["../../../../src/rules/security/SecurePropertiesEncryptionRule.ts"],"names":[],"mappings":";;;AACA,+CAA4C;AAE5C;;;;;;;;;;GAUG;AACH,MAAa,8BAA+B,SAAQ,mBAAQ;IAC1D,EAAE,GAAG,SAAS,CAAC;IACf,IAAI,GAAG,8BAA8B,CAAC;IACtC,WAAW,GAAG,yDAAyD,CAAC;IACxE,QAAQ,GAAG,SAAkB,CAAC;IAC9B,QAAQ,GAAG,UAAmB,CAAC;IAC/B,SAAS,GAAc,eAAe,CAAC;IAEtB,eAAe,GAAG,CAAC,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC;IAClD,iBAAiB,GAAG,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC;IAEzD,QAAQ,CAAC,GAAa,EAAE,QAA2B;QACjD,MAAM,MAAM,GAAY,EAAE,CAAC;QAE3B,oEAAoE;QACpE,MAAM,aAAa,GAAG,IAAI,CAAC,MAAM,CAC/B,kFAAkF;YAChF,qDAAqD,EACvD,GAAG,CACJ,CAAC;QAEF,KAAK,MAAM,MAAM,IAAI,aAAa,EAAE,CAAC;YACnC,qCAAqC;YACrC,MAAM,eAAe,GAAG,IAAI,CAAC,MAAM,CAAC,8BAA8B,EAAE,MAAkB,CAAC,CAAC;YAExF,IAAI,eAAe,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACjC,MAAM,OAAO,GAAG,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,0BAA0B,CAAC;gBACtE,MAAM,CAAC,IAAI,CACT,IAAI,CAAC,WAAW,CACd,MAAM,EACN,IAAI,OAAO,8DAA8D,EACzE;oBACE,QAAQ,EAAE,SAAS;oBACnB,UAAU,EACR,kFAAkF;iBACrF,CACF,CACF,CAAC;gBACF,SAAS;YACX,CAAC;YAED,6BAA6B;YAC7B,KAAK,MAAM,OAAO,IAAI,eAAe,EAAE,CAAC;gBACtC,MAAM,SAAS,GAAG,IAAI,CAAC,YAAY,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;gBAC1D,IAAI,CAAC,SAAS,EAAE,CAAC;oBACf,SAAS;gBACX,CAAC;gBAED,IAAI,IAAI,CAAC,eAAe,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;oBAC7C,MAAM,CAAC,IAAI,CACT,IAAI,CAAC,WAAW,CACd,OAAO,EACP,8BAA8B,SAAS,WAAW,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,EAC/F;wBACE,QAAQ,EAAE,OAAO;wBACjB,UAAU,EAAE,sBAAsB,SAAS,wBAAwB;qBACpE,CACF,CACF,CAAC;gBACJ,CAAC;YACH,CAAC;QACH,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;CACF;AAjED,wEAiEC"}
@@ -0,0 +1,23 @@
1
+ import { ValidationContext, Issue, IssueType } from '../../types';
2
+ import { BaseRule } from '../base/BaseRule';
3
+ /**
4
+ * SEC-008: Secure Properties Key Configuration
5
+ *
6
+ * The `<secure-properties:config>` element's `key` attribute must use a
7
+ * property placeholder (`${...}`) — never a hardcoded encryption key.
8
+ *
9
+ * A hardcoded key in the XML defeats the purpose of encryption because
10
+ * anyone with access to the source code can decrypt all secure properties.
11
+ * The key should be injected via a system property or environment variable
12
+ * at deployment time (e.g., `-Dsecure.key=...` in the Mule runtime args).
13
+ */
14
+ export declare class SecurePropertiesKeyRule extends BaseRule {
15
+ id: string;
16
+ name: string;
17
+ description: string;
18
+ severity: "error";
19
+ category: "security";
20
+ issueType: IssueType;
21
+ validate(doc: Document, _context: ValidationContext): Issue[];
22
+ }
23
+ //# sourceMappingURL=SecurePropertiesKeyRule.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SecurePropertiesKeyRule.d.ts","sourceRoot":"","sources":["../../../../src/rules/security/SecurePropertiesKeyRule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAClE,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE5C;;;;;;;;;;GAUG;AACH,qBAAa,uBAAwB,SAAQ,QAAQ;IACnD,EAAE,SAAa;IACf,IAAI,SAA2B;IAC/B,WAAW,SAA4D;IACvE,QAAQ,EAAG,OAAO,CAAU;IAC5B,QAAQ,EAAG,UAAU,CAAU;IAC/B,SAAS,EAAE,SAAS,CAAmB;IAEvC,QAAQ,CAAC,GAAG,EAAE,QAAQ,EAAE,QAAQ,EAAE,iBAAiB,GAAG,KAAK,EAAE;CAkC9D"}