thuban 0.3.1 → 0.3.3
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/README.md +137 -102
- package/cli.js +644 -93
- package/package.json +5 -2
- package/packages/scanner/alert-manager.js +398 -398
- package/packages/scanner/code-scanner.js +758 -713
- package/packages/scanner/copy-paste-detector.js +33 -7
- package/packages/scanner/dependency-graph.js +541 -536
- package/packages/scanner/drift-detector.js +423 -423
- package/packages/scanner/file-collector.js +64 -0
- package/packages/scanner/file-watcher.js +323 -323
- package/packages/scanner/ghost-code-detector.js +80 -5
- package/packages/scanner/hallucination-detector.js +189 -19
- package/packages/scanner/health-checker.js +586 -586
- package/packages/scanner/index.js +100 -92
- package/packages/scanner/license-manager.js +15 -2
- package/packages/scanner/master-health-checker.js +513 -513
- package/packages/scanner/monitor-notifier.js +64 -0
- package/packages/scanner/monitor-service.js +103 -0
- package/packages/scanner/monitor-store.js +117 -0
- package/packages/scanner/pre-commit-gate.js +1 -1
- package/packages/scanner/scan-diff.js +50 -0
- package/packages/scanner/scan-runner.js +172 -0
- package/packages/scanner/secret-scanner.js +612 -0
- package/packages/scanner/secret-scanner.test.js +103 -0
- package/packages/scanner/sentinel-core.js +616 -608
- package/packages/scanner/sentinel-knowledge.js +322 -322
- package/packages/scanner/tech-debt-analyzer.js +46 -28
- package/packages/scanner/widget-generator.js +415 -415
|
@@ -17,6 +17,31 @@ const DependencyGraph = require('./dependency-graph');
|
|
|
17
17
|
const DriftDetector = require('./drift-detector');
|
|
18
18
|
const WidgetGenerator = require('./widget-generator');
|
|
19
19
|
|
|
20
|
+
/**
|
|
21
|
+
* Convert a JSDoc-style /** ... * / widget string to the appropriate comment
|
|
22
|
+
* style for the target file's language.
|
|
23
|
+
*/
|
|
24
|
+
function formatWidgetComment(jsDocWidget, filePath) {
|
|
25
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
26
|
+
if (ext === '.py') {
|
|
27
|
+
return jsDocWidget
|
|
28
|
+
.replace(/^\/\*\*\n/, '')
|
|
29
|
+
.replace(/\s*\*\/\s*$/, '')
|
|
30
|
+
.split('\n')
|
|
31
|
+
.map(l => l.replace(/^\s*\*\s?/, '# '))
|
|
32
|
+
.join('\n');
|
|
33
|
+
} else if (ext === '.go') {
|
|
34
|
+
return jsDocWidget
|
|
35
|
+
.replace(/^\/\*\*\n/, '')
|
|
36
|
+
.replace(/\s*\*\/\s*$/, '')
|
|
37
|
+
.split('\n')
|
|
38
|
+
.map(l => l.replace(/^\s*\*\s?/, '// '))
|
|
39
|
+
.join('\n');
|
|
40
|
+
}
|
|
41
|
+
// JS, TS, Java, C# — keep /** */ format
|
|
42
|
+
return jsDocWidget;
|
|
43
|
+
}
|
|
44
|
+
|
|
20
45
|
class TechDebtAnalyzer {
|
|
21
46
|
constructor(config = {}) {
|
|
22
47
|
this.config = {
|
|
@@ -81,18 +106,14 @@ class TechDebtAnalyzer {
|
|
|
81
106
|
|
|
82
107
|
// ─── 1. Security Debt ───────────────────────────────────
|
|
83
108
|
const securityIssues = [];
|
|
84
|
-
for (const
|
|
85
|
-
if (
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
fixAction: issue.id === 'SEC001' ? 'extract_to_env' : issue.id === 'SEC002' ? 'extract_to_env' : null,
|
|
93
|
-
});
|
|
94
|
-
}
|
|
95
|
-
}
|
|
109
|
+
for (const issue of (scanResults.issues || [])) {
|
|
110
|
+
if (issue.id?.startsWith('SEC') || issue.category === 'security') {
|
|
111
|
+
securityIssues.push({
|
|
112
|
+
file: path.relative(this.config.rootPath, issue.file),
|
|
113
|
+
...issue,
|
|
114
|
+
fixable: issue.id === 'SEC001' || issue.id === 'SEC002', // Can extract to env vars
|
|
115
|
+
fixAction: issue.id === 'SEC001' ? 'extract_to_env' : issue.id === 'SEC002' ? 'extract_to_env' : null,
|
|
116
|
+
});
|
|
96
117
|
}
|
|
97
118
|
}
|
|
98
119
|
debt.scores.security = Math.max(0, 100 - (securityIssues.filter(i => i.severity === 'critical').length * 25) - (securityIssues.filter(i => i.severity === 'high').length * 10));
|
|
@@ -182,18 +203,14 @@ class TechDebtAnalyzer {
|
|
|
182
203
|
}
|
|
183
204
|
}
|
|
184
205
|
|
|
185
|
-
for (const
|
|
186
|
-
if (
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
fixAction: issue.id === 'QUAL001' ? 'remove_console_log' : null,
|
|
194
|
-
});
|
|
195
|
-
}
|
|
196
|
-
}
|
|
206
|
+
for (const issue of (scanResults.issues || [])) {
|
|
207
|
+
if (issue.id?.startsWith('QUAL') || issue.category === 'quality' || issue.category === 'maintainability') {
|
|
208
|
+
qualityIssues.push({
|
|
209
|
+
file: path.relative(this.config.rootPath, issue.file),
|
|
210
|
+
...issue,
|
|
211
|
+
fixable: ['QUAL001', 'QUAL003', 'QUAL005'].includes(issue.id), // console.log removal, etc.
|
|
212
|
+
fixAction: issue.id === 'QUAL001' ? 'remove_console_log' : null,
|
|
213
|
+
});
|
|
197
214
|
}
|
|
198
215
|
}
|
|
199
216
|
debt.scores.codeQuality = Math.max(0, 100 - (qualityIssues.filter(i => i.severity === 'high').length * 5) - (qualityIssues.filter(i => i.severity === 'medium').length * 2));
|
|
@@ -319,7 +336,8 @@ class TechDebtAnalyzer {
|
|
|
319
336
|
const content = fs.readFileSync(fullPath, 'utf-8');
|
|
320
337
|
const widget = await this.widgetGen.generateWidget(fullPath, content);
|
|
321
338
|
if (widget && widget.widgetString) {
|
|
322
|
-
|
|
339
|
+
const commentBlock = formatWidgetComment(widget.widgetString, fullPath);
|
|
340
|
+
fs.writeFileSync(fullPath, commentBlock + '\n\n' + content, 'utf-8');
|
|
323
341
|
fixes.push({ ...item, status: 'fixed' });
|
|
324
342
|
}
|
|
325
343
|
break;
|
|
@@ -333,7 +351,8 @@ class TechDebtAnalyzer {
|
|
|
333
351
|
// Generate new widget with current state
|
|
334
352
|
const widget = await this.widgetGen.generateWidget(fullPath, stripped);
|
|
335
353
|
if (widget && widget.widgetString) {
|
|
336
|
-
|
|
354
|
+
const commentBlock = formatWidgetComment(widget.widgetString, fullPath);
|
|
355
|
+
fs.writeFileSync(fullPath, commentBlock + '\n\n' + stripped, 'utf-8');
|
|
337
356
|
fixes.push({ ...item, status: 'fixed' });
|
|
338
357
|
}
|
|
339
358
|
break;
|
|
@@ -364,8 +383,7 @@ class TechDebtAnalyzer {
|
|
|
364
383
|
content = content.replace(/require\(['"]sys['"]\)/g, "require('util')");
|
|
365
384
|
// util.isArray() → Array.isArray()
|
|
366
385
|
content = content.replace(/util\.isArray\(/g, 'Array.isArray(');
|
|
367
|
-
// util.isFunction()
|
|
368
|
-
content = content.replace(/util\.isFunction\(([^)]+)\)/g, "typeof $1 === 'function'");
|
|
386
|
+
// util.isFunction() is skipped — regex cannot safely handle arrow function arguments
|
|
369
387
|
// fs.exists() callback → fs.existsSync or fs.access
|
|
370
388
|
content = content.replace(/fs\.exists\(([^,]+),\s*/g, 'fs.access($1, ');
|
|
371
389
|
if (content !== before) {
|