@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.
- package/README.md +63 -17
- package/dist/package.json +1 -1
- package/dist/src/core/XPathHelper.d.ts.map +1 -1
- package/dist/src/core/XPathHelper.js +8 -0
- package/dist/src/core/XPathHelper.js.map +1 -1
- package/dist/src/engine/LintEngine.d.ts +22 -0
- package/dist/src/engine/LintEngine.d.ts.map +1 -1
- package/dist/src/engine/LintEngine.js +105 -18
- package/dist/src/engine/LintEngine.js.map +1 -1
- package/dist/src/rules/api-led/ApikitConsoleProductionRule.d.ts +22 -0
- package/dist/src/rules/api-led/ApikitConsoleProductionRule.d.ts.map +1 -0
- package/dist/src/rules/api-led/ApikitConsoleProductionRule.js +43 -0
- package/dist/src/rules/api-led/ApikitConsoleProductionRule.js.map +1 -0
- package/dist/src/rules/api-led/ApikitMainFlowStructureRule.d.ts +24 -0
- package/dist/src/rules/api-led/ApikitMainFlowStructureRule.d.ts.map +1 -0
- package/dist/src/rules/api-led/ApikitMainFlowStructureRule.js +53 -0
- package/dist/src/rules/api-led/ApikitMainFlowStructureRule.js.map +1 -0
- package/dist/src/rules/api-led/ApikitStatusCodeVariableRule.d.ts +25 -0
- package/dist/src/rules/api-led/ApikitStatusCodeVariableRule.d.ts.map +1 -0
- package/dist/src/rules/api-led/ApikitStatusCodeVariableRule.js +59 -0
- package/dist/src/rules/api-led/ApikitStatusCodeVariableRule.js.map +1 -0
- package/dist/src/rules/connector/EventListenerNullGuardRule.d.ts +24 -0
- package/dist/src/rules/connector/EventListenerNullGuardRule.d.ts.map +1 -0
- package/dist/src/rules/connector/EventListenerNullGuardRule.js +58 -0
- package/dist/src/rules/connector/EventListenerNullGuardRule.js.map +1 -0
- package/dist/src/rules/connector/ReplayChannelConfigRule.d.ts +23 -0
- package/dist/src/rules/connector/ReplayChannelConfigRule.d.ts.map +1 -0
- package/dist/src/rules/connector/ReplayChannelConfigRule.js +52 -0
- package/dist/src/rules/connector/ReplayChannelConfigRule.js.map +1 -0
- package/dist/src/rules/dataweave/DataWeaveRules.d.ts +11 -4
- package/dist/src/rules/dataweave/DataWeaveRules.d.ts.map +1 -1
- package/dist/src/rules/dataweave/DataWeaveRules.js +20 -20
- package/dist/src/rules/dataweave/DataWeaveRules.js.map +1 -1
- package/dist/src/rules/dataweave/DuplicateTransformLogicRule.d.ts +25 -0
- package/dist/src/rules/dataweave/DuplicateTransformLogicRule.d.ts.map +1 -0
- package/dist/src/rules/dataweave/DuplicateTransformLogicRule.js +63 -0
- package/dist/src/rules/dataweave/DuplicateTransformLogicRule.js.map +1 -0
- package/dist/src/rules/error-handling/CatchAllLastRule.d.ts +24 -0
- package/dist/src/rules/error-handling/CatchAllLastRule.d.ts.map +1 -0
- package/dist/src/rules/error-handling/CatchAllLastRule.js +65 -0
- package/dist/src/rules/error-handling/CatchAllLastRule.js.map +1 -0
- package/dist/src/rules/error-handling/ErrorHandlerTypeCoverageRule.d.ts +28 -0
- package/dist/src/rules/error-handling/ErrorHandlerTypeCoverageRule.d.ts.map +1 -0
- package/dist/src/rules/error-handling/ErrorHandlerTypeCoverageRule.js +70 -0
- package/dist/src/rules/error-handling/ErrorHandlerTypeCoverageRule.js.map +1 -0
- package/dist/src/rules/error-handling/ErrorResponseStructureRule.d.ts +23 -0
- package/dist/src/rules/error-handling/ErrorResponseStructureRule.d.ts.map +1 -0
- package/dist/src/rules/error-handling/ErrorResponseStructureRule.js +73 -0
- package/dist/src/rules/error-handling/ErrorResponseStructureRule.js.map +1 -0
- package/dist/src/rules/error-handling/GenericErrorRule.d.ts +15 -3
- package/dist/src/rules/error-handling/GenericErrorRule.d.ts.map +1 -1
- package/dist/src/rules/error-handling/GenericErrorRule.js +58 -18
- package/dist/src/rules/error-handling/GenericErrorRule.js.map +1 -1
- package/dist/src/rules/error-handling/GlobalErrorHandlerRule.d.ts +14 -15
- package/dist/src/rules/error-handling/GlobalErrorHandlerRule.d.ts.map +1 -1
- package/dist/src/rules/error-handling/GlobalErrorHandlerRule.js +59 -38
- package/dist/src/rules/error-handling/GlobalErrorHandlerRule.js.map +1 -1
- package/dist/src/rules/error-handling/TryScopeRule.d.ts +5 -0
- package/dist/src/rules/error-handling/TryScopeRule.d.ts.map +1 -1
- package/dist/src/rules/error-handling/TryScopeRule.js +30 -7
- package/dist/src/rules/error-handling/TryScopeRule.js.map +1 -1
- package/dist/src/rules/http/ConnectionIdleTimeoutRule.d.ts +27 -0
- package/dist/src/rules/http/ConnectionIdleTimeoutRule.d.ts.map +1 -0
- package/dist/src/rules/http/ConnectionIdleTimeoutRule.js +46 -0
- package/dist/src/rules/http/ConnectionIdleTimeoutRule.js.map +1 -0
- package/dist/src/rules/index.d.ts +1 -1
- package/dist/src/rules/index.d.ts.map +1 -1
- package/dist/src/rules/index.js +50 -8
- package/dist/src/rules/index.js.map +1 -1
- package/dist/src/rules/logging/LoggerPayloadRule.d.ts +15 -0
- package/dist/src/rules/logging/LoggerPayloadRule.d.ts.map +1 -1
- package/dist/src/rules/logging/LoggerPayloadRule.js +48 -4
- package/dist/src/rules/logging/LoggerPayloadRule.js.map +1 -1
- package/dist/src/rules/operations/FlowRefTargetExistsRule.d.ts +23 -0
- package/dist/src/rules/operations/FlowRefTargetExistsRule.d.ts.map +1 -0
- package/dist/src/rules/operations/FlowRefTargetExistsRule.js +58 -0
- package/dist/src/rules/operations/FlowRefTargetExistsRule.js.map +1 -0
- package/dist/src/rules/operations/UnusedFlowRule.d.ts +20 -0
- package/dist/src/rules/operations/UnusedFlowRule.d.ts.map +1 -1
- package/dist/src/rules/operations/UnusedFlowRule.js +73 -7
- package/dist/src/rules/operations/UnusedFlowRule.js.map +1 -1
- package/dist/src/rules/operations/UnusedVariableRule.d.ts +31 -0
- package/dist/src/rules/operations/UnusedVariableRule.d.ts.map +1 -0
- package/dist/src/rules/operations/UnusedVariableRule.js +103 -0
- package/dist/src/rules/operations/UnusedVariableRule.js.map +1 -0
- package/dist/src/rules/performance/ListenerReconnectForeverRule.d.ts +28 -0
- package/dist/src/rules/performance/ListenerReconnectForeverRule.d.ts.map +1 -0
- package/dist/src/rules/performance/ListenerReconnectForeverRule.js +56 -0
- package/dist/src/rules/performance/ListenerReconnectForeverRule.js.map +1 -0
- package/dist/src/rules/performance/ReconnectionStrategyRule.d.ts +7 -4
- package/dist/src/rules/performance/ReconnectionStrategyRule.d.ts.map +1 -1
- package/dist/src/rules/performance/ReconnectionStrategyRule.js +44 -24
- package/dist/src/rules/performance/ReconnectionStrategyRule.js.map +1 -1
- package/dist/src/rules/security/ConnectorCredentialsSecuredRule.d.ts +36 -0
- package/dist/src/rules/security/ConnectorCredentialsSecuredRule.d.ts.map +1 -0
- package/dist/src/rules/security/ConnectorCredentialsSecuredRule.js +124 -0
- package/dist/src/rules/security/ConnectorCredentialsSecuredRule.js.map +1 -0
- package/dist/src/rules/security/HardcodedCredentialsRule.d.ts +4 -0
- package/dist/src/rules/security/HardcodedCredentialsRule.d.ts.map +1 -1
- package/dist/src/rules/security/HardcodedCredentialsRule.js +15 -0
- package/dist/src/rules/security/HardcodedCredentialsRule.js.map +1 -1
- package/dist/src/rules/security/SecurePropertiesEncryptionRule.d.ts +25 -0
- package/dist/src/rules/security/SecurePropertiesEncryptionRule.d.ts.map +1 -0
- package/dist/src/rules/security/SecurePropertiesEncryptionRule.js +59 -0
- package/dist/src/rules/security/SecurePropertiesEncryptionRule.js.map +1 -0
- package/dist/src/rules/security/SecurePropertiesKeyRule.d.ts +23 -0
- package/dist/src/rules/security/SecurePropertiesKeyRule.d.ts.map +1 -0
- package/dist/src/rules/security/SecurePropertiesKeyRule.js +45 -0
- package/dist/src/rules/security/SecurePropertiesKeyRule.js.map +1 -0
- package/dist/src/rules/security/TlsKeystorePasswordRule.d.ts +25 -0
- package/dist/src/rules/security/TlsKeystorePasswordRule.d.ts.map +1 -0
- package/dist/src/rules/security/TlsKeystorePasswordRule.js +63 -0
- package/dist/src/rules/security/TlsKeystorePasswordRule.js.map +1 -0
- package/dist/src/rules/standards/ApikitRouteVariableConsistencyRule.d.ts +26 -0
- package/dist/src/rules/standards/ApikitRouteVariableConsistencyRule.d.ts.map +1 -0
- package/dist/src/rules/standards/ApikitRouteVariableConsistencyRule.js +61 -0
- package/dist/src/rules/standards/ApikitRouteVariableConsistencyRule.js.map +1 -0
- package/dist/src/rules/standards/ConfigPropertiesOrderingRule.d.ts +34 -0
- package/dist/src/rules/standards/ConfigPropertiesOrderingRule.d.ts.map +1 -0
- package/dist/src/rules/standards/ConfigPropertiesOrderingRule.js +76 -0
- package/dist/src/rules/standards/ConfigPropertiesOrderingRule.js.map +1 -0
- package/dist/src/rules/standards/MissingEnvPropertiesDeclarationRule.d.ts +25 -0
- package/dist/src/rules/standards/MissingEnvPropertiesDeclarationRule.d.ts.map +1 -0
- package/dist/src/rules/standards/MissingEnvPropertiesDeclarationRule.js +111 -0
- package/dist/src/rules/standards/MissingEnvPropertiesDeclarationRule.js.map +1 -0
- package/dist/src/rules/yaml/YamlRules.d.ts +6 -2
- package/dist/src/rules/yaml/YamlRules.d.ts.map +1 -1
- package/dist/src/rules/yaml/YamlRules.js +15 -11
- package/dist/src/rules/yaml/YamlRules.js.map +1 -1
- package/dist/src/types/Rule.d.ts +13 -0
- package/dist/src/types/Rule.d.ts.map +1 -1
- package/docs/best-practices/rules-catalog.md +337 -29
- package/docs/linter/architecture.md +119 -64
- package/package.json +1 -1
|
@@ -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
|
|
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
|
|
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"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SecurePropertiesKeyRule = void 0;
|
|
4
|
+
const BaseRule_1 = require("../base/BaseRule");
|
|
5
|
+
/**
|
|
6
|
+
* SEC-008: Secure Properties Key Configuration
|
|
7
|
+
*
|
|
8
|
+
* The `<secure-properties:config>` element's `key` attribute must use a
|
|
9
|
+
* property placeholder (`${...}`) — never a hardcoded encryption key.
|
|
10
|
+
*
|
|
11
|
+
* A hardcoded key in the XML defeats the purpose of encryption because
|
|
12
|
+
* anyone with access to the source code can decrypt all secure properties.
|
|
13
|
+
* The key should be injected via a system property or environment variable
|
|
14
|
+
* at deployment time (e.g., `-Dsecure.key=...` in the Mule runtime args).
|
|
15
|
+
*/
|
|
16
|
+
class SecurePropertiesKeyRule extends BaseRule_1.BaseRule {
|
|
17
|
+
id = 'SEC-008';
|
|
18
|
+
name = 'Secure Properties Key';
|
|
19
|
+
description = 'Secure properties encryption key must not be hardcoded';
|
|
20
|
+
severity = 'error';
|
|
21
|
+
category = 'security';
|
|
22
|
+
issueType = 'vulnerability';
|
|
23
|
+
validate(doc, _context) {
|
|
24
|
+
const issues = [];
|
|
25
|
+
// Match secure-properties:config or secure-configuration-properties
|
|
26
|
+
const secureConfigs = this.select('//*[local-name()="config" and contains(namespace-uri(), "secure-properties")] | ' +
|
|
27
|
+
'//*[local-name()="secure-configuration-properties"]', doc);
|
|
28
|
+
for (const config of secureConfigs) {
|
|
29
|
+
const key = this.getAttribute(config, 'key');
|
|
30
|
+
if (!key) {
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
// Key must be a property placeholder
|
|
34
|
+
if (!key.includes('${')) {
|
|
35
|
+
const docName = this.getDocName(config) ?? 'Secure Properties Config';
|
|
36
|
+
issues.push(this.createIssue(config, `"${docName}" has hardcoded encryption key — defeats the purpose of property encryption`, {
|
|
37
|
+
suggestion: 'Use a property placeholder: key="${secure.key}" and inject via -Dsecure.key=... at runtime',
|
|
38
|
+
}));
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return issues;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
exports.SecurePropertiesKeyRule = SecurePropertiesKeyRule;
|
|
45
|
+
//# sourceMappingURL=SecurePropertiesKeyRule.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SecurePropertiesKeyRule.js","sourceRoot":"","sources":["../../../../src/rules/security/SecurePropertiesKeyRule.ts"],"names":[],"mappings":";;;AACA,+CAA4C;AAE5C;;;;;;;;;;GAUG;AACH,MAAa,uBAAwB,SAAQ,mBAAQ;IACnD,EAAE,GAAG,SAAS,CAAC;IACf,IAAI,GAAG,uBAAuB,CAAC;IAC/B,WAAW,GAAG,wDAAwD,CAAC;IACvE,QAAQ,GAAG,OAAgB,CAAC;IAC5B,QAAQ,GAAG,UAAmB,CAAC;IAC/B,SAAS,GAAc,eAAe,CAAC;IAEvC,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,MAAM,GAAG,GAAG,IAAI,CAAC,YAAY,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;YAC7C,IAAI,CAAC,GAAG,EAAE,CAAC;gBACT,SAAS;YACX,CAAC;YAED,qCAAqC;YACrC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;gBACxB,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,6EAA6E,EACxF;oBACE,UAAU,EACR,4FAA4F;iBAC/F,CACF,CACF,CAAC;YACJ,CAAC;QACH,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;CACF;AA1CD,0DA0CC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { ValidationContext, Issue, IssueType } from '../../types';
|
|
2
|
+
import { BaseRule } from '../base/BaseRule';
|
|
3
|
+
/**
|
|
4
|
+
* SEC-009: TLS Keystore/Truststore Passwords Secured
|
|
5
|
+
*
|
|
6
|
+
* TLS context keystore and truststore passwords must use secure property
|
|
7
|
+
* placeholders (`${secure::...}`) rather than plain-text placeholders or
|
|
8
|
+
* hardcoded values.
|
|
9
|
+
*
|
|
10
|
+
* These passwords protect the private keys and certificates used for
|
|
11
|
+
* mutual TLS (mTLS) authentication. Leaking them enables impersonation
|
|
12
|
+
* attacks and man-in-the-middle interception.
|
|
13
|
+
*/
|
|
14
|
+
export declare class TlsKeystorePasswordRule extends BaseRule {
|
|
15
|
+
id: string;
|
|
16
|
+
name: string;
|
|
17
|
+
description: string;
|
|
18
|
+
severity: "error";
|
|
19
|
+
category: "security";
|
|
20
|
+
issueType: IssueType;
|
|
21
|
+
private readonly PASSWORD_ATTRS;
|
|
22
|
+
validate(doc: Document, _context: ValidationContext): Issue[];
|
|
23
|
+
private extractPropName;
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=TlsKeystorePasswordRule.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TlsKeystorePasswordRule.d.ts","sourceRoot":"","sources":["../../../../src/rules/security/TlsKeystorePasswordRule.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,SAAmC;IACvC,WAAW,SAAyE;IACpF,QAAQ,EAAG,OAAO,CAAU;IAC5B,QAAQ,EAAG,UAAU,CAAU;IAC/B,SAAS,EAAE,SAAS,CAAmB;IAEvC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAA+B;IAE9D,QAAQ,CAAC,GAAG,EAAE,QAAQ,EAAE,QAAQ,EAAE,iBAAiB,GAAG,KAAK,EAAE;IAoD7D,OAAO,CAAC,eAAe;CAIxB"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TlsKeystorePasswordRule = void 0;
|
|
4
|
+
const BaseRule_1 = require("../base/BaseRule");
|
|
5
|
+
/**
|
|
6
|
+
* SEC-009: TLS Keystore/Truststore Passwords Secured
|
|
7
|
+
*
|
|
8
|
+
* TLS context keystore and truststore passwords must use secure property
|
|
9
|
+
* placeholders (`${secure::...}`) rather than plain-text placeholders or
|
|
10
|
+
* hardcoded values.
|
|
11
|
+
*
|
|
12
|
+
* These passwords protect the private keys and certificates used for
|
|
13
|
+
* mutual TLS (mTLS) authentication. Leaking them enables impersonation
|
|
14
|
+
* attacks and man-in-the-middle interception.
|
|
15
|
+
*/
|
|
16
|
+
class TlsKeystorePasswordRule extends BaseRule_1.BaseRule {
|
|
17
|
+
id = 'SEC-009';
|
|
18
|
+
name = 'TLS Keystore Password Secured';
|
|
19
|
+
description = 'TLS keystore/truststore passwords must use ${secure::} placeholders';
|
|
20
|
+
severity = 'error';
|
|
21
|
+
category = 'security';
|
|
22
|
+
issueType = 'vulnerability';
|
|
23
|
+
PASSWORD_ATTRS = ['password', 'keyPassword'];
|
|
24
|
+
validate(doc, _context) {
|
|
25
|
+
const issues = [];
|
|
26
|
+
// Select all key-store and trust-store elements
|
|
27
|
+
const stores = this.select('//*[local-name()="key-store" or local-name()="trust-store"]', doc);
|
|
28
|
+
for (const store of stores) {
|
|
29
|
+
for (const attrName of this.PASSWORD_ATTRS) {
|
|
30
|
+
const value = this.getAttribute(store, attrName);
|
|
31
|
+
if (!value || value.trim() === '') {
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
// DataWeave expressions are OK
|
|
35
|
+
if (value.startsWith('#[')) {
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
// Must use ${secure::...}
|
|
39
|
+
if (value.includes('${') && !value.includes('${secure::')) {
|
|
40
|
+
const storeName = store.localName;
|
|
41
|
+
issues.push(this.createIssue(store, `TLS ${storeName} "${attrName}" uses plain property placeholder — must use \${secure::}`, {
|
|
42
|
+
suggestion: `Replace ${value} with \${secure::${this.extractPropName(value)}}`,
|
|
43
|
+
}));
|
|
44
|
+
}
|
|
45
|
+
// Hardcoded value
|
|
46
|
+
if (!value.includes('${') && !value.startsWith('#[')) {
|
|
47
|
+
const storeName = store.localName;
|
|
48
|
+
issues.push(this.createIssue(store, `TLS ${storeName} "${attrName}" is hardcoded — must use \${secure::} placeholder`, {
|
|
49
|
+
severity: 'error',
|
|
50
|
+
suggestion: `Use \${secure::tls.${storeName}.${attrName}} instead of the hardcoded value`,
|
|
51
|
+
}));
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return issues;
|
|
56
|
+
}
|
|
57
|
+
extractPropName(placeholder) {
|
|
58
|
+
const match = /\$\{([^}]+)\}/.exec(placeholder);
|
|
59
|
+
return match ? match[1] : placeholder;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
exports.TlsKeystorePasswordRule = TlsKeystorePasswordRule;
|
|
63
|
+
//# sourceMappingURL=TlsKeystorePasswordRule.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TlsKeystorePasswordRule.js","sourceRoot":"","sources":["../../../../src/rules/security/TlsKeystorePasswordRule.ts"],"names":[],"mappings":";;;AACA,+CAA4C;AAE5C;;;;;;;;;;GAUG;AACH,MAAa,uBAAwB,SAAQ,mBAAQ;IACnD,EAAE,GAAG,SAAS,CAAC;IACf,IAAI,GAAG,+BAA+B,CAAC;IACvC,WAAW,GAAG,qEAAqE,CAAC;IACpF,QAAQ,GAAG,OAAgB,CAAC;IAC5B,QAAQ,GAAG,UAAmB,CAAC;IAC/B,SAAS,GAAc,eAAe,CAAC;IAEtB,cAAc,GAAG,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC;IAE9D,QAAQ,CAAC,GAAa,EAAE,QAA2B;QACjD,MAAM,MAAM,GAAY,EAAE,CAAC;QAE3B,gDAAgD;QAChD,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,6DAA6D,EAAE,GAAG,CAAC,CAAC;QAE/F,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;YAC3B,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,cAAc,EAAE,CAAC;gBAC3C,MAAM,KAAK,GAAG,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;gBACjD,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;oBAClC,SAAS;gBACX,CAAC;gBAED,+BAA+B;gBAC/B,IAAI,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;oBAC3B,SAAS;gBACX,CAAC;gBAED,0BAA0B;gBAC1B,IAAI,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC;oBAC1D,MAAM,SAAS,GAAI,KAAiB,CAAC,SAAS,CAAC;oBAC/C,MAAM,CAAC,IAAI,CACT,IAAI,CAAC,WAAW,CACd,KAAK,EACL,OAAO,SAAS,KAAK,QAAQ,2DAA2D,EACxF;wBACE,UAAU,EAAE,WAAW,KAAK,oBAAoB,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,GAAG;qBAC/E,CACF,CACF,CAAC;gBACJ,CAAC;gBAED,kBAAkB;gBAClB,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;oBACrD,MAAM,SAAS,GAAI,KAAiB,CAAC,SAAS,CAAC;oBAC/C,MAAM,CAAC,IAAI,CACT,IAAI,CAAC,WAAW,CACd,KAAK,EACL,OAAO,SAAS,KAAK,QAAQ,oDAAoD,EACjF;wBACE,QAAQ,EAAE,OAAO;wBACjB,UAAU,EAAE,sBAAsB,SAAS,IAAI,QAAQ,kCAAkC;qBAC1F,CACF,CACF,CAAC;gBACJ,CAAC;YACH,CAAC;QACH,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;IAEO,eAAe,CAAC,WAAmB;QACzC,MAAM,KAAK,GAAG,eAAe,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QAChD,OAAO,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC;IACxC,CAAC;CACF;AAlED,0DAkEC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { ValidationContext, Issue, IssueType } from '../../types';
|
|
2
|
+
import { BaseRule } from '../base/BaseRule';
|
|
3
|
+
/**
|
|
4
|
+
* STD-001: APIKit Route Variable Consistency
|
|
5
|
+
*
|
|
6
|
+
* In APIKit projects, implementation flows (get:\resource:config, etc.)
|
|
7
|
+
* should follow a consistent pattern for setting response variables.
|
|
8
|
+
* For example, if some flows set httpStatus but others don't, this
|
|
9
|
+
* inconsistency can lead to unexpected HTTP responses.
|
|
10
|
+
*
|
|
11
|
+
* This rule flags APIKit implementation flows that deviate from the
|
|
12
|
+
* most common pattern in the file (e.g., if 4/5 flows set httpStatus
|
|
13
|
+
* but one doesn't, the outlier is flagged).
|
|
14
|
+
*/
|
|
15
|
+
export declare class ApikitRouteVariableConsistencyRule extends BaseRule {
|
|
16
|
+
id: string;
|
|
17
|
+
name: string;
|
|
18
|
+
description: string;
|
|
19
|
+
severity: "info";
|
|
20
|
+
category: "standards";
|
|
21
|
+
issueType: IssueType;
|
|
22
|
+
/** Pattern for APIKit-generated flow names */
|
|
23
|
+
private readonly APIKIT_FLOW_PATTERN;
|
|
24
|
+
validate(doc: Document, _context: ValidationContext): Issue[];
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=ApikitRouteVariableConsistencyRule.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ApikitRouteVariableConsistencyRule.d.ts","sourceRoot":"","sources":["../../../../src/rules/standards/ApikitRouteVariableConsistencyRule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAClE,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE5C;;;;;;;;;;;GAWG;AACH,qBAAa,kCAAmC,SAAQ,QAAQ;IAC9D,EAAE,SAAa;IACf,IAAI,SAAuC;IAC3C,WAAW,SAC8E;IACzF,QAAQ,EAAG,MAAM,CAAU;IAC3B,QAAQ,EAAG,WAAW,CAAU;IAChC,SAAS,EAAE,SAAS,CAAgB;IAEpC,8CAA8C;IAC9C,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAkD;IAEtF,QAAQ,CAAC,GAAG,EAAE,QAAQ,EAAE,QAAQ,EAAE,iBAAiB,GAAG,KAAK,EAAE;CAoD9D"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ApikitRouteVariableConsistencyRule = void 0;
|
|
4
|
+
const BaseRule_1 = require("../base/BaseRule");
|
|
5
|
+
/**
|
|
6
|
+
* STD-001: APIKit Route Variable Consistency
|
|
7
|
+
*
|
|
8
|
+
* In APIKit projects, implementation flows (get:\resource:config, etc.)
|
|
9
|
+
* should follow a consistent pattern for setting response variables.
|
|
10
|
+
* For example, if some flows set httpStatus but others don't, this
|
|
11
|
+
* inconsistency can lead to unexpected HTTP responses.
|
|
12
|
+
*
|
|
13
|
+
* This rule flags APIKit implementation flows that deviate from the
|
|
14
|
+
* most common pattern in the file (e.g., if 4/5 flows set httpStatus
|
|
15
|
+
* but one doesn't, the outlier is flagged).
|
|
16
|
+
*/
|
|
17
|
+
class ApikitRouteVariableConsistencyRule extends BaseRule_1.BaseRule {
|
|
18
|
+
id = 'STD-001';
|
|
19
|
+
name = 'APIKit Route Variable Consistency';
|
|
20
|
+
description = 'APIKit implementation flows should follow consistent patterns for response variables';
|
|
21
|
+
severity = 'info';
|
|
22
|
+
category = 'standards';
|
|
23
|
+
issueType = 'code-smell';
|
|
24
|
+
/** Pattern for APIKit-generated flow names */
|
|
25
|
+
APIKIT_FLOW_PATTERN = /^(get|post|put|patch|delete|head|options):\\/;
|
|
26
|
+
validate(doc, _context) {
|
|
27
|
+
const issues = [];
|
|
28
|
+
const flows = this.select('//mule:flow', doc);
|
|
29
|
+
// Collect APIKit implementation flows
|
|
30
|
+
const apikitFlows = [];
|
|
31
|
+
for (const flow of flows) {
|
|
32
|
+
const flowName = this.getAttribute(flow, 'name') ?? '';
|
|
33
|
+
if (!this.APIKIT_FLOW_PATTERN.test(flowName)) {
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
const setsHttpStatus = this.exists('.//*[local-name()="set-variable" and @variableName="httpStatus"]', flow);
|
|
37
|
+
apikitFlows.push({ name: flowName, node: flow, setsHttpStatus });
|
|
38
|
+
}
|
|
39
|
+
// Need at least 3 flows to detect a meaningful pattern
|
|
40
|
+
if (apikitFlows.length < 3) {
|
|
41
|
+
return issues;
|
|
42
|
+
}
|
|
43
|
+
// Determine the majority pattern
|
|
44
|
+
const withStatus = apikitFlows.filter((f) => f.setsHttpStatus).length;
|
|
45
|
+
const withoutStatus = apikitFlows.length - withStatus;
|
|
46
|
+
// Only flag if there's a clear majority (>60%) and at least one outlier
|
|
47
|
+
if (withStatus > withoutStatus && withoutStatus > 0 && withStatus / apikitFlows.length > 0.6) {
|
|
48
|
+
// Majority sets httpStatus — flag those that don't
|
|
49
|
+
for (const flow of apikitFlows) {
|
|
50
|
+
if (!flow.setsHttpStatus) {
|
|
51
|
+
issues.push(this.createIssue(flow.node, `APIKit flow "${flow.name}" does not set httpStatus, but ${withStatus}/${apikitFlows.length} other flows do`, {
|
|
52
|
+
suggestion: 'Add a set-variable for httpStatus to maintain consistency across all APIKit implementation flows',
|
|
53
|
+
}));
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return issues;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
exports.ApikitRouteVariableConsistencyRule = ApikitRouteVariableConsistencyRule;
|
|
61
|
+
//# sourceMappingURL=ApikitRouteVariableConsistencyRule.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ApikitRouteVariableConsistencyRule.js","sourceRoot":"","sources":["../../../../src/rules/standards/ApikitRouteVariableConsistencyRule.ts"],"names":[],"mappings":";;;AACA,+CAA4C;AAE5C;;;;;;;;;;;GAWG;AACH,MAAa,kCAAmC,SAAQ,mBAAQ;IAC9D,EAAE,GAAG,SAAS,CAAC;IACf,IAAI,GAAG,mCAAmC,CAAC;IAC3C,WAAW,GACT,sFAAsF,CAAC;IACzF,QAAQ,GAAG,MAAe,CAAC;IAC3B,QAAQ,GAAG,WAAoB,CAAC;IAChC,SAAS,GAAc,YAAY,CAAC;IAEpC,8CAA8C;IAC7B,mBAAmB,GAAG,8CAA8C,CAAC;IAEtF,QAAQ,CAAC,GAAa,EAAE,QAA2B;QACjD,MAAM,MAAM,GAAY,EAAE,CAAC;QAE3B,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,aAAa,EAAE,GAAG,CAAC,CAAC;QAE9C,sCAAsC;QACtC,MAAM,WAAW,GAAiE,EAAE,CAAC;QAErF,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,MAAM,QAAQ,GAAG,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,CAAC;YACvD,IAAI,CAAC,IAAI,CAAC,mBAAmB,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;gBAC7C,SAAS;YACX,CAAC;YAED,MAAM,cAAc,GAAG,IAAI,CAAC,MAAM,CAChC,kEAAkE,EAClE,IAAI,CACL,CAAC;YAEF,WAAW,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,cAAc,EAAE,CAAC,CAAC;QACnE,CAAC;QAED,uDAAuD;QACvD,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC3B,OAAO,MAAM,CAAC;QAChB,CAAC;QAED,iCAAiC;QACjC,MAAM,UAAU,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,MAAM,CAAC;QACtE,MAAM,aAAa,GAAG,WAAW,CAAC,MAAM,GAAG,UAAU,CAAC;QAEtD,wEAAwE;QACxE,IAAI,UAAU,GAAG,aAAa,IAAI,aAAa,GAAG,CAAC,IAAI,UAAU,GAAG,WAAW,CAAC,MAAM,GAAG,GAAG,EAAE,CAAC;YAC7F,mDAAmD;YACnD,KAAK,MAAM,IAAI,IAAI,WAAW,EAAE,CAAC;gBAC/B,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,CAAC;oBACzB,MAAM,CAAC,IAAI,CACT,IAAI,CAAC,WAAW,CACd,IAAI,CAAC,IAAI,EACT,gBAAgB,IAAI,CAAC,IAAI,kCAAkC,UAAU,IAAI,WAAW,CAAC,MAAM,iBAAiB,EAC5G;wBACE,UAAU,EACR,kGAAkG;qBACrG,CACF,CACF,CAAC;gBACJ,CAAC;YACH,CAAC;QACH,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;CACF;AAhED,gFAgEC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { ValidationContext, Issue } from '../../types';
|
|
2
|
+
import { BaseRule } from '../base/BaseRule';
|
|
3
|
+
/**
|
|
4
|
+
* CFG-001: Configuration Properties Ordering
|
|
5
|
+
*
|
|
6
|
+
* Mule configuration-properties elements should be loaded in the correct
|
|
7
|
+
* order: global defaults first, then environment-specific overrides, then
|
|
8
|
+
* secure properties. This ensures predictable property resolution (Mule
|
|
9
|
+
* uses last-wins for overlapping keys).
|
|
10
|
+
*
|
|
11
|
+
* Expected ordering pattern:
|
|
12
|
+
* 1. config/global.yaml (or common.yaml, defaults.yaml)
|
|
13
|
+
* 2. config/${mule.env}.yaml (environment-specific)
|
|
14
|
+
* 3. secure-properties:config (encrypted secrets)
|
|
15
|
+
* 4. entity-config/*.yaml (optional, additive)
|
|
16
|
+
*
|
|
17
|
+
* This rule flags when env-specific properties appear before global
|
|
18
|
+
* defaults, which would cause globals to override env-specific values.
|
|
19
|
+
*/
|
|
20
|
+
export declare class ConfigPropertiesOrderingRule extends BaseRule {
|
|
21
|
+
id: string;
|
|
22
|
+
name: string;
|
|
23
|
+
description: string;
|
|
24
|
+
severity: "info";
|
|
25
|
+
category: "standards";
|
|
26
|
+
/** Patterns that identify global/default property files */
|
|
27
|
+
private readonly GLOBAL_PATTERNS;
|
|
28
|
+
/** Patterns that identify env-specific property files */
|
|
29
|
+
private readonly ENV_PATTERNS;
|
|
30
|
+
validate(doc: Document, _context: ValidationContext): Issue[];
|
|
31
|
+
private isGlobalFile;
|
|
32
|
+
private isEnvSpecificFile;
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=ConfigPropertiesOrderingRule.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ConfigPropertiesOrderingRule.d.ts","sourceRoot":"","sources":["../../../../src/rules/standards/ConfigPropertiesOrderingRule.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,SAAuC;IAC3C,WAAW,SACwF;IACnG,QAAQ,EAAG,MAAM,CAAU;IAC3B,QAAQ,EAAG,WAAW,CAAU;IAEhC,2DAA2D;IAC3D,OAAO,CAAC,QAAQ,CAAC,eAAe,CAO9B;IAEF,yDAAyD;IACzD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAoD;IAEjF,QAAQ,CAAC,GAAG,EAAE,QAAQ,EAAE,QAAQ,EAAE,iBAAiB,GAAG,KAAK,EAAE;IA6C7D,OAAO,CAAC,YAAY;IAIpB,OAAO,CAAC,iBAAiB;CAG1B"}
|