@sun-asterisk/sunlint 1.3.16 → 1.3.17
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/config/rule-analysis-strategies.js +3 -3
- package/config/rules/enhanced-rules-registry.json +40 -20
- package/core/cli-action-handler.js +2 -2
- package/core/config-merger.js +28 -6
- package/core/constants/defaults.js +1 -1
- package/core/file-targeting-service.js +72 -4
- package/core/output-service.js +21 -4
- package/engines/heuristic-engine.js +5 -0
- package/package.json +1 -1
- package/rules/common/C002_no_duplicate_code/README.md +115 -0
- package/rules/common/C002_no_duplicate_code/analyzer.js +615 -219
- package/rules/common/C002_no_duplicate_code/test-cases/api-handlers.ts +64 -0
- package/rules/common/C002_no_duplicate_code/test-cases/data-processor.ts +46 -0
- package/rules/common/C002_no_duplicate_code/test-cases/good-example.tsx +40 -0
- package/rules/common/C002_no_duplicate_code/test-cases/product-service.ts +57 -0
- package/rules/common/C002_no_duplicate_code/test-cases/user-service.ts +49 -0
- package/rules/common/C008/analyzer.js +40 -0
- package/rules/common/C008/config.json +20 -0
- package/rules/common/C008/ts-morph-analyzer.js +1067 -0
- package/rules/common/C018_no_throw_generic_error/analyzer.js +1 -1
- package/rules/common/C018_no_throw_generic_error/symbol-based-analyzer.js +27 -3
- package/rules/common/C024_no_scatter_hardcoded_constants/symbol-based-analyzer.js +504 -162
- package/rules/common/C029_catch_block_logging/analyzer.js +499 -89
- package/rules/common/C033_separate_service_repository/README.md +131 -20
- package/rules/common/C033_separate_service_repository/analyzer.js +1 -1
- package/rules/common/C033_separate_service_repository/symbol-based-analyzer.js +417 -274
- package/rules/common/C041_no_sensitive_hardcode/analyzer.js +144 -254
- package/rules/common/C041_no_sensitive_hardcode/config.json +50 -0
- package/rules/common/C041_no_sensitive_hardcode/symbol-based-analyzer.js +575 -0
- package/rules/common/C067_no_hardcoded_config/analyzer.js +17 -16
- package/rules/common/C067_no_hardcoded_config/symbol-based-analyzer.js +3477 -659
- package/rules/docs/C002_no_duplicate_code.md +276 -11
- package/rules/index.js +5 -1
- package/rules/security/S006_no_plaintext_recovery_codes/analyzer.js +266 -88
- package/rules/security/S006_no_plaintext_recovery_codes/symbol-based-analyzer.js +805 -0
- package/rules/security/S010_no_insecure_encryption/README.md +78 -0
- package/rules/security/S010_no_insecure_encryption/analyzer.js +463 -398
- package/rules/security/S013_tls_enforcement/README.md +51 -0
- package/rules/security/S013_tls_enforcement/analyzer.js +99 -0
- package/rules/security/S013_tls_enforcement/config.json +41 -0
- package/rules/security/S013_tls_enforcement/symbol-based-analyzer.js +339 -0
- package/rules/security/S014_tls_version_enforcement/README.md +354 -0
- package/rules/security/S014_tls_version_enforcement/analyzer.js +118 -0
- package/rules/security/S014_tls_version_enforcement/config.json +56 -0
- package/rules/security/S014_tls_version_enforcement/symbol-based-analyzer.js +194 -0
- package/rules/security/S055_content_type_validation/analyzer.js +121 -279
- package/rules/security/S055_content_type_validation/symbol-based-analyzer.js +346 -0
- package/rules/tests/C002_no_duplicate_code.test.js +111 -22
- package/rules/common/C029_catch_block_logging/analyzer-smart-pipeline.js +0 -755
- package/rules/common/C041_no_sensitive_hardcode/ast-analyzer.js +0 -296
|
@@ -1,292 +1,182 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
/**
|
|
2
|
+
* C041 Main Analyzer - Do not hardcode or push sensitive information
|
|
3
|
+
* Primary: Protect sensitive application data, avoid security risks, and comply with security standards. Exposing sensitive information can lead to serious security and privacy issues.
|
|
4
|
+
* Fallback: Regex-based for all other cases
|
|
5
|
+
* Purpose: Detect hardcoded sensitive information in source code
|
|
6
|
+
* Command: node cli.js --rules=C041 --input=examples/rule-test-fixtures/rules/C041_no_sensitive_hardcode --engine=heuristic --verbose
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const C041SymbolBasedAnalyzer = require('./symbol-based-analyzer');
|
|
3
10
|
|
|
4
11
|
class C041Analyzer {
|
|
5
|
-
constructor() {
|
|
12
|
+
constructor(options = {}) {
|
|
13
|
+
if (process.env.SUNLINT_DEBUG) {
|
|
14
|
+
console.log(`🔧 [C041] Constructor called with options:`, !!options);
|
|
15
|
+
console.log(`🔧 [C041] Options type:`, typeof options, Object.keys(options || {}));
|
|
16
|
+
}
|
|
17
|
+
|
|
6
18
|
this.ruleId = 'C041';
|
|
7
|
-
this.ruleName = '
|
|
8
|
-
this.description = '
|
|
9
|
-
|
|
19
|
+
this.ruleName = 'Do not hardcode or push sensitive information';
|
|
20
|
+
this.description = 'Protect sensitive application data, avoid security risks, and comply with security standards. Exposing sensitive information can lead to serious security and privacy issues.';
|
|
21
|
+
this.semanticEngine = options.semanticEngine || null;
|
|
22
|
+
this.verbose = options.verbose || false;
|
|
23
|
+
|
|
24
|
+
// Configuration
|
|
25
|
+
this.config = {
|
|
26
|
+
useSymbolBased: true, // Primary approach
|
|
27
|
+
fallbackToRegex: false, // Only when symbol fails completely
|
|
28
|
+
symbolBasedOnly: false // Can be set to true for pure mode
|
|
29
|
+
};
|
|
10
30
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
console.log(`🔍 Running C041 analysis on ${path.basename(filePath)}`);
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
try {
|
|
20
|
-
const content = fs.readFileSync(filePath, 'utf8');
|
|
21
|
-
const fileViolations = await this.analyzeFile(filePath, content, language, options);
|
|
22
|
-
violations.push(...fileViolations);
|
|
23
|
-
} catch (error) {
|
|
24
|
-
console.warn(`⚠️ Failed to analyze ${filePath}: ${error.message}`);
|
|
31
|
+
// Initialize both analyzers
|
|
32
|
+
try {
|
|
33
|
+
this.symbolAnalyzer = new C041SymbolBasedAnalyzer(this.semanticEngine);
|
|
34
|
+
if (process.env.SUNLINT_DEBUG) {
|
|
35
|
+
console.log(`🔧 [C041] Symbol analyzer created successfully`);
|
|
25
36
|
}
|
|
37
|
+
} catch (error) {
|
|
38
|
+
console.error(`🔧 [C041] Error creating symbol analyzer:`, error);
|
|
26
39
|
}
|
|
27
|
-
|
|
28
|
-
return violations;
|
|
29
40
|
}
|
|
30
41
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
42
|
+
/**
|
|
43
|
+
* Initialize with semantic engine
|
|
44
|
+
*/
|
|
45
|
+
async initialize(semanticEngine = null) {
|
|
46
|
+
if (semanticEngine) {
|
|
47
|
+
this.semanticEngine = semanticEngine;
|
|
48
|
+
}
|
|
49
|
+
this.verbose = semanticEngine?.verbose || false;
|
|
50
|
+
|
|
51
|
+
// Initialize both analyzers
|
|
52
|
+
await this.symbolAnalyzer.initialize(semanticEngine);
|
|
53
|
+
|
|
54
|
+
// Ensure verbose flag is propagated
|
|
55
|
+
this.symbolAnalyzer.verbose = this.verbose;
|
|
56
|
+
|
|
57
|
+
if (this.verbose) {
|
|
58
|
+
console.log(`🔧 [C041 Hybrid] Analyzer initialized - verbose: ${this.verbose}`);
|
|
38
59
|
}
|
|
39
60
|
}
|
|
40
61
|
|
|
41
|
-
async
|
|
62
|
+
async analyze(files, language, options = {}) {
|
|
63
|
+
if (process.env.SUNLINT_DEBUG) {
|
|
64
|
+
console.log(`🔧 [C041] analyze() method called with ${files.length} files, language: ${language}`);
|
|
65
|
+
}
|
|
66
|
+
|
|
42
67
|
const violations = [];
|
|
43
|
-
const lines = content.split('\n');
|
|
44
68
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
69
|
+
for (const filePath of files) {
|
|
70
|
+
try {
|
|
71
|
+
if (process.env.SUNLINT_DEBUG) {
|
|
72
|
+
console.log(`🔧 [C041] Processing file: ${filePath}`);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const fileViolations = await this.analyzeFile(filePath, options);
|
|
76
|
+
violations.push(...fileViolations);
|
|
48
77
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
78
|
+
if (process.env.SUNLINT_DEBUG) {
|
|
79
|
+
console.log(`🔧 [C041] File ${filePath}: Found ${fileViolations.length} violations`);
|
|
80
|
+
}
|
|
81
|
+
} catch (error) {
|
|
82
|
+
console.warn(`❌ [C041] Analysis failed for ${filePath}:`, error.message);
|
|
52
83
|
}
|
|
84
|
+
}
|
|
53
85
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
sensitiveMatches.forEach(match => {
|
|
58
|
-
violations.push({
|
|
59
|
-
ruleId: this.ruleId,
|
|
60
|
-
file: filePath,
|
|
61
|
-
line: lineNumber,
|
|
62
|
-
column: match.column,
|
|
63
|
-
message: match.message,
|
|
64
|
-
severity: 'error',
|
|
65
|
-
code: trimmedLine,
|
|
66
|
-
type: match.type,
|
|
67
|
-
confidence: match.confidence,
|
|
68
|
-
suggestion: match.suggestion
|
|
69
|
-
});
|
|
70
|
-
});
|
|
71
|
-
});
|
|
86
|
+
if (process.env.SUNLINT_DEBUG) {
|
|
87
|
+
console.log(`🔧 [C041] Total violations found: ${violations.length}`);
|
|
88
|
+
}
|
|
72
89
|
|
|
73
90
|
return violations;
|
|
74
91
|
}
|
|
75
92
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
trimmed.startsWith('/*') ||
|
|
80
|
-
trimmed.startsWith('*') ||
|
|
81
|
-
trimmed.startsWith('import ') ||
|
|
82
|
-
trimmed.startsWith('export ');
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
findSensitiveHardcode(line, originalLine) {
|
|
86
|
-
const matches = [];
|
|
87
|
-
|
|
88
|
-
// Skip template literals with variables - they are dynamic, not hardcoded
|
|
89
|
-
if (line.includes('${') || line.includes('`')) {
|
|
90
|
-
return matches;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
// Skip if line is clearly configuration, type definition, or UI-related
|
|
94
|
-
if (this.isConfigOrUIContext(line)) {
|
|
95
|
-
return matches;
|
|
93
|
+
async analyzeFile(filePath, options = {}) {
|
|
94
|
+
if (process.env.SUNLINT_DEBUG) {
|
|
95
|
+
console.log(`🔧 [C041] analyzeFile() called for: ${filePath}`);
|
|
96
96
|
}
|
|
97
|
-
|
|
98
|
-
// Look for suspicious patterns with better context awareness
|
|
99
|
-
const patterns = [
|
|
100
|
-
{
|
|
101
|
-
name: 'suspicious_password_variable',
|
|
102
|
-
regex: /(const|let|var)\s+\w*[Pp]ass[Ww]ord\w*\s*=\s*['"`]([^'"`]{4,})['"`]/g,
|
|
103
|
-
severity: 'error',
|
|
104
|
-
message: 'Potential hardcoded password in variable assignment',
|
|
105
|
-
suggestion: 'Move sensitive values to environment variables or secure config files'
|
|
106
|
-
},
|
|
107
|
-
{
|
|
108
|
-
name: 'suspicious_secret_variable',
|
|
109
|
-
regex: /(const|let|var)\s+\w*[Ss]ecret\w*\s*=\s*['"`]([^'"`]{6,})['"`]/g,
|
|
110
|
-
severity: 'error',
|
|
111
|
-
message: 'Potential hardcoded secret in variable assignment',
|
|
112
|
-
suggestion: 'Use environment variables for secrets'
|
|
113
|
-
},
|
|
114
|
-
{
|
|
115
|
-
name: 'suspicious_short_password',
|
|
116
|
-
regex: /(const|let|var)\s+(?!use)\w*([Pp]ass|[Dd]b[Pp]ass|[Aa]dmin)(?!word[A-Z])\w*\s*=\s*['"`]([^'"`]{4,})['"`]/g,
|
|
117
|
-
severity: 'error',
|
|
118
|
-
message: 'Potential hardcoded password or admin credential',
|
|
119
|
-
suggestion: 'Use environment variables for credentials'
|
|
120
|
-
},
|
|
121
|
-
{
|
|
122
|
-
name: 'api_key',
|
|
123
|
-
regex: /(const|let|var)\s+\w*[Aa]pi[Kk]ey\w*\s*=\s*['"`]([^'"`]{10,})['"`]/g,
|
|
124
|
-
severity: 'error',
|
|
125
|
-
message: 'Potential hardcoded API key detected',
|
|
126
|
-
suggestion: 'Use environment variables for API keys'
|
|
127
|
-
},
|
|
128
|
-
{
|
|
129
|
-
name: 'auth_token',
|
|
130
|
-
regex: /(const|let|var)\s+\w*[Tt]oken\w*\s*=\s*['"`]([^'"`]{16,})['"`]/g,
|
|
131
|
-
severity: 'error',
|
|
132
|
-
message: 'Potential hardcoded authentication token detected',
|
|
133
|
-
suggestion: 'Store tokens in secure storage, not in source code'
|
|
134
|
-
},
|
|
135
|
-
{
|
|
136
|
-
name: 'database_url',
|
|
137
|
-
regex: /['"`](mongodb|mysql|postgres|redis):\/\/[^'"`]+['"`]/gi,
|
|
138
|
-
severity: 'error',
|
|
139
|
-
message: 'Hardcoded database connection string detected',
|
|
140
|
-
suggestion: 'Use environment variables for database connections'
|
|
141
|
-
},
|
|
142
|
-
{
|
|
143
|
-
name: 'suspicious_url',
|
|
144
|
-
regex: /['"`]https?:\/\/(?!localhost|127\.0\.0\.1|example\.com|test\.com|www\.w3\.org|www\.google\.com|googleapis\.com)[^'"`]{20,}['"`]/gi,
|
|
145
|
-
severity: 'warning',
|
|
146
|
-
message: 'Hardcoded external URL detected (consider configuration)',
|
|
147
|
-
suggestion: 'Consider moving URLs to configuration files'
|
|
148
|
-
}
|
|
149
|
-
];
|
|
150
97
|
|
|
151
|
-
//
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
if (
|
|
157
|
-
|
|
98
|
+
// 1. Try Symbol-based analysis first (primary)
|
|
99
|
+
if (this.config.useSymbolBased &&
|
|
100
|
+
this.semanticEngine?.project &&
|
|
101
|
+
this.semanticEngine?.initialized) {
|
|
102
|
+
try {
|
|
103
|
+
if (process.env.SUNLINT_DEBUG) {
|
|
104
|
+
console.log(`🔧 [C041] Trying symbol-based analysis...`);
|
|
158
105
|
}
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
106
|
+
const sourceFile = this.semanticEngine.project.getSourceFile(filePath);
|
|
107
|
+
if (sourceFile) {
|
|
108
|
+
if (process.env.SUNLINT_DEBUG) {
|
|
109
|
+
console.log(`🔧 [C041] Source file found, analyzing with symbol-based...`);
|
|
110
|
+
}
|
|
111
|
+
const violations = await this.symbolAnalyzer.analyzeFileWithSymbols(filePath, { ...options, verbose: options.verbose });
|
|
112
|
+
|
|
113
|
+
// Mark violations with analysis strategy
|
|
114
|
+
violations.forEach(v => v.analysisStrategy = 'symbol-based');
|
|
115
|
+
|
|
116
|
+
if (process.env.SUNLINT_DEBUG) {
|
|
117
|
+
console.log(`✅ [C041] Symbol-based analysis: ${violations.length} violations`);
|
|
118
|
+
}
|
|
119
|
+
return violations; // Return even if 0 violations - symbol analysis completed successfully
|
|
120
|
+
} else {
|
|
121
|
+
if (process.env.SUNLINT_DEBUG) {
|
|
122
|
+
console.log(`⚠️ [C041] Source file not found in project`);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
} catch (error) {
|
|
126
|
+
console.warn(`⚠️ [C041] Symbol analysis failed: ${error.message}`);
|
|
127
|
+
// Continue to fallback
|
|
167
128
|
}
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
}
|
|
129
|
+
} else {
|
|
130
|
+
if (process.env.SUNLINT_DEBUG) {
|
|
131
|
+
console.log(`🔄 [C041] Symbol analysis conditions check:`);
|
|
132
|
+
console.log(` - useSymbolBased: ${this.config.useSymbolBased}`);
|
|
133
|
+
console.log(` - semanticEngine: ${!!this.semanticEngine}`);
|
|
134
|
+
console.log(` - semanticEngine.project: ${!!this.semanticEngine?.project}`);
|
|
135
|
+
console.log(` - semanticEngine.initialized: ${this.semanticEngine?.initialized}`);
|
|
136
|
+
console.log(`🔄 [C041] Symbol analysis unavailable, using regex fallback`);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
172
139
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
const uiContexts = [
|
|
178
|
-
'inputtype', 'type:', 'type =', 'type:', 'inputtype=',
|
|
179
|
-
'routes =', 'route:', 'path:', 'routes:',
|
|
180
|
-
'import {', 'export {', 'from ', 'import ',
|
|
181
|
-
'interface', 'type ', 'enum ',
|
|
182
|
-
'props:', 'defaultprops',
|
|
183
|
-
'schema', 'validator',
|
|
184
|
-
'hook', 'use', 'const use', 'import.*use',
|
|
185
|
-
// React/UI specific
|
|
186
|
-
'textinput', 'input ', 'field ', 'form',
|
|
187
|
-
'component', 'page', 'screen', 'modal',
|
|
188
|
-
// Route/navigation specific
|
|
189
|
-
'navigation', 'route', 'path', 'url:', 'route:',
|
|
190
|
-
'setuppassword', 'resetpassword', 'forgotpassword',
|
|
191
|
-
'changepassword', 'confirmpassword'
|
|
192
|
-
];
|
|
193
|
-
|
|
194
|
-
return uiContexts.some(context => lowerLine.includes(context));
|
|
140
|
+
if (options?.verbose) {
|
|
141
|
+
console.log(`🔧 [C041] No analysis methods succeeded, returning empty`);
|
|
142
|
+
}
|
|
143
|
+
return [];
|
|
195
144
|
}
|
|
196
145
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
146
|
+
async analyzeFileBasic(filePath, options = {}) {
|
|
147
|
+
console.log(`🔧 [C041] analyzeFileBasic() called for: ${filePath}`);
|
|
148
|
+
console.log(`🔧 [C041] semanticEngine exists: ${!!this.semanticEngine}`);
|
|
149
|
+
console.log(`🔧 [C041] symbolAnalyzer exists: ${!!this.symbolAnalyzer}`);
|
|
200
150
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
'error', 'message', 'missing', 'invalid', 'failed'
|
|
206
|
-
];
|
|
151
|
+
try {
|
|
152
|
+
// Try symbol-based analysis first
|
|
153
|
+
if (this.semanticEngine?.isSymbolEngineReady?.() &&
|
|
154
|
+
this.semanticEngine.project) {
|
|
207
155
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
);
|
|
212
|
-
|
|
213
|
-
if (hasGlobalFalsePositive) {
|
|
214
|
-
return true;
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
// Common false positive patterns
|
|
218
|
-
const falsePositivePatterns = {
|
|
219
|
-
'suspicious_password_variable': [
|
|
220
|
-
'inputtype', 'type:', 'type =', 'activation', 'forgot_password', 'reset_password',
|
|
221
|
-
'setup_password', 'route', 'path', 'hook', 'use', 'change', 'confirm',
|
|
222
|
-
'validation', 'component', 'page', 'screen', 'textinput', 'input',
|
|
223
|
-
'trigger', 'useeffect', 'password.*trigger', 'renewpassword'
|
|
224
|
-
],
|
|
225
|
-
'suspicious_short_password': [
|
|
226
|
-
'inputtype', 'type:', 'type =', 'activation', 'forgot_password', 'reset_password',
|
|
227
|
-
'setup_password', 'route', 'path', 'hook', 'use', 'change', 'confirm',
|
|
228
|
-
'validation', 'component', 'page', 'screen', 'textinput'
|
|
229
|
-
],
|
|
230
|
-
'suspicious_secret_variable': [
|
|
231
|
-
'component', 'props', 'state', 'hook', 'use'
|
|
232
|
-
],
|
|
233
|
-
'suspicious_url': [
|
|
234
|
-
'localhost', '127.0.0.1', 'example.com', 'test.com', 'placeholder',
|
|
235
|
-
'mock', 'w3.org', 'google.com', 'recaptcha', 'googleapis.com'
|
|
236
|
-
],
|
|
237
|
-
'api_key': [
|
|
238
|
-
'test-', 'mock-', 'example-', 'demo-', 'missing', 'error', 'message'
|
|
239
|
-
]
|
|
240
|
-
};
|
|
241
|
-
|
|
242
|
-
const patterns = falsePositivePatterns[patternName] || [];
|
|
243
|
-
|
|
244
|
-
// Check if line contains any pattern-specific false positive indicators
|
|
245
|
-
const hasPatternFalsePositive = patterns.some(pattern =>
|
|
246
|
-
lowerLine.includes(pattern) || lowerMatch.includes(pattern)
|
|
247
|
-
);
|
|
156
|
+
if (this.verbose) {
|
|
157
|
+
console.log(`🔍 [C041] Using symbol-based analysis for ${filePath}`);
|
|
158
|
+
}
|
|
248
159
|
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
lowerLine.includes('component') ||
|
|
256
|
-
lowerLine.includes('type') ||
|
|
257
|
-
lowerLine.includes('route') ||
|
|
258
|
-
lowerLine.includes('path') ||
|
|
259
|
-
lowerMatch.includes('activation') ||
|
|
260
|
-
lowerMatch.includes('forgot_password') ||
|
|
261
|
-
lowerMatch.includes('reset_password') ||
|
|
262
|
-
lowerMatch.includes('setup_password')) {
|
|
263
|
-
return true;
|
|
160
|
+
const violations = await this.symbolAnalyzer.analyzeFileBasic(filePath, options);
|
|
161
|
+
return violations;
|
|
162
|
+
}
|
|
163
|
+
} catch (error) {
|
|
164
|
+
if (this.verbose) {
|
|
165
|
+
console.warn(`⚠️ [C041] Symbol analysis failed: ${error.message}`);
|
|
264
166
|
}
|
|
265
167
|
}
|
|
266
|
-
|
|
267
|
-
return hasPatternFalsePositive;
|
|
268
168
|
}
|
|
269
169
|
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
if (lowerLine.includes('test') || lowerLine.includes('mock') || lowerLine.includes('example')) {
|
|
277
|
-
confidence -= 0.3;
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
if (lowerLine.includes('const') || lowerLine.includes('let') || lowerLine.includes('var')) {
|
|
281
|
-
confidence += 0.1; // Variable assignments more likely to be hardcode
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
if (lowerLine.includes('type') || lowerLine.includes('component') || lowerLine.includes('props')) {
|
|
285
|
-
confidence -= 0.2; // UI-related less likely to be sensitive
|
|
286
|
-
}
|
|
170
|
+
/**
|
|
171
|
+
* Methods for compatibility with different engine invocation patterns
|
|
172
|
+
*/
|
|
173
|
+
async analyzeFileWithSymbols(filePath, options = {}) {
|
|
174
|
+
return this.analyzeFile(filePath, options);
|
|
175
|
+
}
|
|
287
176
|
|
|
288
|
-
|
|
177
|
+
async analyzeWithSemantics(filePath, options = {}) {
|
|
178
|
+
return this.analyzeFile(filePath, options);
|
|
289
179
|
}
|
|
290
180
|
}
|
|
291
181
|
|
|
292
|
-
module.exports =
|
|
182
|
+
module.exports = C041Analyzer;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "C041",
|
|
3
|
+
"name": "C041_do_not_hardcode_or_push_sensitive_information",
|
|
4
|
+
"category": "architecture",
|
|
5
|
+
"description": "C041 - Do not hardcode or push sensitive information (token, API key, secret, URL) into the repo",
|
|
6
|
+
"severity": "warning",
|
|
7
|
+
"enabled": true,
|
|
8
|
+
"semantic": {
|
|
9
|
+
"enabled": true,
|
|
10
|
+
"priority": "high",
|
|
11
|
+
"fallback": "heuristic"
|
|
12
|
+
},
|
|
13
|
+
"patterns": {
|
|
14
|
+
"include": [
|
|
15
|
+
"**/*.js",
|
|
16
|
+
"**/*.ts",
|
|
17
|
+
"**/*.jsx",
|
|
18
|
+
"**/*.tsx"
|
|
19
|
+
],
|
|
20
|
+
"exclude": [
|
|
21
|
+
"**/*.test.*",
|
|
22
|
+
"**/*.spec.*",
|
|
23
|
+
"**/*.mock.*",
|
|
24
|
+
"**/test/**",
|
|
25
|
+
"**/tests/**",
|
|
26
|
+
"**/spec/**"
|
|
27
|
+
]
|
|
28
|
+
},
|
|
29
|
+
"options": {
|
|
30
|
+
"strictMode": false,
|
|
31
|
+
"allowedDbMethods": [],
|
|
32
|
+
"repositoryPatterns": [
|
|
33
|
+
"*Repository*",
|
|
34
|
+
"*Repo*",
|
|
35
|
+
"*DAO*",
|
|
36
|
+
"*Store*"
|
|
37
|
+
],
|
|
38
|
+
"servicePatterns": [
|
|
39
|
+
"*Service*",
|
|
40
|
+
"*UseCase*",
|
|
41
|
+
"*Handler*",
|
|
42
|
+
"*Manager*"
|
|
43
|
+
],
|
|
44
|
+
"complexityThreshold": {
|
|
45
|
+
"methodLength": 200,
|
|
46
|
+
"cyclomaticComplexity": 5,
|
|
47
|
+
"nestedDepth": 3
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|