@sun-asterisk/sunlint 1.2.2 → 1.3.1

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 (124) hide show
  1. package/CHANGELOG.md +107 -1
  2. package/CONTRIBUTING.md +1654 -66
  3. package/README.md +19 -6
  4. package/config/ci-cd.json +54 -0
  5. package/config/development.json +56 -0
  6. package/config/engines/engines-enhanced.json +86 -0
  7. package/config/engines/semantic-config.json +114 -0
  8. package/config/eslint-rule-mapping.json +50 -38
  9. package/config/large-project.json +143 -0
  10. package/config/presets/all.json +0 -1
  11. package/config/release.json +70 -0
  12. package/config/rule-analysis-strategies.js +23 -4
  13. package/config/rules/S027-categories.json +122 -0
  14. package/config/rules/enhanced-rules-registry.json +2564 -0
  15. package/config/rules/rules-registry-generated.json +785 -837
  16. package/config/rules/rules-registry.json +13 -1
  17. package/core/adapters/sunlint-rule-adapter.js +25 -30
  18. package/core/analysis-orchestrator.js +42 -2
  19. package/core/categories.js +52 -0
  20. package/core/category-constants.js +39 -0
  21. package/core/cli-action-handler.js +53 -32
  22. package/core/cli-program.js +11 -3
  23. package/core/config-manager.js +111 -0
  24. package/core/config-merger.js +88 -0
  25. package/core/constants/categories.js +168 -0
  26. package/core/constants/defaults.js +165 -0
  27. package/core/constants/engines.js +185 -0
  28. package/core/constants/index.js +30 -0
  29. package/core/constants/rules.js +215 -0
  30. package/core/enhanced-rules-registry.js +3 -3
  31. package/core/file-targeting-service.js +128 -7
  32. package/core/interfaces/rule-plugin.interface.js +207 -0
  33. package/core/plugin-manager.js +448 -0
  34. package/core/rule-selection-service.js +42 -15
  35. package/core/semantic-engine.js +658 -0
  36. package/core/semantic-rule-base.js +433 -0
  37. package/core/unified-rule-registry.js +484 -0
  38. package/docs/COMMAND-EXAMPLES.md +134 -0
  39. package/docs/CONSTANTS-ARCHITECTURE.md +288 -0
  40. package/docs/LARGE-PROJECT-GUIDE.md +324 -0
  41. package/engines/core/base-engine.js +249 -0
  42. package/engines/engine-factory.js +275 -0
  43. package/engines/eslint-engine.js +171 -19
  44. package/engines/heuristic-engine.js +569 -78
  45. package/integrations/eslint/plugin/index.js +26 -28
  46. package/origin-rules/common-en.md +8 -8
  47. package/package.json +10 -6
  48. package/rules/common/C003_no_vague_abbreviations/analyzer.js +1 -1
  49. package/rules/common/C017_constructor_logic/analyzer.js +254 -17
  50. package/rules/common/C017_constructor_logic/semantic-analyzer.js +340 -0
  51. package/rules/common/C029_catch_block_logging/analyzer.js +17 -5
  52. package/rules/common/C033_separate_service_repository/README.md +78 -0
  53. package/rules/common/C033_separate_service_repository/analyzer.js +160 -0
  54. package/rules/common/C033_separate_service_repository/config.json +50 -0
  55. package/rules/common/C033_separate_service_repository/regex-based-analyzer.js +585 -0
  56. package/rules/common/C033_separate_service_repository/symbol-based-analyzer.js +368 -0
  57. package/rules/common/C035_error_logging_context/STRATEGY.md +99 -0
  58. package/rules/common/C035_error_logging_context/analyzer.js +230 -0
  59. package/rules/common/C035_error_logging_context/config.json +54 -0
  60. package/rules/common/C035_error_logging_context/regex-based-analyzer.js +299 -0
  61. package/rules/common/C035_error_logging_context/symbol-based-analyzer.js +454 -0
  62. package/rules/common/C040_centralized_validation/analyzer.js +165 -0
  63. package/rules/common/C040_centralized_validation/config.json +46 -0
  64. package/rules/common/C040_centralized_validation/regex-based-analyzer.js +243 -0
  65. package/rules/common/C040_centralized_validation/symbol-based-analyzer.js +416 -0
  66. package/rules/common/C047_no_duplicate_retry_logic/c047-semantic-rule.js +278 -0
  67. package/rules/common/C047_no_duplicate_retry_logic/symbol-analyzer-enhanced.js +968 -0
  68. package/rules/common/C047_no_duplicate_retry_logic/symbol-config.json +71 -0
  69. package/rules/common/{C076_single_test_behavior → C072_single_test_behavior}/analyzer.js +6 -6
  70. package/rules/common/C076_explicit_function_types/README.md +30 -0
  71. package/rules/common/C076_explicit_function_types/analyzer.js +172 -0
  72. package/rules/common/C076_explicit_function_types/config.json +15 -0
  73. package/rules/common/C076_explicit_function_types/semantic-analyzer.js +341 -0
  74. package/rules/index.js +8 -0
  75. package/rules/parser/rule-parser.js +13 -2
  76. package/rules/security/S005_no_origin_auth/README.md +226 -0
  77. package/rules/security/S005_no_origin_auth/analyzer.js +184 -0
  78. package/rules/security/S005_no_origin_auth/ast-analyzer.js +406 -0
  79. package/rules/security/S005_no_origin_auth/config.json +85 -0
  80. package/rules/security/S006_no_plaintext_recovery_codes/README.md +139 -0
  81. package/rules/security/S006_no_plaintext_recovery_codes/analyzer.js +306 -0
  82. package/rules/security/S006_no_plaintext_recovery_codes/config.json +48 -0
  83. package/rules/security/S007_no_plaintext_otp/README.md +198 -0
  84. package/rules/security/S007_no_plaintext_otp/analyzer.js +406 -0
  85. package/rules/security/S007_no_plaintext_otp/config.json +79 -0
  86. package/rules/security/S007_no_plaintext_otp/semantic-analyzer.js +609 -0
  87. package/rules/security/S007_no_plaintext_otp/semantic-config.json +195 -0
  88. package/rules/security/S007_no_plaintext_otp/semantic-wrapper.js +280 -0
  89. package/rules/security/S027_no_hardcoded_secrets/analyzer.js +180 -366
  90. package/rules/security/S027_no_hardcoded_secrets/categories.json +153 -0
  91. package/rules/security/S027_no_hardcoded_secrets/categorized-analyzer.js +250 -0
  92. package/scripts/category-manager.js +150 -0
  93. package/scripts/generate-rules-registry.js +88 -0
  94. package/scripts/migrate-rule-registry.js +157 -0
  95. package/scripts/prepare-release.sh +1 -1
  96. package/scripts/validate-system.js +48 -0
  97. package/.sunlint.json +0 -35
  98. package/config/README.md +0 -88
  99. package/config/engines/eslint-rule-mapping.json +0 -74
  100. package/config/schemas/sunlint-schema.json +0 -0
  101. package/config/testing/test-s005-working.ts +0 -22
  102. package/core/multi-rule-runner.js +0 -0
  103. package/docs/ESLINT-INTEGRATION-STRATEGY.md +0 -392
  104. package/docs/FUTURE_PACKAGES.md +0 -83
  105. package/docs/HEURISTIC_VS_AI.md +0 -113
  106. package/docs/PRODUCTION_DEPLOYMENT_ANALYSIS.md +0 -112
  107. package/docs/PRODUCTION_SIZE_IMPACT.md +0 -183
  108. package/docs/RELEASE_GUIDE.md +0 -230
  109. package/docs/STANDARDIZED-CATEGORY-FILTERING.md +0 -156
  110. package/engines/tree-sitter-parser.js +0 -0
  111. package/engines/universal-ast-engine.js +0 -0
  112. package/integrations/eslint/plugin/rules/common/c076-single-behavior-per-test.js +0 -254
  113. package/rules/common/C029_catch_block_logging/analyzer-backup.js +0 -426
  114. package/rules/common/C029_catch_block_logging/analyzer-fixed.js +0 -130
  115. package/rules/common/C029_catch_block_logging/analyzer-multi-tech.js +0 -487
  116. package/rules/common/C029_catch_block_logging/analyzer-simple.js +0 -110
  117. package/rules/common/C029_catch_block_logging/ast-analyzer-backup.js +0 -441
  118. package/rules/common/C029_catch_block_logging/ast-analyzer-new.js +0 -127
  119. package/rules/common/C029_catch_block_logging/ast-analyzer.js +0 -133
  120. package/rules/common/C029_catch_block_logging/cfg-analyzer.js +0 -408
  121. package/rules/common/C029_catch_block_logging/dataflow-analyzer.js +0 -454
  122. package/rules/common/C029_catch_block_logging/multi-language-ast-engine.js +0 -700
  123. package/rules/common/C029_catch_block_logging/pattern-learning-analyzer.js +0 -568
  124. package/rules/common/C029_catch_block_logging/semantic-analyzer.js +0 -459
@@ -0,0 +1,54 @@
1
+ {
2
+ "id": "C035_error_logging_context",
3
+ "name": "C035_error_logging_context",
4
+ "category": "architecture",
5
+ "description": "C035 - Khi xử lý lỗi, phải ghi log đầy đủ thông tin liên quan",
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.js",
22
+ "**/*.test.ts",
23
+ "**/*.spec.js",
24
+ "**/*.spec.ts",
25
+ "**/node_modules/**",
26
+ "**/dist/**",
27
+ "**/build/**"
28
+ ]
29
+ },
30
+ "analysis": {
31
+ "approach": "symbol-based-primary",
32
+ "fallback": "regex-based",
33
+ "depth": 2,
34
+ "timeout": 5000
35
+ },
36
+ "validation": {
37
+ "requiredContext": [
38
+ "error_message",
39
+ "identifier",
40
+ "context"
41
+ ],
42
+ "sensitivePatterns": [
43
+ "password", "passwd", "pwd",
44
+ "token", "jwt", "auth", "secret",
45
+ "key", "apikey", "privatekey",
46
+ "ssn", "credit", "card", "cvv"
47
+ ],
48
+ "loggerPatterns": [
49
+ "console.log", "console.error", "console.warn",
50
+ "logger.log", "logger.error", "logger.warn", "logger.info",
51
+ "log.error", "log.warn", "log.info"
52
+ ]
53
+ }
54
+ }
@@ -0,0 +1,299 @@
1
+ /**
2
+ * C035 Regex-based Analyzer - Basic Error Logging Context Detection
3
+ * Purpose: Fallback pattern matching when symbol analysis fails
4
+ */
5
+
6
+ class C035RegexBasedAnalyzer {
7
+ constructor(semanticEngine = null) {
8
+ this.ruleId = 'C035';
9
+ this.ruleName = 'Error Logging Context Analysis (Regex-Based)';
10
+ this.semanticEngine = semanticEngine;
11
+ this.verbose = false;
12
+
13
+ // Patterns for identifying catch blocks (supports TypeScript type annotations)
14
+ this.catchPattern = /catch\s*\(\s*(\w+)(?:\s*:\s*\w+(?:\s*\|\s*\w+)*)?\s*\)\s*\{([^{}]*(?:\{[^{}]*\}[^{}]*)*)\}/gs;
15
+ this.logPatterns = [
16
+ /console\.(log|error|warn|info)\s*\(/g,
17
+ /logger\.(log|error|warn|info|debug)\s*\(/g,
18
+ /log\.(error|warn|info|debug)\s*\(/g
19
+ ];
20
+
21
+ // Sensitive data patterns
22
+ this.sensitivePatterns = [
23
+ /password|passwd|pwd/gi,
24
+ /token|jwt|auth|secret|key/gi,
25
+ /ssn|social|credit|card|cvv/gi
26
+ ];
27
+
28
+ // String concatenation patterns (non-structured)
29
+ this.stringConcatPatterns = [
30
+ /\+\s*["'`]/g, // string concatenation
31
+ /["'`]\s*\+/g, // string concatenation
32
+ /\$\{.*\}/g // template literals (basic)
33
+ ];
34
+ }
35
+
36
+ async initialize(semanticEngine = null) {
37
+ if (semanticEngine) {
38
+ this.semanticEngine = semanticEngine;
39
+ }
40
+ this.verbose = semanticEngine?.verbose || false;
41
+
42
+ if (this.verbose) {
43
+ console.log(`🔧 [C035 Regex-Based] Analyzer initialized`);
44
+ }
45
+ }
46
+
47
+ async analyzeFileBasic(filePath, options = {}) {
48
+ const fs = require('fs');
49
+ const path = require('path');
50
+ const violations = [];
51
+
52
+ if (this.verbose) {
53
+ console.log(`🔧 [C035 Regex] Starting analysis for: ${filePath}`);
54
+ }
55
+
56
+ try {
57
+ const content = fs.readFileSync(filePath, 'utf8');
58
+
59
+ if (this.verbose) {
60
+ console.log(`🔧 [C035 Regex] File content length: ${content.length}`);
61
+ }
62
+
63
+ const lines = content.split('\n');
64
+ const catchBlocks = this.findCatchBlocks(content);
65
+
66
+ if (this.verbose) {
67
+ console.log(`🔧 [C035 Regex] Found ${catchBlocks.length} catch blocks`);
68
+ }
69
+
70
+ for (const block of catchBlocks) {
71
+ const blockViolations = this.analyzeCatchBlockContent(block, lines, filePath);
72
+ if (this.verbose && blockViolations.length > 0) {
73
+ console.log(`🔧 [C035 Regex] Block violations: ${blockViolations.length}`);
74
+ }
75
+ violations.push(...blockViolations);
76
+ }
77
+
78
+ if (this.verbose) {
79
+ console.log(`🔧 [C035 Regex] Total violations found: ${violations.length}`);
80
+ }
81
+
82
+ return violations;
83
+ } catch (error) {
84
+ if (this.verbose) {
85
+ console.error(`🔧 [C035 Regex] Error analyzing ${filePath}:`, error);
86
+ }
87
+ return [];
88
+ }
89
+ } /**
90
+ * Find catch blocks in content using regex
91
+ */
92
+ findCatchBlocks(content) {
93
+ const catchBlocks = [];
94
+ let match;
95
+
96
+ // Reset regex
97
+ this.catchPattern.lastIndex = 0;
98
+
99
+ while ((match = this.catchPattern.exec(content)) !== null) {
100
+ const fullMatch = match[0];
101
+ const errorVar = match[1];
102
+ const blockContent = match[2];
103
+
104
+ // Calculate line number
105
+ const beforeMatch = content.substring(0, match.index);
106
+ const lineNumber = beforeMatch.split('\n').length;
107
+
108
+ catchBlocks.push({
109
+ fullMatch,
110
+ errorVar,
111
+ blockContent,
112
+ lineNumber,
113
+ startIndex: match.index
114
+ });
115
+ }
116
+
117
+ return catchBlocks;
118
+ }
119
+
120
+ /**
121
+ * Analyze catch block content for logging violations
122
+ */
123
+ analyzeCatchBlockContent(catchBlock, lines, filePath) {
124
+ const violations = [];
125
+ const { blockContent, lineNumber, errorVar } = catchBlock;
126
+
127
+ // Find log calls in catch block
128
+ const logCalls = this.findLogCallsInContent(blockContent);
129
+
130
+ if (logCalls.length === 0) {
131
+ // No logging - C029's concern, not ours
132
+ return violations;
133
+ }
134
+
135
+ // Analyze each log call
136
+ for (const logCall of logCalls) {
137
+ const logLineNumber = lineNumber + logCall.relativeLineNumber;
138
+
139
+ // Check for non-structured logging (string concatenation)
140
+ if (this.hasStringConcatenation(logCall.content)) {
141
+ violations.push({
142
+ ruleId: this.ruleId,
143
+ severity: 'warning',
144
+ message: 'Error logging should use structured format instead of string concatenation',
145
+ source: this.ruleId,
146
+ file: filePath,
147
+ line: logLineNumber,
148
+ column: logCall.column,
149
+ description: `[REGEX-FALLBACK] String concatenation detected in error logging. Use structured object format.`,
150
+ suggestion: 'Use logger.error("message", { error: e.message, context: {...} }) instead of string concatenation',
151
+ category: 'logging'
152
+ });
153
+ }
154
+
155
+ // Check for sensitive data
156
+ const sensitiveData = this.findSensitiveData(logCall.content);
157
+ if (sensitiveData.length > 0) {
158
+ violations.push({
159
+ ruleId: this.ruleId,
160
+ severity: 'error',
161
+ message: 'Error logging contains potentially sensitive data',
162
+ source: this.ruleId,
163
+ file: filePath,
164
+ line: logLineNumber,
165
+ column: logCall.column,
166
+ description: `[REGEX-FALLBACK] Sensitive patterns detected: ${sensitiveData.join(', ')}. Mask or exclude sensitive data.`,
167
+ suggestion: 'Mask sensitive data or exclude entirely from logs',
168
+ category: 'security'
169
+ });
170
+ }
171
+
172
+ // Basic context check (limited in regex mode)
173
+ if (!this.hasBasicContext(logCall.content, errorVar)) {
174
+ violations.push({
175
+ ruleId: this.ruleId,
176
+ severity: 'warning',
177
+ message: 'Error logging appears to miss important context information',
178
+ source: this.ruleId,
179
+ file: filePath,
180
+ line: logLineNumber,
181
+ column: logCall.column,
182
+ description: `[REGEX-FALLBACK] Basic context validation suggests missing error details or identifiers.`,
183
+ suggestion: 'Include error message, identifiers (requestId, userId), and operation context',
184
+ category: 'logging'
185
+ });
186
+ }
187
+ }
188
+
189
+ return violations;
190
+ }
191
+
192
+ /**
193
+ * Find log calls within catch block content
194
+ */
195
+ findLogCallsInContent(content) {
196
+ const logCalls = [];
197
+ const lines = content.split('\n');
198
+
199
+ for (let i = 0; i < lines.length; i++) {
200
+ const line = lines[i];
201
+
202
+ for (const pattern of this.logPatterns) {
203
+ pattern.lastIndex = 0; // Reset regex
204
+ const match = pattern.exec(line);
205
+
206
+ if (match) {
207
+ logCalls.push({
208
+ content: line.trim(),
209
+ relativeLineNumber: i,
210
+ column: match.index + 1,
211
+ method: match[1] || 'unknown'
212
+ });
213
+ }
214
+ }
215
+ }
216
+
217
+ return logCalls;
218
+ }
219
+
220
+ /**
221
+ * Check if log call uses string concatenation
222
+ */
223
+ hasStringConcatenation(content) {
224
+ return this.stringConcatPatterns.some(pattern => {
225
+ pattern.lastIndex = 0;
226
+ return pattern.test(content);
227
+ });
228
+ }
229
+
230
+ /**
231
+ * Find sensitive data patterns in content
232
+ */
233
+ findSensitiveData(content) {
234
+ const found = [];
235
+
236
+ for (const pattern of this.sensitivePatterns) {
237
+ pattern.lastIndex = 0;
238
+ const matches = content.match(pattern);
239
+ if (matches) {
240
+ found.push(...matches.map(m => m.toLowerCase()));
241
+ }
242
+ }
243
+
244
+ return [...new Set(found)]; // Remove duplicates
245
+ }
246
+
247
+ /**
248
+ * Basic context validation (limited in regex mode)
249
+ */
250
+ hasBasicContext(content, errorVar) {
251
+ const lowerContent = content.toLowerCase();
252
+
253
+ // Check if error variable is used
254
+ const hasError = lowerContent.includes(errorVar.toLowerCase());
255
+
256
+ // Check for basic context indicators
257
+ const contextIndicators = ['id', 'request', 'user', 'operation', 'method'];
258
+ const hasContext = contextIndicators.some(indicator =>
259
+ lowerContent.includes(indicator)
260
+ );
261
+
262
+ return hasError && hasContext;
263
+ }
264
+
265
+ async analyze(files, language, options = {}) {
266
+ if (this.verbose) {
267
+ console.log(`🔧 [C035 Regex] analyze() called with ${files.length} files, language: ${language}`);
268
+ }
269
+
270
+ const violations = [];
271
+
272
+ for (const filePath of files) {
273
+ try {
274
+ if (this.verbose) {
275
+ console.log(`🔧 [C035 Regex] Processing file: ${filePath}`);
276
+ }
277
+
278
+ const fileViolations = await this.analyzeFileBasic(filePath, options);
279
+ violations.push(...fileViolations);
280
+
281
+ if (this.verbose) {
282
+ console.log(`🔧 [C035 Regex] File ${filePath}: Found ${fileViolations.length} violations`);
283
+ }
284
+ } catch (error) {
285
+ if (this.verbose) {
286
+ console.warn(`❌ [C035 Regex] Analysis failed for ${filePath}:`, error.message);
287
+ }
288
+ }
289
+ }
290
+
291
+ if (this.verbose) {
292
+ console.log(`🔧 [C035 Regex] Total violations found: ${violations.length}`);
293
+ }
294
+
295
+ return violations;
296
+ }
297
+ }
298
+
299
+ module.exports = C035RegexBasedAnalyzer;