@sfdxy/mule-lint 1.21.0 → 1.22.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.
@@ -0,0 +1,135 @@
1
+ # CI/CD Integration
2
+
3
+ > **Applies to:** All
4
+ > **Related Rules:** `PROJ-001` · `PROJ-002`
5
+ > **Last Updated:** April 2026
6
+
7
+ ## When to Read This
8
+
9
+ Read this when setting up CI/CD pipelines, integrating mule-lint into builds, or configuring quality gates.
10
+
11
+ ---
12
+
13
+ ## Pipeline Stages
14
+
15
+ ```
16
+ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
17
+ │ Build │ → │ Lint │ → │ Test │ → │ Package │ → │ Deploy │
18
+ │ │ │ │ │ │ │ │ │ │
19
+ │ mvn │ │ mule- │ │ mvn test │ │ mvn │ │ anypoint │
20
+ │ compile │ │ lint │ │ │ │ package │ │ deploy │
21
+ └──────────┘ └──────────┘ └──────────┘ └──────────┘ └──────────┘
22
+ ```
23
+
24
+ ---
25
+
26
+ ## mule-lint Integration
27
+
28
+ ### Quality Gate Configuration
29
+
30
+ ```json
31
+ // .mulelintrc.json
32
+ {
33
+ "include": ["src/main/mule/**/*.xml"],
34
+ "exclude": ["src/test/munit/**/*.xml"],
35
+ "qualityGate": {
36
+ "name": "Project Quality Gate",
37
+ "conditions": [
38
+ { "metric": "errors", "operator": ">", "threshold": 0, "status": "fail" },
39
+ { "metric": "warnings", "operator": ">", "threshold": 10, "status": "warn" }
40
+ ]
41
+ },
42
+ "rules": {
43
+ "MULE-001": {
44
+ "enabled": false,
45
+ "reason": "Global error handler in non-standard location — documented exception"
46
+ }
47
+ }
48
+ }
49
+ ```
50
+
51
+ **Rule suppression:** When disabling a rule, always include a `reason` or `comment` field explaining why. This documents the engineering decision for future reviewers.
52
+
53
+ ### Output Formats
54
+
55
+ | Format | Use Case | Command |
56
+ | -------- | ------------------------------- | ------------------------------------ |
57
+ | `pretty` | Local development | `mule-lint . -f pretty` |
58
+ | `json` | CI/CD parsing | `mule-lint . -f json` |
59
+ | `sarif` | GitHub Code Scanning, AI agents | `mule-lint . -f sarif -o lint.sarif` |
60
+ | `html` | Human review reports | `mule-lint . -f html -o report.html` |
61
+
62
+ ---
63
+
64
+ ## GitHub Actions Example
65
+
66
+ ```yaml
67
+ name: Mule CI/CD
68
+
69
+ on:
70
+ push:
71
+ branches: [main, develop]
72
+ pull_request:
73
+ branches: [main]
74
+
75
+ jobs:
76
+ build-and-test:
77
+ runs-on: ubuntu-latest
78
+ steps:
79
+ - uses: actions/checkout@v4
80
+
81
+ - name: Set up JDK 17
82
+ uses: actions/setup-java@v4
83
+ with:
84
+ java-version: '17'
85
+ distribution: 'temurin'
86
+
87
+ - name: Cache Maven packages
88
+ uses: actions/cache@v4
89
+ with:
90
+ path: ~/.m2
91
+ key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
92
+
93
+ - name: Build
94
+ run: mvn -B clean compile
95
+
96
+ - name: Run mule-lint
97
+ run: npx @sfdxy/mule-lint . -c .mulelintrc.json -f sarif -o lint.sarif
98
+
99
+ - name: Upload SARIF results
100
+ uses: github/codeql-action/upload-sarif@v3
101
+ with:
102
+ sarif_file: lint.sarif
103
+
104
+ - name: Run MUnit tests
105
+ run: mvn -B test -Dmule.env=dev -Dsecure.key=test
106
+ ```
107
+
108
+ ---
109
+
110
+ ## Git Branch Strategy
111
+
112
+ | Branch | Purpose | Deployment Target |
113
+ | ----------- | --------------------- | ----------------- |
114
+ | `main` | Production-ready code | Production |
115
+ | `develop` | Integration branch | QA/Staging |
116
+ | `feature/*` | New features | Development |
117
+ | `hotfix/*` | Production fixes | Production |
118
+
119
+ ---
120
+
121
+ ## Commit Messages
122
+
123
+ Follow [Conventional Commits](https://www.conventionalcommits.org/):
124
+
125
+ ```
126
+ feat: add new order processing logic
127
+ fix: resolve null pointer in mapping
128
+ docs: update README with deployment steps
129
+ chore: upgrade mule maven plugin
130
+ refactor: extract common DWL functions to module
131
+ ```
132
+
133
+ ---
134
+
135
+ **See also:** [Testing](testing.md) · [Deployment & Modernization](deployment-2026.md) · [Folder Structure](folder-structure.md)
@@ -0,0 +1,253 @@
1
+ # Connector Configuration Patterns
2
+
3
+ > **Applies to:** All (System APIs, Process APIs)
4
+ > **Related Rules:** `SEC-007` · `SEC-008` · `PERF-002` · `RES-001` · `RES-002` · `SF-001` · `SF-002`
5
+ > **Last Updated:** April 2026
6
+
7
+ ## When to Read This
8
+
9
+ Read this when configuring Salesforce, NetSuite, HTTP, or Database connectors in Mule 4. Covers connector attribute gotchas, the entity-config pattern, and protocol negotiation.
10
+
11
+ ---
12
+
13
+ ## Patterns
14
+
15
+ ### Pattern 1: Entity Configuration (YAML-Driven)
16
+
17
+ **Use when:** building a System API that supports multiple entity types (Account, Contact, Order, etc.) with consistent CRUD operations.
18
+
19
+ Instead of hardcoding entity-specific details in flow XML, externalize them to per-entity YAML files:
20
+
21
+ ```
22
+ src/main/resources/entity-config/
23
+ ├── account.yaml
24
+ ├── contact.yaml
25
+ ├── opportunity.yaml
26
+ └── order.yaml
27
+ ```
28
+
29
+ **Entity config structure:**
30
+
31
+ ```yaml
32
+ # entity-config/account.yaml
33
+ entity:
34
+ account:
35
+ sObjectType: 'Account'
36
+ enabled: true
37
+ externalIdField: 'NetSuite_ID__c'
38
+ queryFields: 'Id, Name, BillingStreet, BillingCity, Phone, Website'
39
+ queryTemplate: 'SELECT {fields} FROM Account WHERE {filter} LIMIT {limit}'
40
+ writeback:
41
+ netSuiteIdField: 'NetSuite_ID__c'
42
+ errorField: 'NetSuite_Error__c'
43
+ lastSyncField: 'Last_NetSuite_Sync__c'
44
+ ```
45
+
46
+ **Load in global-config.xml:**
47
+
48
+ ```xml
49
+ <configuration-properties doc:name="Account Config"
50
+ file="entity-config/account.yaml"/>
51
+ <configuration-properties doc:name="Contact Config"
52
+ file="entity-config/contact.yaml"/>
53
+ ```
54
+
55
+ **Benefits:**
56
+
57
+ - Add a new entity by creating a YAML file — no flow XML changes
58
+ - Entity behavior is visible, auditable, and environment-independent
59
+ - LLMs can read entity configs to understand available operations
60
+
61
+ ### Pattern 2: Salesforce JWT Connector
62
+
63
+ **Use when:** authenticating to Salesforce via OAuth 2.0 JWT Bearer flow.
64
+
65
+ ```xml
66
+ <salesforce:sfdc-config name="Salesforce_Config">
67
+ <salesforce:jwt-connection
68
+ consumerKey="${secure::salesforce.jwt.consumerKey}"
69
+ keyStore="${salesforce.jwt.keystorePath}"
70
+ storePassword="${secure::salesforce.jwt.storePassword}"
71
+ principal="${salesforce.jwt.principal}"
72
+ tokenEndpoint="${salesforce.jwt.tokenEndpoint}"
73
+ audienceUrl="${salesforce.jwt.audienceUrl}">
74
+ <reconnection>
75
+ <reconnect count="3" frequency="5000"/>
76
+ </reconnection>
77
+ </salesforce:jwt-connection>
78
+ </salesforce:sfdc-config>
79
+ ```
80
+
81
+ > ⚠️ **Gotchas** (common mistakes that cause runtime failures):
82
+ >
83
+ > | Incorrect | Correct | Notes |
84
+ > | ----------------------------------- | ------------------------ | ---------------------------------- |
85
+ > | `salesforce:jwt-connection-config` | `salesforce:sfdc-config` | Outer config element name |
86
+ > | `keyStorePath="..."` | `keyStore="..."` | JWT connection attribute |
87
+ > | `type="Account"` (on upsert) | `objectType="Account"` | Upsert operation attribute |
88
+ > | `type="Account"` (on create/update) | `type="Account"` | Create/Update use `type` (correct) |
89
+
90
+ ### Pattern 3: Protocol Negotiation (Dual-Protocol SAPI)
91
+
92
+ **Use when:** a System API must support both SOAP and REST protocols to the same backend (e.g., NetSuite).
93
+
94
+ The calling PAPI sends an `x-integration-protocol` header. The SAPI routes internally:
95
+
96
+ ```xml
97
+ <!-- common/netsuite-process-subflow.xml -->
98
+ <sub-flow name="netsuite-process-subflow">
99
+ <choice>
100
+ <when expression="#[vars.protocol == 'SOAP']">
101
+ <flow-ref name="netsuite-soap-upsert-subflow"/>
102
+ </when>
103
+ <when expression="#[vars.protocol == 'REST']">
104
+ <flow-ref name="netsuite-rest-upsert-subflow"/>
105
+ </when>
106
+ </choice>
107
+ </sub-flow>
108
+ ```
109
+
110
+ **Protocol support matrix:**
111
+
112
+ | Record Type | SOAP | REST |
113
+ | ----------- | ---- | -------------- |
114
+ | Customer | ✅ | ✅ |
115
+ | Contact | ✅ | ✅ |
116
+ | Sales Order | ✅ | ❌ (SOAP-only) |
117
+ | Credit Memo | ✅ | ❌ (SOAP-only) |
118
+
119
+ ### Pattern 4: HTTP Request Connector (with Pooling)
120
+
121
+ **Use when:** making outbound HTTP calls to downstream APIs.
122
+
123
+ ```xml
124
+ <http:request-config name="SAPI_HTTP_Config"
125
+ responseTimeout="${https.request.responseTimeout}">
126
+ <http:request-connection host="${https.request.host}"
127
+ port="${https.request.port}"
128
+ connectionIdleTimeout="${https.connection.idleTimeout}"
129
+ maxConnections="${https.connection.maxConnections}">
130
+ <reconnection>
131
+ <reconnect frequency="${reconnection.frequency}"
132
+ count="${reconnection.attempts}"/>
133
+ </reconnection>
134
+ </http:request-connection>
135
+ <!-- Set correlation ID once — applied to every request automatically -->
136
+ <http:default-headers>
137
+ <http:default-header key="X-Correlation-Id" value="#[correlationId]"/>
138
+ </http:default-headers>
139
+ </http:request-config>
140
+ ```
141
+
142
+ **Rules:**
143
+
144
+ - Always set `responseTimeout` (avoid hanging connections)
145
+ - Set `connectionIdleTimeout >= responseTimeout` (Grizzly kills connections if idle fires first)
146
+ - Configure connection pooling for production (`maxConnections`)
147
+
148
+ ### Pattern 5: Reconnection Strategies
149
+
150
+ **Use when:** configuring any connector that connects to an external system.
151
+
152
+ | Connector Type | Strategy | Example |
153
+ | -------------------------------------- | --------------------- | ---------------------------------- |
154
+ | **Event listeners** (SF, MQ) | `reconnect-forever` | Must auto-recover from disconnects |
155
+ | **Outbound connectors** (HTTP, SF, DB) | `reconnect count="3"` | Bounded retries with frequency |
156
+ | **HTTP Listener** | `reconnect-forever` | Server must always be up |
157
+
158
+ ```xml
159
+ <!-- Listener — always reconnect -->
160
+ <http:listener-config name="httpListenerConfig">
161
+ <http:listener-connection host="0.0.0.0" port="${http.port}">
162
+ <reconnection>
163
+ <reconnect-forever frequency="5000"/>
164
+ </reconnection>
165
+ </http:listener-connection>
166
+ </http:listener-config>
167
+
168
+ <!-- Outbound — bounded retries -->
169
+ <salesforce:sfdc-config name="Salesforce_Config">
170
+ <salesforce:jwt-connection ...>
171
+ <reconnection>
172
+ <reconnect count="3" frequency="5000"/>
173
+ </reconnection>
174
+ </salesforce:jwt-connection>
175
+ </salesforce:sfdc-config>
176
+ ```
177
+
178
+ ### Pattern 6: ObjectStore for Reference Data Caching
179
+
180
+ **Use when:** frequently-accessed reference data (customer records, config lookups) is fetched repeatedly during batch processing. Cache in ObjectStore with TTL to reduce API calls.
181
+
182
+ ```xml
183
+ <!-- global.xml — configure the cache store -->
184
+ <os:object-store name="customer-cache-store"
185
+ entryTtl="${customer.cache.ttl}"
186
+ expirationInterval="${customer.cache.expirationInterval}"
187
+ maxEntries="200"/>
188
+ ```
189
+
190
+ **Key rules:**
191
+
192
+ - Set `maxEntries` to prevent unbounded memory growth
193
+ - Set `entryTtl` appropriate to data volatility (e.g., 1 hour for customer data, 24 hours for country codes)
194
+ - Use `os:contains` + `os:retrieve` to check-then-get, not just `os:retrieve` with default (avoids computing defaults unnecessarily)
195
+
196
+ ---
197
+
198
+ ## DWL Utility Module: `parseAndConvert`
199
+
200
+ The Salesforce connector requires Java-typed values (DateTime, Date, Boolean) — not strings. Use a shared DWL module for type coercion:
201
+
202
+ ```dataweave
203
+ %dw 2.0
204
+ // dwl/modules/salesforceUtility.dwl
205
+
206
+ var dateTimePattern = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d{1,3})?(Z|[+-]\d{2}:\d{2})?$/
207
+ var dateOnlyPattern = /^\d{4}-\d{2}-\d{2}$/
208
+
209
+ fun parseAndConvert(obj: Object) =
210
+ obj mapObject ((value, key) ->
211
+ if ((value is String) and ((value as String) matches dateTimePattern))
212
+ (key): (value as String) as DateTime
213
+ else if ((value is String) and ((value as String) matches dateOnlyPattern))
214
+ (key): (value as String) as Date
215
+ else if ((value is String) and ((value as String) == ""))
216
+ (key): null
217
+ else if (value is Object)
218
+ (key): parseAndConvert(value)
219
+ else
220
+ (key): value
221
+ )
222
+ ```
223
+
224
+ **Usage in flow XML:**
225
+
226
+ ```xml
227
+ <ee:transform>
228
+ <ee:set-payload><![CDATA[%dw 2.0
229
+ import dwl::modules::salesforceUtility
230
+ output application/java
231
+ ---
232
+ salesforceUtility::parseAndConvert(payload)
233
+ ]]></ee:set-payload>
234
+ </ee:transform>
235
+ ```
236
+
237
+ > ⚠️ **DWL import path rule:** Always use the full path prefix `dwl::modules::moduleName`. Short paths like `modules::moduleName` will fail at runtime.
238
+
239
+ ---
240
+
241
+ ## Checklist
242
+
243
+ - [ ] Entity configs externalized to `entity-config/{entity}.yaml`
244
+ - [ ] All connector credentials use `${secure::...}` property placeholders
245
+ - [ ] Reconnection strategies configured on all connectors
246
+ - [ ] `responseTimeout` explicitly set on HTTP request configs
247
+ - [ ] No hardcoded connector attribute values (hosts, ports, keys)
248
+ - [ ] DWL modules imported with full `dwl::modules::` path prefix
249
+ - [ ] Salesforce payloads pass through `parseAndConvert()` before connector call
250
+
251
+ ---
252
+
253
+ **See also:** [Security](security.md) · [Performance](performance.md) · [DataWeave Patterns](dataweave-patterns.md)