@sfdxy/mule-lint 1.20.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 (134) hide show
  1. package/README.md +63 -17
  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 +22 -0
  7. package/dist/src/engine/LintEngine.d.ts.map +1 -1
  8. package/dist/src/engine/LintEngine.js +105 -18
  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 +11 -4
  31. package/dist/src/rules/dataweave/DataWeaveRules.d.ts.map +1 -1
  32. package/dist/src/rules/dataweave/DataWeaveRules.js +20 -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/ErrorHandlerTypeCoverageRule.d.ts +28 -0
  43. package/dist/src/rules/error-handling/ErrorHandlerTypeCoverageRule.d.ts.map +1 -0
  44. package/dist/src/rules/error-handling/ErrorHandlerTypeCoverageRule.js +70 -0
  45. package/dist/src/rules/error-handling/ErrorHandlerTypeCoverageRule.js.map +1 -0
  46. package/dist/src/rules/error-handling/ErrorResponseStructureRule.d.ts +23 -0
  47. package/dist/src/rules/error-handling/ErrorResponseStructureRule.d.ts.map +1 -0
  48. package/dist/src/rules/error-handling/ErrorResponseStructureRule.js +73 -0
  49. package/dist/src/rules/error-handling/ErrorResponseStructureRule.js.map +1 -0
  50. package/dist/src/rules/error-handling/GenericErrorRule.d.ts +15 -3
  51. package/dist/src/rules/error-handling/GenericErrorRule.d.ts.map +1 -1
  52. package/dist/src/rules/error-handling/GenericErrorRule.js +58 -18
  53. package/dist/src/rules/error-handling/GenericErrorRule.js.map +1 -1
  54. package/dist/src/rules/error-handling/GlobalErrorHandlerRule.d.ts +14 -15
  55. package/dist/src/rules/error-handling/GlobalErrorHandlerRule.d.ts.map +1 -1
  56. package/dist/src/rules/error-handling/GlobalErrorHandlerRule.js +59 -38
  57. package/dist/src/rules/error-handling/GlobalErrorHandlerRule.js.map +1 -1
  58. package/dist/src/rules/error-handling/TryScopeRule.d.ts +5 -0
  59. package/dist/src/rules/error-handling/TryScopeRule.d.ts.map +1 -1
  60. package/dist/src/rules/error-handling/TryScopeRule.js +30 -7
  61. package/dist/src/rules/error-handling/TryScopeRule.js.map +1 -1
  62. package/dist/src/rules/http/ConnectionIdleTimeoutRule.d.ts +27 -0
  63. package/dist/src/rules/http/ConnectionIdleTimeoutRule.d.ts.map +1 -0
  64. package/dist/src/rules/http/ConnectionIdleTimeoutRule.js +46 -0
  65. package/dist/src/rules/http/ConnectionIdleTimeoutRule.js.map +1 -0
  66. package/dist/src/rules/index.d.ts +1 -1
  67. package/dist/src/rules/index.d.ts.map +1 -1
  68. package/dist/src/rules/index.js +50 -8
  69. package/dist/src/rules/index.js.map +1 -1
  70. package/dist/src/rules/logging/LoggerPayloadRule.d.ts +15 -0
  71. package/dist/src/rules/logging/LoggerPayloadRule.d.ts.map +1 -1
  72. package/dist/src/rules/logging/LoggerPayloadRule.js +48 -4
  73. package/dist/src/rules/logging/LoggerPayloadRule.js.map +1 -1
  74. package/dist/src/rules/operations/FlowRefTargetExistsRule.d.ts +23 -0
  75. package/dist/src/rules/operations/FlowRefTargetExistsRule.d.ts.map +1 -0
  76. package/dist/src/rules/operations/FlowRefTargetExistsRule.js +58 -0
  77. package/dist/src/rules/operations/FlowRefTargetExistsRule.js.map +1 -0
  78. package/dist/src/rules/operations/UnusedFlowRule.d.ts +20 -0
  79. package/dist/src/rules/operations/UnusedFlowRule.d.ts.map +1 -1
  80. package/dist/src/rules/operations/UnusedFlowRule.js +73 -7
  81. package/dist/src/rules/operations/UnusedFlowRule.js.map +1 -1
  82. package/dist/src/rules/operations/UnusedVariableRule.d.ts +31 -0
  83. package/dist/src/rules/operations/UnusedVariableRule.d.ts.map +1 -0
  84. package/dist/src/rules/operations/UnusedVariableRule.js +103 -0
  85. package/dist/src/rules/operations/UnusedVariableRule.js.map +1 -0
  86. package/dist/src/rules/performance/ListenerReconnectForeverRule.d.ts +28 -0
  87. package/dist/src/rules/performance/ListenerReconnectForeverRule.d.ts.map +1 -0
  88. package/dist/src/rules/performance/ListenerReconnectForeverRule.js +56 -0
  89. package/dist/src/rules/performance/ListenerReconnectForeverRule.js.map +1 -0
  90. package/dist/src/rules/performance/ReconnectionStrategyRule.d.ts +7 -4
  91. package/dist/src/rules/performance/ReconnectionStrategyRule.d.ts.map +1 -1
  92. package/dist/src/rules/performance/ReconnectionStrategyRule.js +44 -24
  93. package/dist/src/rules/performance/ReconnectionStrategyRule.js.map +1 -1
  94. package/dist/src/rules/security/ConnectorCredentialsSecuredRule.d.ts +36 -0
  95. package/dist/src/rules/security/ConnectorCredentialsSecuredRule.d.ts.map +1 -0
  96. package/dist/src/rules/security/ConnectorCredentialsSecuredRule.js +124 -0
  97. package/dist/src/rules/security/ConnectorCredentialsSecuredRule.js.map +1 -0
  98. package/dist/src/rules/security/HardcodedCredentialsRule.d.ts +4 -0
  99. package/dist/src/rules/security/HardcodedCredentialsRule.d.ts.map +1 -1
  100. package/dist/src/rules/security/HardcodedCredentialsRule.js +15 -0
  101. package/dist/src/rules/security/HardcodedCredentialsRule.js.map +1 -1
  102. package/dist/src/rules/security/SecurePropertiesEncryptionRule.d.ts +25 -0
  103. package/dist/src/rules/security/SecurePropertiesEncryptionRule.d.ts.map +1 -0
  104. package/dist/src/rules/security/SecurePropertiesEncryptionRule.js +59 -0
  105. package/dist/src/rules/security/SecurePropertiesEncryptionRule.js.map +1 -0
  106. package/dist/src/rules/security/SecurePropertiesKeyRule.d.ts +23 -0
  107. package/dist/src/rules/security/SecurePropertiesKeyRule.d.ts.map +1 -0
  108. package/dist/src/rules/security/SecurePropertiesKeyRule.js +45 -0
  109. package/dist/src/rules/security/SecurePropertiesKeyRule.js.map +1 -0
  110. package/dist/src/rules/security/TlsKeystorePasswordRule.d.ts +25 -0
  111. package/dist/src/rules/security/TlsKeystorePasswordRule.d.ts.map +1 -0
  112. package/dist/src/rules/security/TlsKeystorePasswordRule.js +63 -0
  113. package/dist/src/rules/security/TlsKeystorePasswordRule.js.map +1 -0
  114. package/dist/src/rules/standards/ApikitRouteVariableConsistencyRule.d.ts +26 -0
  115. package/dist/src/rules/standards/ApikitRouteVariableConsistencyRule.d.ts.map +1 -0
  116. package/dist/src/rules/standards/ApikitRouteVariableConsistencyRule.js +61 -0
  117. package/dist/src/rules/standards/ApikitRouteVariableConsistencyRule.js.map +1 -0
  118. package/dist/src/rules/standards/ConfigPropertiesOrderingRule.d.ts +34 -0
  119. package/dist/src/rules/standards/ConfigPropertiesOrderingRule.d.ts.map +1 -0
  120. package/dist/src/rules/standards/ConfigPropertiesOrderingRule.js +76 -0
  121. package/dist/src/rules/standards/ConfigPropertiesOrderingRule.js.map +1 -0
  122. package/dist/src/rules/standards/MissingEnvPropertiesDeclarationRule.d.ts +25 -0
  123. package/dist/src/rules/standards/MissingEnvPropertiesDeclarationRule.d.ts.map +1 -0
  124. package/dist/src/rules/standards/MissingEnvPropertiesDeclarationRule.js +111 -0
  125. package/dist/src/rules/standards/MissingEnvPropertiesDeclarationRule.js.map +1 -0
  126. package/dist/src/rules/yaml/YamlRules.d.ts +6 -2
  127. package/dist/src/rules/yaml/YamlRules.d.ts.map +1 -1
  128. package/dist/src/rules/yaml/YamlRules.js +15 -11
  129. package/dist/src/rules/yaml/YamlRules.js.map +1 -1
  130. package/dist/src/types/Rule.d.ts +13 -0
  131. package/dist/src/types/Rule.d.ts.map +1 -1
  132. package/docs/best-practices/rules-catalog.md +337 -29
  133. package/docs/linter/architecture.md +119 -64
  134. package/package.json +1 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FlowRefTargetExistsRule.js","sourceRoot":"","sources":["../../../../src/rules/operations/FlowRefTargetExistsRule.ts"],"names":[],"mappings":";;;AACA,+CAA4C;AAE5C;;;;;;;;;;GAUG;AACH,MAAa,uBAAwB,SAAQ,mBAAQ;IACnD,EAAE,GAAG,SAAS,CAAC;IACf,IAAI,GAAG,wBAAwB,CAAC;IAChC,WAAW,GAAG,4DAA4D,CAAC;IAC3E,QAAQ,GAAG,OAAgB,CAAC;IAC5B,QAAQ,GAAG,YAAqB,CAAC;IACjC,SAAS,GAAc,KAAK,CAAC;IAE7B,QAAQ,CAAC,GAAa,EAAE,OAA0B;QAChD,MAAM,MAAM,GAAY,EAAE,CAAC;QAE3B,uDAAuD;QACvD,MAAM,cAAc,GAAG,IAAI,GAAG,EAAU,CAAC;QACzC,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,qDAAqD,EAAE,GAAG,CAAC,CAAC;QACtF,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,MAAM,IAAI,GAAG,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC;YACzC,IAAI,IAAI,EAAE,CAAC;gBACT,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YAC3B,CAAC;QACH,CAAC;QAED,qDAAqD;QACrD,MAAM,YAAY,GAAG,OAAO,CAAC,YAAY,IAAI,cAAc,CAAC;QAE5D,uBAAuB;QACvB,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,8BAA8B,EAAE,GAAG,CAAC,CAAC;QAClE,KAAK,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;YAC3B,MAAM,UAAU,GAAG,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC;YAC9C,IAAI,CAAC,UAAU,EAAE,CAAC;gBAChB,SAAS;YACX,CAAC;YAED,iDAAiD;YACjD,IAAI,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC3D,SAAS;YACX,CAAC;YAED,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC;gBAClC,MAAM,OAAO,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,UAAU,CAAC;gBACnD,MAAM,CAAC,IAAI,CACT,IAAI,CAAC,WAAW,CAAC,GAAG,EAAE,aAAa,OAAO,gCAAgC,UAAU,GAAG,EAAE;oBACvF,UAAU,EACR,mGAAmG;iBACtG,CAAC,CACH,CAAC;YACJ,CAAC;QACH,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;CACF;AAlDD,0DAkDC"}
@@ -9,6 +9,14 @@ import { BaseRule } from '../base/BaseRule';
9
9
  * (populated during the pre-scan phase), the rule checks across all project
10
10
  * files. When scanning a standalone file (allFlowRefs is undefined), only
11
11
  * intra-file references are checked.
12
+ *
13
+ * The rule recognises several categories of "externally referenced" flows:
14
+ * - APIKit-generated flows: verb:\path:config (routed by apikit:router)
15
+ * - Flows with external triggers: http:listener, scheduler, vm:listener,
16
+ * salesforce:* listeners (replay-channel-listener, subscribe-channel-listener,
17
+ * replay-topic-listener, subscribe-topic-listener, modified-object-listener,
18
+ * new-object-listener)
19
+ * - Common naming conventions: *-main, *-api, api-*, *-console, *-error-handler, global*
12
20
  */
13
21
  export declare class UnusedFlowRule extends BaseRule {
14
22
  id: string;
@@ -17,6 +25,18 @@ export declare class UnusedFlowRule extends BaseRule {
17
25
  severity: "warning";
18
26
  category: "standards";
19
27
  validate(doc: Document, context: ValidationContext): Issue[];
28
+ /**
29
+ * Check if a flow name matches the APIKit auto-generated naming convention.
30
+ * Pattern: verb:\path:config-name (e.g. "get:\orders:api-config")
31
+ * Also matches with (type) suffix: "get:\orders:api-config(application\json)"
32
+ */
33
+ private isApikitFlow;
34
+ /**
35
+ * Check if a flow has an external trigger (a source component as the first
36
+ * processor). This covers HTTP listeners, schedulers, VM listeners,
37
+ * Salesforce connectors, and any other connector listener.
38
+ */
39
+ private hasExternalTrigger;
20
40
  private isExternallyReferenced;
21
41
  }
22
42
  //# sourceMappingURL=UnusedFlowRule.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"UnusedFlowRule.d.ts","sourceRoot":"","sources":["../../../../src/rules/operations/UnusedFlowRule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACvD,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE5C;;;;;;;;;GASG;AACH,qBAAa,cAAe,SAAQ,QAAQ;IAC1C,EAAE,SAAa;IACf,IAAI,SAA2B;IAC/B,WAAW,SAA6C;IACxD,QAAQ,EAAG,SAAS,CAAU;IAC9B,QAAQ,EAAG,WAAW,CAAU;IAEhC,QAAQ,CAAC,GAAG,EAAE,QAAQ,EAAE,OAAO,EAAE,iBAAiB,GAAG,KAAK,EAAE;IA0E5D,OAAO,CAAC,sBAAsB;CAY/B"}
1
+ {"version":3,"file":"UnusedFlowRule.d.ts","sourceRoot":"","sources":["../../../../src/rules/operations/UnusedFlowRule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACvD,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE5C;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAAa,cAAe,SAAQ,QAAQ;IAC1C,EAAE,SAAa;IACf,IAAI,SAA2B;IAC/B,WAAW,SAA6C;IACxD,QAAQ,EAAG,SAAS,CAAU;IAC9B,QAAQ,EAAG,WAAW,CAAU;IAEhC,QAAQ,CAAC,GAAG,EAAE,QAAQ,EAAE,OAAO,EAAE,iBAAiB,GAAG,KAAK,EAAE;IAwE5D;;;;OAIG;IACH,OAAO,CAAC,YAAY;IAKpB;;;;OAIG;IACH,OAAO,CAAC,kBAAkB;IAgD1B,OAAO,CAAC,sBAAsB;CAY/B"}
@@ -11,6 +11,14 @@ const BaseRule_1 = require("../base/BaseRule");
11
11
  * (populated during the pre-scan phase), the rule checks across all project
12
12
  * files. When scanning a standalone file (allFlowRefs is undefined), only
13
13
  * intra-file references are checked.
14
+ *
15
+ * The rule recognises several categories of "externally referenced" flows:
16
+ * - APIKit-generated flows: verb:\path:config (routed by apikit:router)
17
+ * - Flows with external triggers: http:listener, scheduler, vm:listener,
18
+ * salesforce:* listeners (replay-channel-listener, subscribe-channel-listener,
19
+ * replay-topic-listener, subscribe-topic-listener, modified-object-listener,
20
+ * new-object-listener)
21
+ * - Common naming conventions: *-main, *-api, api-*, *-console, *-error-handler, global*
14
22
  */
15
23
  class UnusedFlowRule extends BaseRule_1.BaseRule {
16
24
  id = 'HYG-003';
@@ -54,18 +62,19 @@ class UnusedFlowRule extends BaseRule_1.BaseRule {
54
62
  }
55
63
  }
56
64
  }
57
- // Check private flows (not triggered by HTTP/scheduler)
65
+ // Check private flows (not triggered by HTTP/scheduler/connector listeners)
58
66
  for (const flow of flows) {
59
67
  const name = this.getNameAttribute(flow);
60
68
  if (!name) {
61
69
  continue;
62
70
  }
63
- // Skip if it has an external trigger
64
- const hasHttpListener = this.exists('.//*[local-name()="listener"]', flow);
65
- const hasScheduler = this.exists('.//*[local-name()="scheduler"]', flow);
66
- const hasVmListener = this.exists('.//*[local-name()="listener" and contains(@config-ref, "vm")]', flow);
67
- if (hasHttpListener || hasScheduler || hasVmListener) {
68
- continue; // Entry point flow
71
+ // Skip APIKit-generated flows (verb:\path:config pattern)
72
+ if (this.isApikitFlow(name)) {
73
+ continue;
74
+ }
75
+ // Skip if it has an external trigger (listener / scheduler)
76
+ if (this.hasExternalTrigger(flow)) {
77
+ continue;
69
78
  }
70
79
  // Check if referenced
71
80
  if (!referencedFlows.has(name) && !this.isExternallyReferenced(name)) {
@@ -77,6 +86,63 @@ class UnusedFlowRule extends BaseRule_1.BaseRule {
77
86
  }
78
87
  return issues;
79
88
  }
89
+ /**
90
+ * Check if a flow name matches the APIKit auto-generated naming convention.
91
+ * Pattern: verb:\path:config-name (e.g. "get:\orders:api-config")
92
+ * Also matches with (type) suffix: "get:\orders:api-config(application\json)"
93
+ */
94
+ isApikitFlow(name) {
95
+ // APIKit flow names contain backslash-separated segments starting with an HTTP verb
96
+ return /^(get|post|put|patch|delete|head|options|trace):\\.+:.+$/i.test(name);
97
+ }
98
+ /**
99
+ * Check if a flow has an external trigger (a source component as the first
100
+ * processor). This covers HTTP listeners, schedulers, VM listeners,
101
+ * Salesforce connectors, and any other connector listener.
102
+ */
103
+ hasExternalTrigger(flow) {
104
+ // http:listener or any namespace listener
105
+ const hasHttpListener = this.exists('.//*[local-name()="listener"]', flow);
106
+ if (hasHttpListener) {
107
+ return true;
108
+ }
109
+ // scheduler
110
+ const hasScheduler = this.exists('.//*[local-name()="scheduler"]', flow);
111
+ if (hasScheduler) {
112
+ return true;
113
+ }
114
+ // Salesforce-specific listeners (platform events, CDC, polling)
115
+ const sfListenerPatterns = [
116
+ 'replay-channel-listener',
117
+ 'subscribe-channel-listener',
118
+ 'replay-topic-listener',
119
+ 'subscribe-topic-listener',
120
+ 'modified-object-listener',
121
+ 'new-object-listener',
122
+ ];
123
+ for (const pattern of sfListenerPatterns) {
124
+ if (this.exists(`.//*[local-name()="${pattern}"]`, flow)) {
125
+ return true;
126
+ }
127
+ }
128
+ // JMS, AMQP, Anypoint MQ, File, FTP, SFTP, Email, DB polling listeners
129
+ const otherListenerPatterns = [
130
+ 'subscriber', // jms:subscriber, amqp:subscriber
131
+ 'consume', // anypoint-mq:subscriber is actually "subscriber" but some use "consume"
132
+ 'on-new-file', // file:listener
133
+ 'on-new-or-updated-file', // sftp/ftp
134
+ 'listener-imap', // email
135
+ 'listener-pop3', // email
136
+ 'on-new-message', // anypoint-mq
137
+ 'on-table-row', // db polling
138
+ ];
139
+ for (const pattern of otherListenerPatterns) {
140
+ if (this.exists(`.//*[local-name()="${pattern}"]`, flow)) {
141
+ return true;
142
+ }
143
+ }
144
+ return false;
145
+ }
80
146
  isExternallyReferenced(name) {
81
147
  // Common patterns that are typically referenced externally
82
148
  const externalPatterns = [
@@ -1 +1 @@
1
- {"version":3,"file":"UnusedFlowRule.js","sourceRoot":"","sources":["../../../../src/rules/operations/UnusedFlowRule.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"UnusedFlowRule.js","sourceRoot":"","sources":["../../../../src/rules/operations/UnusedFlowRule.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ import { ValidationContext, Issue, IssueType } from '../../types';
2
+ import { BaseRule } from '../base/BaseRule';
3
+ /**
4
+ * HYG-005: Unused Variable
5
+ *
6
+ * Detects variables that are set in a flow but never referenced later
7
+ * in the same flow. This is a common code smell that indicates dead code
8
+ * or incomplete refactoring.
9
+ *
10
+ * Checks for set-variable elements whose variableName is not referenced
11
+ * by any subsequent expression in the same flow via `vars.variableName`
12
+ * or `#[vars.variableName]` patterns.
13
+ *
14
+ * Note: This is a best-effort heuristic — variables consumed outside the
15
+ * flow (via flow-ref caller, for example) cannot be detected.
16
+ */
17
+ export declare class UnusedVariableRule extends BaseRule {
18
+ id: string;
19
+ name: string;
20
+ description: string;
21
+ severity: "info";
22
+ category: "operations";
23
+ issueType: IssueType;
24
+ /** Well-known variables that are always considered "used" (consumed by connectors/listeners) */
25
+ private readonly WELL_KNOWN_VARS;
26
+ validate(doc: Document, _context: ValidationContext): Issue[];
27
+ private serializeNode;
28
+ private collectTextContent;
29
+ private escapeRegex;
30
+ }
31
+ //# sourceMappingURL=UnusedVariableRule.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"UnusedVariableRule.d.ts","sourceRoot":"","sources":["../../../../src/rules/operations/UnusedVariableRule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAClE,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE5C;;;;;;;;;;;;;GAaG;AACH,qBAAa,kBAAmB,SAAQ,QAAQ;IAC9C,EAAE,SAAa;IACf,IAAI,SAAqB;IACzB,WAAW,SAAuE;IAClF,QAAQ,EAAG,MAAM,CAAU;IAC3B,QAAQ,EAAG,YAAY,CAAU;IACjC,SAAS,EAAE,SAAS,CAAgB;IAEpC,gGAAgG;IAChG,OAAO,CAAC,QAAQ,CAAC,eAAe,CAK7B;IAEH,QAAQ,CAAC,GAAG,EAAE,QAAQ,EAAE,QAAQ,EAAE,iBAAiB,GAAG,KAAK,EAAE;IAuD7D,OAAO,CAAC,aAAa;IAOrB,OAAO,CAAC,kBAAkB;IAqB1B,OAAO,CAAC,WAAW;CAGpB"}
@@ -0,0 +1,103 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.UnusedVariableRule = void 0;
4
+ const BaseRule_1 = require("../base/BaseRule");
5
+ /**
6
+ * HYG-005: Unused Variable
7
+ *
8
+ * Detects variables that are set in a flow but never referenced later
9
+ * in the same flow. This is a common code smell that indicates dead code
10
+ * or incomplete refactoring.
11
+ *
12
+ * Checks for set-variable elements whose variableName is not referenced
13
+ * by any subsequent expression in the same flow via `vars.variableName`
14
+ * or `#[vars.variableName]` patterns.
15
+ *
16
+ * Note: This is a best-effort heuristic — variables consumed outside the
17
+ * flow (via flow-ref caller, for example) cannot be detected.
18
+ */
19
+ class UnusedVariableRule extends BaseRule_1.BaseRule {
20
+ id = 'HYG-005';
21
+ name = 'Unused Variable';
22
+ description = 'Variables set in a flow should be referenced within the same flow';
23
+ severity = 'info';
24
+ category = 'operations';
25
+ issueType = 'code-smell';
26
+ /** Well-known variables that are always considered "used" (consumed by connectors/listeners) */
27
+ WELL_KNOWN_VARS = new Set([
28
+ 'httpStatus',
29
+ 'outboundHeaders',
30
+ 'statusCode',
31
+ 'correlationId',
32
+ ]);
33
+ validate(doc, _context) {
34
+ const issues = [];
35
+ const flows = this.select('//mule:flow | //mule:sub-flow', doc);
36
+ for (const flow of flows) {
37
+ const flowName = this.getAttribute(flow, 'name') ?? '';
38
+ // Collect all set-variable declarations in this flow
39
+ const setVars = this.select('.//*[local-name()="set-variable"]', flow);
40
+ const variables = [];
41
+ for (const setVar of setVars) {
42
+ const varName = this.getAttribute(setVar, 'variableName');
43
+ if (varName && !this.WELL_KNOWN_VARS.has(varName)) {
44
+ variables.push({ name: varName, node: setVar });
45
+ }
46
+ }
47
+ if (variables.length === 0) {
48
+ continue;
49
+ }
50
+ // Get the full text content of the flow to search for references
51
+ const flowText = this.serializeNode(flow);
52
+ for (const { name, node } of variables) {
53
+ // Check for common reference patterns:
54
+ // vars.name, vars['name'], vars["name"], vars.name
55
+ const patterns = [`vars.${name}`, `vars['${name}']`, `vars["${name}"]`, `#[vars.${name}]`];
56
+ const isReferenced = patterns.some((pattern) => {
57
+ // Count occurrences — must appear beyond just the set-variable itself
58
+ const regex = new RegExp(this.escapeRegex(pattern), 'g');
59
+ const matches = flowText.match(regex);
60
+ return matches !== null && matches.length > 0;
61
+ });
62
+ if (!isReferenced) {
63
+ issues.push(this.createIssue(node, `Variable "${name}" is set in flow "${flowName}" but never referenced within the same flow`, {
64
+ suggestion: `Remove the unused variable or verify it is consumed by a downstream flow via flow-ref`,
65
+ }));
66
+ }
67
+ }
68
+ }
69
+ return issues;
70
+ }
71
+ serializeNode(node) {
72
+ // Get all text content and attribute values from the node subtree
73
+ const parts = [];
74
+ this.collectTextContent(node, parts);
75
+ return parts.join(' ');
76
+ }
77
+ collectTextContent(node, parts) {
78
+ if (node.nodeType === 3 /* TEXT_NODE */) {
79
+ parts.push(node.textContent ?? '');
80
+ }
81
+ else if (node.nodeType === 1 /* ELEMENT_NODE */) {
82
+ // Include attribute values (expressions live in attributes)
83
+ const element = node;
84
+ if (element.attributes) {
85
+ for (let i = 0; i < element.attributes.length; i++) {
86
+ parts.push(element.attributes[i].value);
87
+ }
88
+ }
89
+ // Recurse into children
90
+ const children = node.childNodes;
91
+ if (children) {
92
+ for (let i = 0; i < children.length; i++) {
93
+ this.collectTextContent(children[i], parts);
94
+ }
95
+ }
96
+ }
97
+ }
98
+ escapeRegex(str) {
99
+ return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
100
+ }
101
+ }
102
+ exports.UnusedVariableRule = UnusedVariableRule;
103
+ //# sourceMappingURL=UnusedVariableRule.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"UnusedVariableRule.js","sourceRoot":"","sources":["../../../../src/rules/operations/UnusedVariableRule.ts"],"names":[],"mappings":"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"}
@@ -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"}
@@ -5,12 +5,14 @@ import { BaseRule } from '../base/BaseRule';
5
5
  *
6
6
  * Connectors should have reconnection strategies configured for resilience.
7
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
+ *
8
12
  * Per the Mule HTTP connector XSD, `<reconnection>` is a child element of
9
13
  * `<http:request-connection>`, NOT a direct child of `<http:request-config>`.
10
- * Placing `<reconnection>` directly under `<http:request-config>` causes a
11
- * SAXParseException at build time. The rule uses a descendant search (`.//*`)
12
- * to correctly resolve reconnection elements at any depth, including the valid
13
- * `http:request-config > http:request-connection > reconnection` nesting.
14
+ * The rule uses a descendant search (`.//*`) to correctly resolve reconnection
15
+ * elements at any depth.
14
16
  */
15
17
  export declare class ReconnectionStrategyRule extends BaseRule {
16
18
  id: string;
@@ -19,5 +21,6 @@ export declare class ReconnectionStrategyRule extends BaseRule {
19
21
  severity: "warning";
20
22
  category: "performance";
21
23
  validate(doc: Document, _context: ValidationContext): Issue[];
24
+ private hasAnyReconnection;
22
25
  }
23
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;;;;;;;;;;;GAWG;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;CAkE9D"}
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"}
@@ -7,12 +7,14 @@ const BaseRule_1 = require("../base/BaseRule");
7
7
  *
8
8
  * Connectors should have reconnection strategies configured for resilience.
9
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
+ *
10
14
  * Per the Mule HTTP connector XSD, `<reconnection>` is a child element of
11
15
  * `<http:request-connection>`, NOT a direct child of `<http:request-config>`.
12
- * Placing `<reconnection>` directly under `<http:request-config>` causes a
13
- * SAXParseException at build time. The rule uses a descendant search (`.//*`)
14
- * to correctly resolve reconnection elements at any depth, including the valid
15
- * `http:request-config > http:request-connection > reconnection` nesting.
16
+ * The rule uses a descendant search (`.//*`) to correctly resolve reconnection
17
+ * elements at any depth.
16
18
  */
17
19
  class ReconnectionStrategyRule extends BaseRule_1.BaseRule {
18
20
  id = 'RES-001';
@@ -22,52 +24,70 @@ class ReconnectionStrategyRule extends BaseRule_1.BaseRule {
22
24
  category = 'performance';
23
25
  validate(doc, _context) {
24
26
  const issues = [];
25
- // Specific connector configurations that benefit from reconnection strategies
26
- // Using more specific patterns to avoid false positives on generic "config" elements
27
- 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 = [
28
43
  { pattern: 'request-config', name: 'HTTP Request' },
29
- { pattern: 'listener-config', name: 'HTTP Listener' },
30
44
  { pattern: 'jms-config', name: 'JMS' },
31
45
  { pattern: 'amqp-config', name: 'AMQP' },
32
46
  { pattern: 'sftp-config', name: 'SFTP' },
33
47
  { pattern: 'ftp-config', name: 'FTP' },
34
48
  { pattern: 'vm-config', name: 'VM' },
35
49
  ];
36
- for (const connector of connectorConfigs) {
50
+ for (const connector of requestConfigs) {
37
51
  const configs = this.select(`//*[local-name()="${connector.pattern}"]`, doc);
38
52
  for (const config of configs) {
39
- // Use descendant search (.//*) so that reconnection elements nested anywhere
40
- // inside the config element are detected. This handles the XSD-correct pattern:
41
- // <http:request-config>
42
- // <http:request-connection>
43
- // <reconnection>...</reconnection> ← correct per HTTP connector XSD
44
- // </http:request-connection>
45
- // </http:request-config>
46
- const hasReconnection = this.exists('.//*[local-name()="reconnection"]', config) ||
47
- this.exists('.//*[local-name()="reconnect"]', config) ||
48
- this.exists('.//*[local-name()="reconnect-forever"]', config);
53
+ const hasReconnection = this.hasAnyReconnection(config);
49
54
  if (!hasReconnection) {
50
55
  const name = this.getNameAttribute(config) ?? connector.name;
51
56
  issues.push(this.createIssue(config, `${connector.name} config "${name}" has no reconnection strategy`, {
52
- suggestion: 'Add <reconnection><reconnect count="3" frequency="2000"/></reconnection> inside <http:request-connection> for HTTP connectors',
57
+ suggestion: 'Add <reconnection><reconnect count="3" frequency="2000"/></reconnection> inside the connection element for outbound connectors',
53
58
  }));
54
59
  }
55
60
  }
56
61
  }
57
- // Database configs specifically - check for db namespace
62
+ // Database configs check for db namespace
58
63
  const dbConfigs = this.select('//*[local-name()="config" and starts-with(name(), "db:")]', doc);
59
64
  for (const config of dbConfigs) {
60
- const hasReconnection = this.exists('.//*[local-name()="reconnection"]', config) ||
61
- this.exists('.//*[local-name()="reconnect"]', config);
65
+ const hasReconnection = this.hasAnyReconnection(config);
62
66
  if (!hasReconnection) {
63
67
  const name = this.getNameAttribute(config) ?? 'Database';
64
68
  issues.push(this.createIssue(config, `Database config "${name}" has no reconnection strategy`, {
65
- 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',
66
81
  }));
67
82
  }
68
83
  }
69
84
  return issues;
70
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
+ }
71
91
  }
72
92
  exports.ReconnectionStrategyRule = ReconnectionStrategyRule;
73
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;;;;;;;;;;;GAWG;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,6EAA6E;gBAC7E,gFAAgF;gBAChF,0BAA0B;gBAC1B,gCAAgC;gBAChC,4EAA4E;gBAC5E,iCAAiC;gBACjC,2BAA2B;gBAC3B,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,EACR,+HAA+H;qBAClI,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;AAzED,4DAyEC"}
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"}