@sun-asterisk/sunlint 1.3.7 → 1.3.9

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 (51) hide show
  1. package/CHANGELOG.md +63 -0
  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 +247 -53
  5. package/core/file-targeting-service.js +98 -7
  6. package/package.json +1 -1
  7. package/rules/common/C065_one_behavior_per_test/analyzer.js +851 -0
  8. package/rules/common/C065_one_behavior_per_test/config.json +95 -0
  9. package/rules/security/S020_no_eval_dynamic_code/README.md +136 -0
  10. package/rules/security/S020_no_eval_dynamic_code/analyzer.js +263 -0
  11. package/rules/security/S020_no_eval_dynamic_code/config.json +54 -0
  12. package/rules/security/S020_no_eval_dynamic_code/regex-based-analyzer.js +307 -0
  13. package/rules/security/S020_no_eval_dynamic_code/symbol-based-analyzer.js +280 -0
  14. package/rules/security/S024_xpath_xxe_protection/symbol-based-analyzer.js +3 -3
  15. package/rules/security/S025_server_side_validation/symbol-based-analyzer.js +3 -4
  16. package/rules/security/S030_directory_browsing_protection/README.md +128 -0
  17. package/rules/security/S030_directory_browsing_protection/analyzer.js +264 -0
  18. package/rules/security/S030_directory_browsing_protection/config.json +63 -0
  19. package/rules/security/S030_directory_browsing_protection/regex-based-analyzer.js +483 -0
  20. package/rules/security/S030_directory_browsing_protection/symbol-based-analyzer.js +539 -0
  21. package/rules/security/S033_samesite_session_cookies/symbol-based-analyzer.js +8 -9
  22. package/rules/security/S037_cache_headers/README.md +128 -0
  23. package/rules/security/S037_cache_headers/analyzer.js +263 -0
  24. package/rules/security/S037_cache_headers/config.json +50 -0
  25. package/rules/security/S037_cache_headers/regex-based-analyzer.js +463 -0
  26. package/rules/security/S037_cache_headers/symbol-based-analyzer.js +546 -0
  27. package/rules/security/S038_no_version_headers/README.md +234 -0
  28. package/rules/security/S038_no_version_headers/analyzer.js +262 -0
  29. package/rules/security/S038_no_version_headers/config.json +49 -0
  30. package/rules/security/S038_no_version_headers/regex-based-analyzer.js +339 -0
  31. package/rules/security/S038_no_version_headers/symbol-based-analyzer.js +375 -0
  32. package/rules/security/S039_no_session_tokens_in_url/README.md +198 -0
  33. package/rules/security/S039_no_session_tokens_in_url/analyzer.js +262 -0
  34. package/rules/security/S039_no_session_tokens_in_url/config.json +92 -0
  35. package/rules/security/S039_no_session_tokens_in_url/regex-based-analyzer.js +337 -0
  36. package/rules/security/S039_no_session_tokens_in_url/symbol-based-analyzer.js +443 -0
  37. package/rules/security/S049_short_validity_tokens/analyzer.js +175 -0
  38. package/rules/security/S049_short_validity_tokens/config.json +124 -0
  39. package/rules/security/S049_short_validity_tokens/regex-based-analyzer.js +295 -0
  40. package/rules/security/S049_short_validity_tokens/symbol-based-analyzer.js +389 -0
  41. package/rules/security/S051_password_length_policy/analyzer.js +410 -0
  42. package/rules/security/S051_password_length_policy/config.json +83 -0
  43. package/rules/security/S052_weak_otp_entropy/analyzer.js +403 -0
  44. package/rules/security/S052_weak_otp_entropy/config.json +57 -0
  45. package/rules/security/S054_no_default_accounts/README.md +129 -0
  46. package/rules/security/S054_no_default_accounts/analyzer.js +792 -0
  47. package/rules/security/S054_no_default_accounts/config.json +101 -0
  48. package/rules/security/S056_log_injection_protection/analyzer.js +242 -0
  49. package/rules/security/S056_log_injection_protection/config.json +148 -0
  50. package/rules/security/S056_log_injection_protection/regex-based-analyzer.js +120 -0
  51. package/rules/security/S056_log_injection_protection/symbol-based-analyzer.js +246 -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,84 @@ 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 absoluteInputPath = path.resolve(inputPath);
167
+ const inputDirName = path.basename(absoluteInputPath);
168
+
169
+ // If user already specified a source directory (src, lib, app, packages, test, etc.),
170
+ // don't try to optimize further - use it as is
171
+ const sourceDirectoryNames = ['src', 'lib', 'app', 'packages', 'test', 'tests', '__tests__', 'spec', 'specs'];
172
+ if (sourceDirectoryNames.includes(inputDirName)) {
173
+ if (cliOptions.verbose) {
174
+ console.log(chalk.blue(`🎯 Direct targeting: Using specified source directory ${inputDirName}`));
175
+ }
176
+ optimizedPaths.push(inputPath);
177
+ continue;
178
+ }
179
+
180
+ // Only optimize if this appears to be a project root directory
181
+ const projectOptimization = this.findProjectSourceDirs(inputPath, cliOptions);
182
+ if (projectOptimization.length > 0) {
183
+ if (cliOptions.verbose) {
184
+ console.log(chalk.blue(`🎯 Smart targeting: Found ${projectOptimization.length} source directories in ${path.basename(inputPath)}`));
185
+ }
186
+ optimizedPaths.push(...projectOptimization);
187
+ } else {
188
+ optimizedPaths.push(inputPath);
189
+ }
190
+ } else {
191
+ optimizedPaths.push(inputPath);
192
+ }
193
+ }
194
+
195
+ return optimizedPaths;
196
+ }
197
+
198
+ /**
199
+ * Find source directories in project to avoid scanning entire project
200
+ */
201
+ findProjectSourceDirs(projectPath, cliOptions = {}) {
202
+ const sourceDirs = [];
203
+ const candidateDirs = ['src', 'lib', 'app', 'packages'];
204
+ const testDirs = ['test', 'tests', '__tests__', 'spec', 'specs'];
205
+
206
+ // Always include test directories if --include-tests flag is used
207
+ const dirsToCheck = cliOptions.includeTests ? [...candidateDirs, ...testDirs] : candidateDirs;
208
+
209
+ for (const dir of dirsToCheck) {
210
+ const dirPath = path.join(projectPath, dir);
211
+ if (fs.existsSync(dirPath) && fs.statSync(dirPath).isDirectory()) {
212
+ sourceDirs.push(dirPath);
213
+ }
214
+ }
215
+
216
+ return sourceDirs;
217
+ }
218
+
153
219
  /**
154
220
  * Check if directory should be skipped
221
+ * Enhanced with more comprehensive ignore patterns
222
+ * Enhanced with more comprehensive ignore patterns
155
223
  */
156
224
  shouldSkipDirectory(dirName) {
157
225
  const skipDirs = [
158
226
  'node_modules', '.git', 'dist', 'build', 'coverage',
159
- '.next', '.nuxt', 'vendor', 'target', 'generated'
227
+ '.next', '.nuxt', 'vendor', 'target', 'generated',
228
+ '.vscode', '.id',
229
+ '.vscode', '.idea', '.husky', '.github', '.yarn',
230
+ 'out', 'public', 'static', 'assets', 'tmp', 'temp',
231
+ 'cache', '.cache', 'logs', 'logea', '.husky', '.github', '.yarn',
232
+ 'out', 'public', 'static', 'assets', 'tmp', 'temp',
233
+ 'cache', '.cache', 'logs', 'log'
160
234
  ];
161
235
  return skipDirs.includes(dirName);
162
236
  }
@@ -278,10 +352,27 @@ class FileTargetingService {
278
352
  if (debug) console.log(`🔍 [DEBUG] After include patterns ${langConfig.include}: ${langFiles.length} files`);
279
353
  }
280
354
 
281
- // Apply language-specific exclude patterns
355
+ // Apply language-specific exclude patterns (but respect --include-tests for test files)
282
356
  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`);
357
+ // Skip test-related exclude patterns if --include-tests is enabled
358
+ let effectiveExcludes = langConfig.exclude;
359
+ if (cliOptions.includeTests === true) {
360
+ // Remove test-related patterns completely
361
+ effectiveExcludes = langConfig.exclude.filter(pattern => {
362
+ const isTestPattern = pattern.includes('.test.') || pattern.includes('.spec.') ||
363
+ pattern.includes('/test/') || pattern.includes('/tests/') ||
364
+ pattern.includes('/__tests__/');
365
+ return !isTestPattern;
366
+ });
367
+ if (debug) console.log(`🔍 [DEBUG] --include-tests enabled, filtered excludes: ${effectiveExcludes}`);
368
+ }
369
+
370
+ if (effectiveExcludes.length > 0) {
371
+ langFiles = this.applyExcludePatterns(langFiles, effectiveExcludes, debug);
372
+ if (debug) console.log(`🔍 [DEBUG] After exclude patterns ${effectiveExcludes}: ${langFiles.length} files`);
373
+ } else {
374
+ if (debug) console.log(`🔍 [DEBUG] All exclude patterns filtered out by --include-tests`);
375
+ }
285
376
  }
286
377
 
287
378
  languageFiles.push(...langFiles);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sun-asterisk/sunlint",
3
- "version": "1.3.7",
3
+ "version": "1.3.9",
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": {