@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.
- package/CHANGELOG.md +107 -1
- package/CONTRIBUTING.md +1654 -66
- package/README.md +19 -6
- package/config/ci-cd.json +54 -0
- package/config/development.json +56 -0
- package/config/engines/engines-enhanced.json +86 -0
- package/config/engines/semantic-config.json +114 -0
- package/config/eslint-rule-mapping.json +50 -38
- package/config/large-project.json +143 -0
- package/config/presets/all.json +0 -1
- package/config/release.json +70 -0
- package/config/rule-analysis-strategies.js +23 -4
- package/config/rules/S027-categories.json +122 -0
- package/config/rules/enhanced-rules-registry.json +2564 -0
- package/config/rules/rules-registry-generated.json +785 -837
- package/config/rules/rules-registry.json +13 -1
- package/core/adapters/sunlint-rule-adapter.js +25 -30
- package/core/analysis-orchestrator.js +42 -2
- package/core/categories.js +52 -0
- package/core/category-constants.js +39 -0
- package/core/cli-action-handler.js +53 -32
- package/core/cli-program.js +11 -3
- package/core/config-manager.js +111 -0
- package/core/config-merger.js +88 -0
- package/core/constants/categories.js +168 -0
- package/core/constants/defaults.js +165 -0
- package/core/constants/engines.js +185 -0
- package/core/constants/index.js +30 -0
- package/core/constants/rules.js +215 -0
- package/core/enhanced-rules-registry.js +3 -3
- package/core/file-targeting-service.js +128 -7
- package/core/interfaces/rule-plugin.interface.js +207 -0
- package/core/plugin-manager.js +448 -0
- package/core/rule-selection-service.js +42 -15
- package/core/semantic-engine.js +658 -0
- package/core/semantic-rule-base.js +433 -0
- package/core/unified-rule-registry.js +484 -0
- package/docs/COMMAND-EXAMPLES.md +134 -0
- package/docs/CONSTANTS-ARCHITECTURE.md +288 -0
- package/docs/LARGE-PROJECT-GUIDE.md +324 -0
- package/engines/core/base-engine.js +249 -0
- package/engines/engine-factory.js +275 -0
- package/engines/eslint-engine.js +171 -19
- package/engines/heuristic-engine.js +569 -78
- package/integrations/eslint/plugin/index.js +26 -28
- package/origin-rules/common-en.md +8 -8
- package/package.json +10 -6
- package/rules/common/C003_no_vague_abbreviations/analyzer.js +1 -1
- package/rules/common/C017_constructor_logic/analyzer.js +254 -17
- package/rules/common/C017_constructor_logic/semantic-analyzer.js +340 -0
- package/rules/common/C029_catch_block_logging/analyzer.js +17 -5
- package/rules/common/C033_separate_service_repository/README.md +78 -0
- package/rules/common/C033_separate_service_repository/analyzer.js +160 -0
- package/rules/common/C033_separate_service_repository/config.json +50 -0
- package/rules/common/C033_separate_service_repository/regex-based-analyzer.js +585 -0
- package/rules/common/C033_separate_service_repository/symbol-based-analyzer.js +368 -0
- package/rules/common/C035_error_logging_context/STRATEGY.md +99 -0
- package/rules/common/C035_error_logging_context/analyzer.js +230 -0
- package/rules/common/C035_error_logging_context/config.json +54 -0
- package/rules/common/C035_error_logging_context/regex-based-analyzer.js +299 -0
- package/rules/common/C035_error_logging_context/symbol-based-analyzer.js +454 -0
- package/rules/common/C040_centralized_validation/analyzer.js +165 -0
- package/rules/common/C040_centralized_validation/config.json +46 -0
- package/rules/common/C040_centralized_validation/regex-based-analyzer.js +243 -0
- package/rules/common/C040_centralized_validation/symbol-based-analyzer.js +416 -0
- package/rules/common/C047_no_duplicate_retry_logic/c047-semantic-rule.js +278 -0
- package/rules/common/C047_no_duplicate_retry_logic/symbol-analyzer-enhanced.js +968 -0
- package/rules/common/C047_no_duplicate_retry_logic/symbol-config.json +71 -0
- package/rules/common/{C076_single_test_behavior → C072_single_test_behavior}/analyzer.js +6 -6
- package/rules/common/C076_explicit_function_types/README.md +30 -0
- package/rules/common/C076_explicit_function_types/analyzer.js +172 -0
- package/rules/common/C076_explicit_function_types/config.json +15 -0
- package/rules/common/C076_explicit_function_types/semantic-analyzer.js +341 -0
- package/rules/index.js +8 -0
- package/rules/parser/rule-parser.js +13 -2
- package/rules/security/S005_no_origin_auth/README.md +226 -0
- package/rules/security/S005_no_origin_auth/analyzer.js +184 -0
- package/rules/security/S005_no_origin_auth/ast-analyzer.js +406 -0
- package/rules/security/S005_no_origin_auth/config.json +85 -0
- package/rules/security/S006_no_plaintext_recovery_codes/README.md +139 -0
- package/rules/security/S006_no_plaintext_recovery_codes/analyzer.js +306 -0
- package/rules/security/S006_no_plaintext_recovery_codes/config.json +48 -0
- package/rules/security/S007_no_plaintext_otp/README.md +198 -0
- package/rules/security/S007_no_plaintext_otp/analyzer.js +406 -0
- package/rules/security/S007_no_plaintext_otp/config.json +79 -0
- package/rules/security/S007_no_plaintext_otp/semantic-analyzer.js +609 -0
- package/rules/security/S007_no_plaintext_otp/semantic-config.json +195 -0
- package/rules/security/S007_no_plaintext_otp/semantic-wrapper.js +280 -0
- package/rules/security/S027_no_hardcoded_secrets/analyzer.js +180 -366
- package/rules/security/S027_no_hardcoded_secrets/categories.json +153 -0
- package/rules/security/S027_no_hardcoded_secrets/categorized-analyzer.js +250 -0
- package/scripts/category-manager.js +150 -0
- package/scripts/generate-rules-registry.js +88 -0
- package/scripts/migrate-rule-registry.js +157 -0
- package/scripts/prepare-release.sh +1 -1
- package/scripts/validate-system.js +48 -0
- package/.sunlint.json +0 -35
- package/config/README.md +0 -88
- package/config/engines/eslint-rule-mapping.json +0 -74
- package/config/schemas/sunlint-schema.json +0 -0
- package/config/testing/test-s005-working.ts +0 -22
- package/core/multi-rule-runner.js +0 -0
- package/docs/ESLINT-INTEGRATION-STRATEGY.md +0 -392
- package/docs/FUTURE_PACKAGES.md +0 -83
- package/docs/HEURISTIC_VS_AI.md +0 -113
- package/docs/PRODUCTION_DEPLOYMENT_ANALYSIS.md +0 -112
- package/docs/PRODUCTION_SIZE_IMPACT.md +0 -183
- package/docs/RELEASE_GUIDE.md +0 -230
- package/docs/STANDARDIZED-CATEGORY-FILTERING.md +0 -156
- package/engines/tree-sitter-parser.js +0 -0
- package/engines/universal-ast-engine.js +0 -0
- package/integrations/eslint/plugin/rules/common/c076-single-behavior-per-test.js +0 -254
- package/rules/common/C029_catch_block_logging/analyzer-backup.js +0 -426
- package/rules/common/C029_catch_block_logging/analyzer-fixed.js +0 -130
- package/rules/common/C029_catch_block_logging/analyzer-multi-tech.js +0 -487
- package/rules/common/C029_catch_block_logging/analyzer-simple.js +0 -110
- package/rules/common/C029_catch_block_logging/ast-analyzer-backup.js +0 -441
- package/rules/common/C029_catch_block_logging/ast-analyzer-new.js +0 -127
- package/rules/common/C029_catch_block_logging/ast-analyzer.js +0 -133
- package/rules/common/C029_catch_block_logging/cfg-analyzer.js +0 -408
- package/rules/common/C029_catch_block_logging/dataflow-analyzer.js +0 -454
- package/rules/common/C029_catch_block_logging/multi-language-ast-engine.js +0 -700
- package/rules/common/C029_catch_block_logging/pattern-learning-analyzer.js +0 -568
- package/rules/common/C029_catch_block_logging/semantic-analyzer.js +0 -459
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
{
|
|
2
|
+
"ruleId": "S007",
|
|
3
|
+
"name": "No Plaintext OTP (Semantic Analysis)",
|
|
4
|
+
"category": "security",
|
|
5
|
+
"severity": "error",
|
|
6
|
+
"type": "semantic",
|
|
7
|
+
"description": "Detects plaintext OTP storage and transmission using semantic analysis with Symbol Table",
|
|
8
|
+
|
|
9
|
+
"analysis": {
|
|
10
|
+
"engine": "semantic",
|
|
11
|
+
"strategy": "symbol-table",
|
|
12
|
+
"crossFileAnalysis": true,
|
|
13
|
+
"requiresTypeChecker": false,
|
|
14
|
+
"cacheResults": true,
|
|
15
|
+
"timeout": 30000,
|
|
16
|
+
"maxFiles": 1000
|
|
17
|
+
},
|
|
18
|
+
|
|
19
|
+
"scope": {
|
|
20
|
+
"fileTypes": [".ts", ".tsx", ".js", ".jsx"],
|
|
21
|
+
"excludePatterns": [
|
|
22
|
+
"**/test/**",
|
|
23
|
+
"**/tests/**",
|
|
24
|
+
"**/__tests__/**",
|
|
25
|
+
"**/*.test.*",
|
|
26
|
+
"**/*.spec.*",
|
|
27
|
+
"**/node_modules/**",
|
|
28
|
+
"**/build/**",
|
|
29
|
+
"**/dist/**"
|
|
30
|
+
]
|
|
31
|
+
},
|
|
32
|
+
|
|
33
|
+
"semanticPatterns": {
|
|
34
|
+
"otpVariables": {
|
|
35
|
+
"patterns": [
|
|
36
|
+
"^(otp|totp|hotp)$",
|
|
37
|
+
"^(one_?time|onetime)_?(password|pass|code)$",
|
|
38
|
+
"^(auth|verification|sms|temp|security|access|login)_?code$",
|
|
39
|
+
"^(two_?factor|2fa|mfa)_?(token|code)$",
|
|
40
|
+
"^pin_?code$"
|
|
41
|
+
],
|
|
42
|
+
"caseInsensitive": true
|
|
43
|
+
},
|
|
44
|
+
|
|
45
|
+
"otpFunctions": {
|
|
46
|
+
"patterns": [
|
|
47
|
+
"^(generate|create|store|save|send|validate|verify)_?otp$",
|
|
48
|
+
"^otp_?(generate|create|store|save|send|validate|verify)$",
|
|
49
|
+
"^(generate|create|store|save|send|validate|verify)_?(auth|verification|sms|temp|security|access|login)_?code$",
|
|
50
|
+
"^send_?(sms|email|auth)_?code$"
|
|
51
|
+
],
|
|
52
|
+
"methodNames": [
|
|
53
|
+
"sendOtp", "storeOtp", "saveOtp", "generateOtp", "verifyOtp",
|
|
54
|
+
"sendSmsCode", "sendAuthCode", "storeAuthCode", "saveAuthCode"
|
|
55
|
+
]
|
|
56
|
+
},
|
|
57
|
+
|
|
58
|
+
"dangerousOperations": {
|
|
59
|
+
"storage": [
|
|
60
|
+
"save", "store", "insert", "update", "create", "persist",
|
|
61
|
+
"collection.insertOne", "collection.updateOne", "db.save",
|
|
62
|
+
"redis.set", "redis.hset", "cache.put", "cache.set"
|
|
63
|
+
],
|
|
64
|
+
"transmission": [
|
|
65
|
+
"send", "emit", "post", "put", "response.json", "res.send",
|
|
66
|
+
"email.send", "sms.send", "notify", "broadcast"
|
|
67
|
+
],
|
|
68
|
+
"browserStorage": [
|
|
69
|
+
"localStorage.setItem", "sessionStorage.setItem",
|
|
70
|
+
"localStorage.set", "sessionStorage.set"
|
|
71
|
+
],
|
|
72
|
+
"logging": [
|
|
73
|
+
"console.log", "console.debug", "console.info",
|
|
74
|
+
"logger.info", "logger.debug", "log.info"
|
|
75
|
+
]
|
|
76
|
+
},
|
|
77
|
+
|
|
78
|
+
"safeOperations": [
|
|
79
|
+
"bcrypt.hash", "crypto.createHash", "crypto.createHmac",
|
|
80
|
+
"hash", "encrypt", "cipher", "secure", "pbkdf2",
|
|
81
|
+
"scrypt", "argon2", "aes.encrypt", "rsa.encrypt"
|
|
82
|
+
]
|
|
83
|
+
},
|
|
84
|
+
|
|
85
|
+
"violations": {
|
|
86
|
+
"types": {
|
|
87
|
+
"semantic_otp_variable_usage": {
|
|
88
|
+
"severity": "error",
|
|
89
|
+
"message": "OTP variable used in {context} without encryption",
|
|
90
|
+
"suggestion": "Encrypt or hash OTP values before {context}"
|
|
91
|
+
},
|
|
92
|
+
"semantic_otp_function_call": {
|
|
93
|
+
"severity": "warning",
|
|
94
|
+
"message": "Function may handle OTP in plaintext",
|
|
95
|
+
"suggestion": "Ensure OTP values are encrypted before processing"
|
|
96
|
+
},
|
|
97
|
+
"semantic_plaintext_otp_argument": {
|
|
98
|
+
"severity": "error",
|
|
99
|
+
"message": "Potential plaintext OTP passed to {operation}",
|
|
100
|
+
"suggestion": "Encrypt or hash OTP values before storage/transmission"
|
|
101
|
+
},
|
|
102
|
+
"semantic_method_chain_otp": {
|
|
103
|
+
"severity": "error",
|
|
104
|
+
"message": "Method chain exposes OTP in plaintext",
|
|
105
|
+
"suggestion": "Use secure methods for OTP handling in method chains"
|
|
106
|
+
},
|
|
107
|
+
"semantic_data_flow_violation": {
|
|
108
|
+
"severity": "error",
|
|
109
|
+
"message": "OTP flows to unsafe operation without encryption",
|
|
110
|
+
"suggestion": "Ensure OTP is encrypted before reaching this operation"
|
|
111
|
+
},
|
|
112
|
+
"semantic_cross_file_otp_violation": {
|
|
113
|
+
"severity": "warning",
|
|
114
|
+
"message": "Imported OTP symbol used unsafely",
|
|
115
|
+
"suggestion": "Ensure consistent OTP security across file boundaries"
|
|
116
|
+
}
|
|
117
|
+
},
|
|
118
|
+
|
|
119
|
+
"severityMapping": {
|
|
120
|
+
"storage": "error",
|
|
121
|
+
"transmission": "error",
|
|
122
|
+
"browser_storage": "warning",
|
|
123
|
+
"logging": "warning",
|
|
124
|
+
"unknown_dangerous": "info"
|
|
125
|
+
}
|
|
126
|
+
},
|
|
127
|
+
|
|
128
|
+
"dataFlow": {
|
|
129
|
+
"enabled": true,
|
|
130
|
+
"maxDistance": 20,
|
|
131
|
+
"trackAcrossFiles": true,
|
|
132
|
+
"trackThroughCallbacks": true,
|
|
133
|
+
"trackAsyncFlows": true
|
|
134
|
+
},
|
|
135
|
+
|
|
136
|
+
"performance": {
|
|
137
|
+
"symbolTableCaching": true,
|
|
138
|
+
"maxAnalysisDepth": 10,
|
|
139
|
+
"maxCrossFileReferences": 100,
|
|
140
|
+
"timeoutPerFile": 5000
|
|
141
|
+
},
|
|
142
|
+
|
|
143
|
+
"reporting": {
|
|
144
|
+
"includeSymbolContext": true,
|
|
145
|
+
"includeCrossFileReferences": true,
|
|
146
|
+
"includeDataFlowPath": true,
|
|
147
|
+
"includeCodeSnippets": true,
|
|
148
|
+
"confidenceThreshold": 0.7
|
|
149
|
+
},
|
|
150
|
+
|
|
151
|
+
"examples": {
|
|
152
|
+
"violations": [
|
|
153
|
+
{
|
|
154
|
+
"description": "Direct OTP storage",
|
|
155
|
+
"code": "const otp = generateOtp(); await user.save({ otp });",
|
|
156
|
+
"reason": "OTP variable flows directly to storage operation"
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
"description": "OTP in response",
|
|
160
|
+
"code": "return response.json({ authCode, success: true });",
|
|
161
|
+
"reason": "OTP variable included in API response"
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
"description": "Method chain violation",
|
|
165
|
+
"code": "this.otpCode.save();",
|
|
166
|
+
"reason": "OTP flows through method chain to unsafe operation"
|
|
167
|
+
}
|
|
168
|
+
],
|
|
169
|
+
|
|
170
|
+
"safePatterns": [
|
|
171
|
+
{
|
|
172
|
+
"description": "Encrypted storage",
|
|
173
|
+
"code": "const hashedOtp = await bcrypt.hash(otp, 10); await user.save({ hashedOtp });",
|
|
174
|
+
"reason": "OTP is hashed before storage"
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
"description": "Secure transmission",
|
|
178
|
+
"code": "const encrypted = encrypt(otp, key); await send(encrypted);",
|
|
179
|
+
"reason": "OTP is encrypted before transmission"
|
|
180
|
+
}
|
|
181
|
+
]
|
|
182
|
+
},
|
|
183
|
+
|
|
184
|
+
"metadata": {
|
|
185
|
+
"version": "1.0.0",
|
|
186
|
+
"lastUpdated": "2024-01-20",
|
|
187
|
+
"author": "SunLint Security Team",
|
|
188
|
+
"references": [
|
|
189
|
+
"OWASP A02:2021 - Cryptographic Failures",
|
|
190
|
+
"NIST SP 800-63B - Authentication Guidelines",
|
|
191
|
+
"RFC 6238 - TOTP: Time-Based One-Time Password Algorithm"
|
|
192
|
+
],
|
|
193
|
+
"tags": ["security", "authentication", "otp", "encryption", "semantic"]
|
|
194
|
+
}
|
|
195
|
+
}
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* S007 Semantic Wrapper
|
|
3
|
+
* Integrates S007SemanticAnalyzer with HeuristicEngine
|
|
4
|
+
* Provides compatibility layer between semantic analysis and existing framework
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const S007SemanticAnalyzer = require('./semantic-analyzer');
|
|
8
|
+
const SemanticRuleBase = require('../../../core/semantic-rule-base');
|
|
9
|
+
|
|
10
|
+
class S007SemanticWrapper extends SemanticRuleBase {
|
|
11
|
+
constructor(options = {}) {
|
|
12
|
+
super('S007', {
|
|
13
|
+
category: 'security',
|
|
14
|
+
severity: 'error',
|
|
15
|
+
description: 'Detects plaintext OTP storage and transmission using semantic analysis',
|
|
16
|
+
crossFileAnalysis: true,
|
|
17
|
+
requiresTypeChecker: false,
|
|
18
|
+
cacheResults: true,
|
|
19
|
+
...options
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
this.semanticAnalyzer = new S007SemanticAnalyzer('S007');
|
|
23
|
+
this.verbose = options.verbose || false;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Initialize with semantic engine
|
|
28
|
+
*/
|
|
29
|
+
async initialize(semanticEngine) {
|
|
30
|
+
await super.initialize(semanticEngine);
|
|
31
|
+
|
|
32
|
+
// Initialize the semantic analyzer
|
|
33
|
+
await this.semanticAnalyzer.initialize(semanticEngine);
|
|
34
|
+
|
|
35
|
+
if (this.verbose) {
|
|
36
|
+
console.log(`🧠 S007SemanticWrapper initialized with semantic engine`);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Analyze single file using semantic analysis
|
|
42
|
+
*/
|
|
43
|
+
async analyzeFile(filePath, options = {}) {
|
|
44
|
+
if (this.verbose) {
|
|
45
|
+
console.log(`🧠 S007: Analyzing ${filePath} with semantic analysis`);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
try {
|
|
49
|
+
// Delegate to semantic analyzer
|
|
50
|
+
await this.semanticAnalyzer.analyzeFile(filePath, options);
|
|
51
|
+
|
|
52
|
+
// Get violations from semantic analyzer
|
|
53
|
+
const semanticViolations = this.semanticAnalyzer.getViolations();
|
|
54
|
+
|
|
55
|
+
// Add violations to our collection
|
|
56
|
+
for (const violation of semanticViolations) {
|
|
57
|
+
this.addViolation(violation);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Clear violations from semantic analyzer for next file
|
|
61
|
+
this.semanticAnalyzer.clearViolations();
|
|
62
|
+
|
|
63
|
+
if (this.verbose && semanticViolations.length > 0) {
|
|
64
|
+
console.log(`🧠 S007: Found ${semanticViolations.length} semantic violations in ${filePath}`);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
} catch (error) {
|
|
68
|
+
console.error(`❌ S007: Semantic analysis failed for ${filePath}:`, error.message);
|
|
69
|
+
|
|
70
|
+
// Fallback to regex analysis if semantic fails
|
|
71
|
+
if (options.fallbackToRegex !== false) {
|
|
72
|
+
await this.fallbackToRegexAnalysis(filePath, options);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Fallback to regex analysis if semantic analysis fails
|
|
79
|
+
*/
|
|
80
|
+
async fallbackToRegexAnalysis(filePath, options) {
|
|
81
|
+
try {
|
|
82
|
+
if (this.verbose) {
|
|
83
|
+
console.log(`⚠️ S007: Falling back to regex analysis for ${filePath}`);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Use the existing regex analyzer as fallback
|
|
87
|
+
const RegexAnalyzer = require('./analyzer');
|
|
88
|
+
const regexAnalyzer = new RegexAnalyzer();
|
|
89
|
+
|
|
90
|
+
const regexViolations = await regexAnalyzer.analyze([filePath], 'typescript', options);
|
|
91
|
+
|
|
92
|
+
// Add regex violations with lower confidence
|
|
93
|
+
for (const violation of regexViolations) {
|
|
94
|
+
this.addViolation({
|
|
95
|
+
...violation,
|
|
96
|
+
analysisMethod: 'regex_fallback',
|
|
97
|
+
confidence: 0.7, // Lower confidence for fallback
|
|
98
|
+
source: 'regex_analyzer'
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (this.verbose && regexViolations.length > 0) {
|
|
103
|
+
console.log(`🔧 S007: Found ${regexViolations.length} regex violations (fallback) in ${filePath}`);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
} catch (fallbackError) {
|
|
107
|
+
console.error(`❌ S007: Fallback analysis also failed for ${filePath}:`, fallbackError.message);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Get supported file types
|
|
113
|
+
*/
|
|
114
|
+
isValidFileType(filePath) {
|
|
115
|
+
const supportedExtensions = ['.ts', '.tsx', '.js', '.jsx'];
|
|
116
|
+
const path = require('path');
|
|
117
|
+
const ext = path.extname(filePath);
|
|
118
|
+
return supportedExtensions.includes(ext);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Enhanced violation adding with semantic context
|
|
123
|
+
*/
|
|
124
|
+
addViolation(violation) {
|
|
125
|
+
const enhancedViolation = {
|
|
126
|
+
...violation,
|
|
127
|
+
|
|
128
|
+
// Add semantic metadata
|
|
129
|
+
analysisEngine: 'semantic',
|
|
130
|
+
analysisMethod: violation.analysisMethod || 'semantic',
|
|
131
|
+
confidence: violation.confidence || 0.9,
|
|
132
|
+
timestamp: Date.now(),
|
|
133
|
+
|
|
134
|
+
// Ensure required fields
|
|
135
|
+
ruleId: this.ruleId,
|
|
136
|
+
category: this.config.category,
|
|
137
|
+
severity: violation.severity || this.config.severity,
|
|
138
|
+
|
|
139
|
+
// Add semantic-specific fields
|
|
140
|
+
semanticContext: violation.symbolContext || {},
|
|
141
|
+
crossFileReferences: violation.crossFileReferences || [],
|
|
142
|
+
dataFlowAnalysis: violation.dataFlowAnalysis || null,
|
|
143
|
+
|
|
144
|
+
// Enhanced suggestions for semantic violations
|
|
145
|
+
suggestion: this.enhanceSemanticSuggestion(violation),
|
|
146
|
+
|
|
147
|
+
// Code context
|
|
148
|
+
codeSnippet: violation.codeSnippet || null,
|
|
149
|
+
|
|
150
|
+
// Metadata
|
|
151
|
+
metadata: {
|
|
152
|
+
engineVersion: '3.0',
|
|
153
|
+
analysisType: 'semantic',
|
|
154
|
+
symbolTableUsed: true,
|
|
155
|
+
crossFileAnalysis: this.config.crossFileAnalysis,
|
|
156
|
+
...violation.metadata
|
|
157
|
+
}
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
super.addViolation(enhancedViolation);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Enhance suggestions with semantic context
|
|
165
|
+
*/
|
|
166
|
+
enhanceSemanticSuggestion(violation) {
|
|
167
|
+
const baseSuggestion = violation.suggestion || 'Ensure OTP security best practices';
|
|
168
|
+
|
|
169
|
+
// Add context-specific suggestions based on semantic analysis
|
|
170
|
+
const contextSuggestions = [];
|
|
171
|
+
|
|
172
|
+
if (violation.symbolContext) {
|
|
173
|
+
const context = violation.symbolContext;
|
|
174
|
+
|
|
175
|
+
if (context.operation) {
|
|
176
|
+
contextSuggestions.push(`Consider replacing '${context.operation}' with a secure alternative`);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
if (context.dataFlow && context.dataFlow.length > 1) {
|
|
180
|
+
contextSuggestions.push('Review the data flow path to identify where encryption should be applied');
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
if (context.crossFileReferences && context.crossFileReferences.length > 0) {
|
|
184
|
+
contextSuggestions.push('Ensure security measures are consistent across all files using this OTP symbol');
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// Combine base suggestion with context-specific suggestions
|
|
189
|
+
if (contextSuggestions.length > 0) {
|
|
190
|
+
return `${baseSuggestion}. Additional recommendations: ${contextSuggestions.join('; ')}.`;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
return baseSuggestion;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Generate analysis report with semantic insights
|
|
198
|
+
*/
|
|
199
|
+
generateReport() {
|
|
200
|
+
const baseReport = super.generateReport();
|
|
201
|
+
|
|
202
|
+
// Add semantic-specific statistics
|
|
203
|
+
const semanticStats = this.calculateSemanticStats();
|
|
204
|
+
|
|
205
|
+
return {
|
|
206
|
+
...baseReport,
|
|
207
|
+
semanticAnalysis: {
|
|
208
|
+
enabled: true,
|
|
209
|
+
symbolTableUsed: true,
|
|
210
|
+
crossFileAnalysisPerformed: this.config.crossFileAnalysis,
|
|
211
|
+
dataFlowAnalysisPerformed: true,
|
|
212
|
+
statistics: semanticStats
|
|
213
|
+
}
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Calculate semantic analysis statistics
|
|
219
|
+
*/
|
|
220
|
+
calculateSemanticStats() {
|
|
221
|
+
const violations = this.getViolations();
|
|
222
|
+
|
|
223
|
+
const stats = {
|
|
224
|
+
totalViolations: violations.length,
|
|
225
|
+
violationsByType: {},
|
|
226
|
+
violationsByContext: {},
|
|
227
|
+
averageConfidence: 0,
|
|
228
|
+
crossFileViolations: 0,
|
|
229
|
+
dataFlowViolations: 0
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
// Analyze violation types and contexts
|
|
233
|
+
for (const violation of violations) {
|
|
234
|
+
// Count by type
|
|
235
|
+
const type = violation.type || 'unknown';
|
|
236
|
+
stats.violationsByType[type] = (stats.violationsByType[type] || 0) + 1;
|
|
237
|
+
|
|
238
|
+
// Count by context
|
|
239
|
+
if (violation.symbolContext && violation.symbolContext.usageContext) {
|
|
240
|
+
const context = violation.symbolContext.usageContext;
|
|
241
|
+
stats.violationsByContext[context] = (stats.violationsByContext[context] || 0) + 1;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// Count cross-file violations
|
|
245
|
+
if (violation.crossFileReferences && violation.crossFileReferences.length > 0) {
|
|
246
|
+
stats.crossFileViolations++;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// Count data flow violations
|
|
250
|
+
if (violation.dataFlowAnalysis) {
|
|
251
|
+
stats.dataFlowViolations++;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// Calculate average confidence
|
|
256
|
+
if (violations.length > 0) {
|
|
257
|
+
const totalConfidence = violations.reduce((sum, v) => sum + (v.confidence || 0.9), 0);
|
|
258
|
+
stats.averageConfidence = totalConfidence / violations.length;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
return stats;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* Cleanup semantic resources
|
|
266
|
+
*/
|
|
267
|
+
async cleanup() {
|
|
268
|
+
if (this.semanticAnalyzer && typeof this.semanticAnalyzer.cleanup === 'function') {
|
|
269
|
+
await this.semanticAnalyzer.cleanup();
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
await super.cleanup();
|
|
273
|
+
|
|
274
|
+
if (this.verbose) {
|
|
275
|
+
console.log(`🧠 S007SemanticWrapper cleanup completed`);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
module.exports = S007SemanticWrapper;
|