@sun-asterisk/sunlint 1.3.6 → 1.3.8

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 (50) hide show
  1. package/CHANGELOG.md +76 -1
  2. package/config/defaults/default.json +2 -1
  3. package/config/rule-analysis-strategies.js +20 -0
  4. package/config/rules/enhanced-rules-registry.json +230 -43
  5. package/core/analysis-orchestrator.js +9 -5
  6. package/core/file-targeting-service.js +83 -7
  7. package/core/performance-optimizer.js +8 -2
  8. package/package.json +1 -1
  9. package/rules/common/C065_one_behavior_per_test/analyzer.js +851 -0
  10. package/rules/common/C065_one_behavior_per_test/config.json +95 -0
  11. package/rules/common/C073_validate_required_config_on_startup/README.md +110 -0
  12. package/rules/common/C073_validate_required_config_on_startup/analyzer.js +770 -0
  13. package/rules/common/C073_validate_required_config_on_startup/config.json +46 -0
  14. package/rules/common/C073_validate_required_config_on_startup/symbol-based-analyzer.js +370 -0
  15. package/rules/security/S037_cache_headers/README.md +128 -0
  16. package/rules/security/S037_cache_headers/analyzer.js +263 -0
  17. package/rules/security/S037_cache_headers/config.json +50 -0
  18. package/rules/security/S037_cache_headers/regex-based-analyzer.js +463 -0
  19. package/rules/security/S037_cache_headers/symbol-based-analyzer.js +546 -0
  20. package/rules/security/S038_no_version_headers/README.md +234 -0
  21. package/rules/security/S038_no_version_headers/analyzer.js +262 -0
  22. package/rules/security/S038_no_version_headers/config.json +49 -0
  23. package/rules/security/S038_no_version_headers/regex-based-analyzer.js +339 -0
  24. package/rules/security/S038_no_version_headers/symbol-based-analyzer.js +375 -0
  25. package/rules/security/S039_no_session_tokens_in_url/README.md +198 -0
  26. package/rules/security/S039_no_session_tokens_in_url/analyzer.js +262 -0
  27. package/rules/security/S039_no_session_tokens_in_url/config.json +92 -0
  28. package/rules/security/S039_no_session_tokens_in_url/regex-based-analyzer.js +337 -0
  29. package/rules/security/S039_no_session_tokens_in_url/symbol-based-analyzer.js +436 -0
  30. package/rules/security/S049_short_validity_tokens/analyzer.js +175 -0
  31. package/rules/security/S049_short_validity_tokens/config.json +124 -0
  32. package/rules/security/S049_short_validity_tokens/regex-based-analyzer.js +295 -0
  33. package/rules/security/S049_short_validity_tokens/symbol-based-analyzer.js +389 -0
  34. package/rules/security/S051_password_length_policy/analyzer.js +410 -0
  35. package/rules/security/S051_password_length_policy/config.json +83 -0
  36. package/rules/security/S052_weak_otp_entropy/analyzer.js +403 -0
  37. package/rules/security/S052_weak_otp_entropy/config.json +57 -0
  38. package/rules/security/S054_no_default_accounts/README.md +129 -0
  39. package/rules/security/S054_no_default_accounts/analyzer.js +792 -0
  40. package/rules/security/S054_no_default_accounts/config.json +101 -0
  41. package/rules/security/S056_log_injection_protection/analyzer.js +242 -0
  42. package/rules/security/S056_log_injection_protection/config.json +148 -0
  43. package/rules/security/S056_log_injection_protection/regex-based-analyzer.js +120 -0
  44. package/rules/security/S056_log_injection_protection/symbol-based-analyzer.js +287 -0
  45. package/rules/security/S057_utc_logging/README.md +152 -0
  46. package/rules/security/S057_utc_logging/analyzer.js +457 -0
  47. package/rules/security/S057_utc_logging/config.json +105 -0
  48. package/rules/security/S058_no_ssrf/README.md +180 -0
  49. package/rules/security/S058_no_ssrf/analyzer.js +403 -0
  50. package/rules/security/S058_no_ssrf/config.json +125 -0
@@ -16,7 +16,7 @@ class FileTargetingService {
16
16
 
17
17
  /**
18
18
  * Get target files based on enhanced configuration
19
- * ENHANCED: Uses metadata for intelligent file targeting
19
+ * ENHANCED: Uses metadata for intelligent file targeting with smart project-level optimization
20
20
  */
21
21
  async getTargetFiles(inputPaths, config, cliOptions = {}) {
22
22
  try {
@@ -32,11 +32,14 @@ class FileTargetingService {
32
32
 
33
33
  let allFiles = [];
34
34
 
35
+ // Smart project-level optimization
36
+ const optimizedPaths = this.optimizeProjectPaths(inputPaths, cliOptions);
37
+
35
38
  // Use enhanced targeting based on metadata
36
39
  if (metadata?.shouldBypassProjectDiscovery) {
37
- allFiles = await this.collectTargetedFiles(inputPaths, config, cliOptions);
40
+ allFiles = await this.collectTargetedFiles(optimizedPaths, config, cliOptions);
38
41
  } else {
39
- allFiles = await this.collectProjectFiles(inputPaths, config, cliOptions);
42
+ allFiles = await this.collectProjectFiles(optimizedPaths, config, cliOptions);
40
43
  }
41
44
 
42
45
  // Apply filtering logic
@@ -150,13 +153,69 @@ class FileTargetingService {
150
153
  return allFiles;
151
154
  }
152
155
 
156
+ /**
157
+ * Optimize project paths to focus on source and test directories
158
+ * Prevents unnecessary scanning of entire project when smart targeting is possible
159
+ */
160
+ optimizeProjectPaths(inputPaths, cliOptions = {}) {
161
+ const optimizedPaths = [];
162
+
163
+ for (const inputPath of inputPaths) {
164
+ // If targeting entire project directory, try to find source/test subdirectories
165
+ if (fs.existsSync(inputPath) && fs.statSync(inputPath).isDirectory()) {
166
+ const projectOptimization = this.findProjectSourceDirs(inputPath, cliOptions);
167
+ if (projectOptimization.length > 0) {
168
+ if (cliOptions.verbose) {
169
+ console.log(chalk.blue(`🎯 Smart targeting: Found ${projectOptimization.length} source directories in ${path.basename(inputPath)}`));
170
+ }
171
+ optimizedPaths.push(...projectOptimization);
172
+ } else {
173
+ optimizedPaths.push(inputPath);
174
+ }
175
+ } else {
176
+ optimizedPaths.push(inputPath);
177
+ }
178
+ }
179
+
180
+ return optimizedPaths;
181
+ }
182
+
183
+ /**
184
+ * Find source directories in project to avoid scanning entire project
185
+ */
186
+ findProjectSourceDirs(projectPath, cliOptions = {}) {
187
+ const sourceDirs = [];
188
+ const candidateDirs = ['src', 'lib', 'app', 'packages'];
189
+ const testDirs = ['test', 'tests', '__tests__', 'spec', 'specs'];
190
+
191
+ // Always include test directories if --include-tests flag is used
192
+ const dirsToCheck = cliOptions.includeTests ? [...candidateDirs, ...testDirs] : candidateDirs;
193
+
194
+ for (const dir of dirsToCheck) {
195
+ const dirPath = path.join(projectPath, dir);
196
+ if (fs.existsSync(dirPath) && fs.statSync(dirPath).isDirectory()) {
197
+ sourceDirs.push(dirPath);
198
+ }
199
+ }
200
+
201
+ return sourceDirs;
202
+ }
203
+
153
204
  /**
154
205
  * Check if directory should be skipped
206
+ * Enhanced with more comprehensive ignore patterns
207
+ * Enhanced with more comprehensive ignore patterns
155
208
  */
156
209
  shouldSkipDirectory(dirName) {
157
210
  const skipDirs = [
158
211
  'node_modules', '.git', 'dist', 'build', 'coverage',
159
- '.next', '.nuxt', 'vendor', 'target', 'generated'
212
+ '.next', '.nuxt', 'vendor', 'target', 'generated',
213
+ '.vscode', '.id',
214
+ '.vscode', '.idea', '.husky', '.github', '.yarn',
215
+ 'out', 'public', 'static', 'assets', 'tmp', 'temp',
216
+ 'cache', '.cache', 'logs', 'logea', '.husky', '.github', '.yarn',
217
+ 'out', 'public', 'static', 'assets', 'tmp', 'temp',
218
+ 'cache', '.cache', 'logs', 'log'
160
219
  ];
161
220
  return skipDirs.includes(dirName);
162
221
  }
@@ -278,10 +337,27 @@ class FileTargetingService {
278
337
  if (debug) console.log(`🔍 [DEBUG] After include patterns ${langConfig.include}: ${langFiles.length} files`);
279
338
  }
280
339
 
281
- // Apply language-specific exclude patterns
340
+ // Apply language-specific exclude patterns (but respect --include-tests for test files)
282
341
  if (langConfig.exclude && langConfig.exclude.length > 0) {
283
- langFiles = this.applyExcludePatterns(langFiles, langConfig.exclude, debug);
284
- if (debug) console.log(`🔍 [DEBUG] After exclude patterns ${langConfig.exclude}: ${langFiles.length} files`);
342
+ // Skip test-related exclude patterns if --include-tests is enabled
343
+ let effectiveExcludes = langConfig.exclude;
344
+ if (cliOptions.includeTests === true) {
345
+ // Remove test-related patterns completely
346
+ effectiveExcludes = langConfig.exclude.filter(pattern => {
347
+ const isTestPattern = pattern.includes('.test.') || pattern.includes('.spec.') ||
348
+ pattern.includes('/test/') || pattern.includes('/tests/') ||
349
+ pattern.includes('/__tests__/');
350
+ return !isTestPattern;
351
+ });
352
+ if (debug) console.log(`🔍 [DEBUG] --include-tests enabled, filtered excludes: ${effectiveExcludes}`);
353
+ }
354
+
355
+ if (effectiveExcludes.length > 0) {
356
+ langFiles = this.applyExcludePatterns(langFiles, effectiveExcludes, debug);
357
+ if (debug) console.log(`🔍 [DEBUG] After exclude patterns ${effectiveExcludes}: ${langFiles.length} files`);
358
+ } else {
359
+ if (debug) console.log(`🔍 [DEBUG] All exclude patterns filtered out by --include-tests`);
360
+ }
285
361
  }
286
362
 
287
363
  languageFiles.push(...langFiles);
@@ -26,6 +26,12 @@ class PerformanceOptimizer {
26
26
  ...DEFAULT_PERFORMANCE,
27
27
  ...config
28
28
  };
29
+
30
+ // Override maxTotalFiles if provided in config
31
+ if (config.maxFiles !== undefined) {
32
+ this.fileSizeLimits.maxTotalFiles = config.maxFiles;
33
+ }
34
+
29
35
  this.initialized = true;
30
36
  }
31
37
 
@@ -106,8 +112,8 @@ class PerformanceOptimizer {
106
112
  break;
107
113
  }
108
114
 
109
- // Check file count limit
110
- if (filtered.length >= this.fileSizeLimits.maxTotalFiles) {
115
+ // Check file count limit (skip if unlimited -1)
116
+ if (this.fileSizeLimits.maxTotalFiles > 0 && filtered.length >= this.fileSizeLimits.maxTotalFiles) {
111
117
  if (this.config.verbose) {
112
118
  console.log(`⚠️ Reached file count limit: ${this.fileSizeLimits.maxTotalFiles} files`);
113
119
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sun-asterisk/sunlint",
3
- "version": "1.3.6",
3
+ "version": "1.3.8",
4
4
  "description": "☀️ SunLint - Multi-language static analysis tool for code quality and security | Sun* Engineering Standards",
5
5
  "main": "cli.js",
6
6
  "bin": {