coverme-scanner 2.0.1 → 4.0.0
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 +27 -4
- package/dist/analyzers/ast-analyzer.d.ts +29 -0
- package/dist/analyzers/ast-analyzer.d.ts.map +1 -0
- package/dist/analyzers/ast-analyzer.js +194 -0
- package/dist/analyzers/ast-analyzer.js.map +1 -0
- package/dist/analyzers/duplication-detector.d.ts +27 -0
- package/dist/analyzers/duplication-detector.d.ts.map +1 -0
- package/dist/analyzers/duplication-detector.js +169 -0
- package/dist/analyzers/duplication-detector.js.map +1 -0
- package/dist/analyzers/index.d.ts +5 -0
- package/dist/analyzers/index.d.ts.map +1 -0
- package/dist/analyzers/index.js +10 -0
- package/dist/analyzers/index.js.map +1 -0
- package/dist/analyzers/stride-analyzer.d.ts +20 -0
- package/dist/analyzers/stride-analyzer.d.ts.map +1 -0
- package/dist/analyzers/stride-analyzer.js +166 -0
- package/dist/analyzers/stride-analyzer.js.map +1 -0
- package/dist/cli/index.js +4 -2
- package/dist/cli/index.js.map +1 -1
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +16 -0
- package/dist/index.js.map +1 -0
- package/dist/prompts/advanced-analysis.md +199 -0
- package/dist/prompts/orchestration.md +102 -3
- package/dist/report/generator.js +1 -1
- package/dist/report/generator.js.map +1 -1
- package/dist/report/index.d.ts +3 -2
- package/dist/report/index.d.ts.map +1 -1
- package/dist/report/index.js +16 -4
- package/dist/report/index.js.map +1 -1
- package/dist/report/pdf-generator.d.ts +23 -0
- package/dist/report/pdf-generator.d.ts.map +1 -0
- package/dist/report/pdf-generator.js +405 -0
- package/dist/report/pdf-generator.js.map +1 -0
- package/dist/templates/report-minimal.html +429 -0
- package/dist/templates/report.html +465 -0
- package/package.json +30 -3
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
### The Most Comprehensive AI Security Scanner for Your Codebase
|
|
6
6
|
|
|
7
|
-
**
|
|
7
|
+
**23 AI Agents | AST Analysis | STRIDE + DREAD | Professional PDF Reports | Zero Config**
|
|
8
8
|
|
|
9
9
|
[](https://www.npmjs.com/package/coverme-scanner)
|
|
10
10
|
[](https://opensource.org/licenses/MIT)
|
|
@@ -47,7 +47,7 @@ coverme init
|
|
|
47
47
|
/coverme
|
|
48
48
|
```
|
|
49
49
|
|
|
50
|
-
**That's it.** Watch
|
|
50
|
+
**That's it.** Watch 23 AI agents analyze your entire codebase and generate a professional PDF or HTML report.
|
|
51
51
|
|
|
52
52
|
---
|
|
53
53
|
|
|
@@ -76,13 +76,14 @@ Agents that aren't relevant to your project **automatically skip**:
|
|
|
76
76
|
|
|
77
77
|
---
|
|
78
78
|
|
|
79
|
-
##
|
|
79
|
+
## 23 Specialized Agents
|
|
80
80
|
|
|
81
81
|
<details>
|
|
82
82
|
<summary><b>Security Agents (Click to expand)</b></summary>
|
|
83
83
|
|
|
84
84
|
| Agent | What It Finds |
|
|
85
85
|
|-------|---------------|
|
|
86
|
+
| **Advanced Static Analysis** | AST dead code detection, duplication detection, STRIDE classification, DREAD scoring |
|
|
86
87
|
| **Security Core** | OWASP Top 10, SQL/NoSQL injection, XSS, Command injection, SSRF, Path traversal |
|
|
87
88
|
| **Auth & Session** | OAuth flaws, JWT vulnerabilities, session fixation, cookie security, MFA bypass |
|
|
88
89
|
| **API Security** | CORS misconfiguration, rate limiting, IDOR, mass assignment, webhook security |
|
|
@@ -124,9 +125,31 @@ Agents that aren't relevant to your project **automatically skip**:
|
|
|
124
125
|
|
|
125
126
|
---
|
|
126
127
|
|
|
128
|
+
## v3.0 — Enterprise Analysis Engine
|
|
129
|
+
|
|
130
|
+
New in v3.0:
|
|
131
|
+
|
|
132
|
+
| Feature | Description |
|
|
133
|
+
|---------|-------------|
|
|
134
|
+
| **Professional PDF Reports** | Enterprise-grade PDFs — cover page, threat model, architecture overview |
|
|
135
|
+
| **AST Dead Code Detection** | Unused imports, variables, functions, unreachable code |
|
|
136
|
+
| **Code Duplication Detection** | Jaro-Winkler similarity; shows lines removable by merging |
|
|
137
|
+
| **STRIDE Threat Modeling** | Auto-classifies findings into STRIDE categories |
|
|
138
|
+
| **DREAD Risk Scoring** | 0-10 risk scores across 5 dimensions per finding |
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
# Generate PDF report
|
|
142
|
+
coverme report .coverme/scan.json -f pdf -o assessment.pdf
|
|
143
|
+
|
|
144
|
+
# Generate HTML report
|
|
145
|
+
coverme report .coverme/scan.json -f html
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
127
150
|
## Beautiful Reports
|
|
128
151
|
|
|
129
|
-
CoverMe generates **professional HTML reports** with:
|
|
152
|
+
CoverMe generates **professional HTML and PDF reports** with:
|
|
130
153
|
|
|
131
154
|
<table>
|
|
132
155
|
<tr>
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export interface DeadCodeFinding {
|
|
2
|
+
type: 'unused-import' | 'unused-variable' | 'unused-function' | 'unreachable-code';
|
|
3
|
+
file: string;
|
|
4
|
+
line: number;
|
|
5
|
+
endLine?: number;
|
|
6
|
+
name?: string;
|
|
7
|
+
description: string;
|
|
8
|
+
}
|
|
9
|
+
export interface CodeMetrics {
|
|
10
|
+
linesOfCode: number;
|
|
11
|
+
totalFunctions: number;
|
|
12
|
+
totalVariables: number;
|
|
13
|
+
totalImports: number;
|
|
14
|
+
cyclomaticComplexity: number;
|
|
15
|
+
cognitiveComplexity: number;
|
|
16
|
+
}
|
|
17
|
+
export declare class ASTAnalyzer {
|
|
18
|
+
private usedIdentifiers;
|
|
19
|
+
private declaredIdentifiers;
|
|
20
|
+
private imports;
|
|
21
|
+
analyzeFile(filePath: string): Promise<{
|
|
22
|
+
deadCode: DeadCodeFinding[];
|
|
23
|
+
metrics: CodeMetrics;
|
|
24
|
+
}>;
|
|
25
|
+
private analyzeJavaScriptAST;
|
|
26
|
+
private calculateComplexity;
|
|
27
|
+
reset(): void;
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=ast-analyzer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ast-analyzer.d.ts","sourceRoot":"","sources":["../../src/analyzers/ast-analyzer.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,eAAe,GAAG,iBAAiB,GAAG,iBAAiB,GAAG,kBAAkB,CAAC;IACnF,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,WAAW;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;IACrB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,mBAAmB,EAAE,MAAM,CAAC;CAC7B;AAED,qBAAa,WAAW;IACtB,OAAO,CAAC,eAAe,CAAqB;IAC5C,OAAO,CAAC,mBAAmB,CAAqD;IAChF,OAAO,CAAC,OAAO,CAAsD;IAE/D,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;QAC3C,QAAQ,EAAE,eAAe,EAAE,CAAC;QAC5B,OAAO,EAAE,WAAW,CAAC;KACtB,CAAC;IA+BF,OAAO,CAAC,oBAAoB;IAqG5B,OAAO,CAAC,mBAAmB;IAyB3B,KAAK,IAAI,IAAI;CAKd"}
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.ASTAnalyzer = void 0;
|
|
40
|
+
const parser_1 = require("@babel/parser");
|
|
41
|
+
// @ts-ignore
|
|
42
|
+
const traverse_1 = __importDefault(require("@babel/traverse"));
|
|
43
|
+
const t = __importStar(require("@babel/types"));
|
|
44
|
+
const fs_1 = require("fs");
|
|
45
|
+
class ASTAnalyzer {
|
|
46
|
+
usedIdentifiers = new Set();
|
|
47
|
+
declaredIdentifiers = new Map();
|
|
48
|
+
imports = new Map();
|
|
49
|
+
async analyzeFile(filePath) {
|
|
50
|
+
const content = (0, fs_1.readFileSync)(filePath, 'utf-8');
|
|
51
|
+
const ext = filePath.split('.').pop();
|
|
52
|
+
let ast;
|
|
53
|
+
const deadCode = [];
|
|
54
|
+
const metrics = {
|
|
55
|
+
linesOfCode: content.split('\n').length,
|
|
56
|
+
totalFunctions: 0,
|
|
57
|
+
totalVariables: 0,
|
|
58
|
+
totalImports: 0,
|
|
59
|
+
cyclomaticComplexity: 0,
|
|
60
|
+
cognitiveComplexity: 0,
|
|
61
|
+
};
|
|
62
|
+
try {
|
|
63
|
+
// Use Babel parser for all file types — supports TypeScript, JSX, decorators
|
|
64
|
+
ast = (0, parser_1.parse)(content, {
|
|
65
|
+
sourceType: 'module',
|
|
66
|
+
plugins: ['jsx', 'typescript', 'decorators-legacy'],
|
|
67
|
+
errorRecovery: true,
|
|
68
|
+
});
|
|
69
|
+
this.analyzeJavaScriptAST(ast, filePath, deadCode, metrics);
|
|
70
|
+
}
|
|
71
|
+
catch (error) {
|
|
72
|
+
// Silent fail - file might not be parseable
|
|
73
|
+
return { deadCode, metrics };
|
|
74
|
+
}
|
|
75
|
+
return { deadCode, metrics };
|
|
76
|
+
}
|
|
77
|
+
analyzeJavaScriptAST(ast, filePath, deadCode, metrics) {
|
|
78
|
+
// First pass: collect declarations
|
|
79
|
+
(0, traverse_1.default)(ast, {
|
|
80
|
+
ImportDeclaration: (path) => {
|
|
81
|
+
path.node.specifiers.forEach((spec) => {
|
|
82
|
+
const name = spec.local.name;
|
|
83
|
+
this.imports.set(name, {
|
|
84
|
+
line: spec.loc?.start.line || 0,
|
|
85
|
+
used: false,
|
|
86
|
+
});
|
|
87
|
+
metrics.totalImports++;
|
|
88
|
+
});
|
|
89
|
+
},
|
|
90
|
+
FunctionDeclaration: (path) => {
|
|
91
|
+
metrics.totalFunctions++;
|
|
92
|
+
if (path.node.id) {
|
|
93
|
+
this.declaredIdentifiers.set(path.node.id.name, {
|
|
94
|
+
line: path.node.loc?.start.line || 0,
|
|
95
|
+
type: 'function',
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
// Calculate complexity
|
|
99
|
+
metrics.cyclomaticComplexity += this.calculateComplexity(path.node);
|
|
100
|
+
},
|
|
101
|
+
VariableDeclarator: (path) => {
|
|
102
|
+
metrics.totalVariables++;
|
|
103
|
+
if (t.isIdentifier(path.node.id)) {
|
|
104
|
+
this.declaredIdentifiers.set(path.node.id.name, {
|
|
105
|
+
line: path.node.loc?.start.line || 0,
|
|
106
|
+
type: 'variable',
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
},
|
|
110
|
+
// Second pass: track usage
|
|
111
|
+
Identifier: (path) => {
|
|
112
|
+
if (!path.isReferencedIdentifier())
|
|
113
|
+
return;
|
|
114
|
+
this.usedIdentifiers.add(path.node.name);
|
|
115
|
+
if (this.imports.has(path.node.name)) {
|
|
116
|
+
const imp = this.imports.get(path.node.name);
|
|
117
|
+
imp.used = true;
|
|
118
|
+
}
|
|
119
|
+
},
|
|
120
|
+
// Detect unreachable code after return
|
|
121
|
+
ReturnStatement: (path) => {
|
|
122
|
+
const parent = path.getFunctionParent();
|
|
123
|
+
if (!parent)
|
|
124
|
+
return;
|
|
125
|
+
const bodyPath = parent.get('body');
|
|
126
|
+
if (!bodyPath.isBlockStatement())
|
|
127
|
+
return;
|
|
128
|
+
const statements = bodyPath.get('body');
|
|
129
|
+
const returnIndex = statements.findIndex((s) => s === path);
|
|
130
|
+
if (returnIndex >= 0 && returnIndex < statements.length - 1) {
|
|
131
|
+
const nextStmt = statements[returnIndex + 1];
|
|
132
|
+
deadCode.push({
|
|
133
|
+
type: 'unreachable-code',
|
|
134
|
+
file: filePath,
|
|
135
|
+
line: nextStmt.node.loc?.start.line || 0,
|
|
136
|
+
description: 'Unreachable code after return statement',
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
},
|
|
140
|
+
});
|
|
141
|
+
// Find unused imports
|
|
142
|
+
for (const [name, info] of this.imports.entries()) {
|
|
143
|
+
if (!info.used && !name.startsWith('_')) {
|
|
144
|
+
deadCode.push({
|
|
145
|
+
type: 'unused-import',
|
|
146
|
+
file: filePath,
|
|
147
|
+
line: info.line,
|
|
148
|
+
name,
|
|
149
|
+
description: `Unused import: ${name}`,
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
// Find unused declarations
|
|
154
|
+
for (const [name, info] of this.declaredIdentifiers.entries()) {
|
|
155
|
+
if (!this.usedIdentifiers.has(name) && !name.startsWith('_')) {
|
|
156
|
+
deadCode.push({
|
|
157
|
+
type: info.type === 'function' ? 'unused-function' : 'unused-variable',
|
|
158
|
+
file: filePath,
|
|
159
|
+
line: info.line,
|
|
160
|
+
name,
|
|
161
|
+
description: `Unused ${info.type}: ${name}`,
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
calculateComplexity(node) {
|
|
167
|
+
let complexity = 1;
|
|
168
|
+
const visitor = {
|
|
169
|
+
IfStatement: () => complexity++,
|
|
170
|
+
SwitchCase: () => complexity++,
|
|
171
|
+
ForStatement: () => complexity++,
|
|
172
|
+
ForInStatement: () => complexity++,
|
|
173
|
+
ForOfStatement: () => complexity++,
|
|
174
|
+
WhileStatement: () => complexity++,
|
|
175
|
+
DoWhileStatement: () => complexity++,
|
|
176
|
+
ConditionalExpression: () => complexity++,
|
|
177
|
+
LogicalExpression: (path) => {
|
|
178
|
+
if (path.node.operator === '&&' || path.node.operator === '||') {
|
|
179
|
+
complexity++;
|
|
180
|
+
}
|
|
181
|
+
},
|
|
182
|
+
CatchClause: () => complexity++,
|
|
183
|
+
};
|
|
184
|
+
(0, traverse_1.default)(node, visitor, undefined, {});
|
|
185
|
+
return complexity;
|
|
186
|
+
}
|
|
187
|
+
reset() {
|
|
188
|
+
this.usedIdentifiers.clear();
|
|
189
|
+
this.declaredIdentifiers.clear();
|
|
190
|
+
this.imports.clear();
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
exports.ASTAnalyzer = ASTAnalyzer;
|
|
194
|
+
//# sourceMappingURL=ast-analyzer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ast-analyzer.js","sourceRoot":"","sources":["../../src/analyzers/ast-analyzer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export interface DuplicationFinding {
|
|
2
|
+
type: 'exact-duplicate' | 'similar-code';
|
|
3
|
+
files: string[];
|
|
4
|
+
lines: Array<{
|
|
5
|
+
file: string;
|
|
6
|
+
startLine: number;
|
|
7
|
+
endLine: number;
|
|
8
|
+
}>;
|
|
9
|
+
linesCount: number;
|
|
10
|
+
similarity: number;
|
|
11
|
+
code?: string;
|
|
12
|
+
description: string;
|
|
13
|
+
recommendation: string;
|
|
14
|
+
}
|
|
15
|
+
export declare class DuplicationDetector {
|
|
16
|
+
private minLines;
|
|
17
|
+
private minSimilarity;
|
|
18
|
+
constructor(minLines?: number, minSimilarity?: number);
|
|
19
|
+
detectDuplications(files: string[]): Promise<DuplicationFinding[]>;
|
|
20
|
+
private extractCodeBlocks;
|
|
21
|
+
private normalizeCode;
|
|
22
|
+
private isSignificantCode;
|
|
23
|
+
private hashCode;
|
|
24
|
+
private calculateSimilarity;
|
|
25
|
+
private overlaps;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=duplication-detector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"duplication-detector.d.ts","sourceRoot":"","sources":["../../src/analyzers/duplication-detector.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,iBAAiB,GAAG,cAAc,CAAC;IACzC,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,KAAK,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACnE,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;CACxB;AAUD,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,aAAa,CAAS;gBAElB,QAAQ,SAAI,EAAE,aAAa,SAAO;IAKxC,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,kBAAkB,EAAE,CAAC;IA6GxE,OAAO,CAAC,iBAAiB;IA4BzB,OAAO,CAAC,aAAa;IAQrB,OAAO,CAAC,iBAAiB;IAMzB,OAAO,CAAC,QAAQ;IAUhB,OAAO,CAAC,mBAAmB;IAS3B,OAAO,CAAC,QAAQ;CAGjB"}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.DuplicationDetector = void 0;
|
|
7
|
+
const fs_1 = require("fs");
|
|
8
|
+
// @ts-ignore - no types available; package exports default function directly
|
|
9
|
+
const jaro_winkler_1 = __importDefault(require("jaro-winkler"));
|
|
10
|
+
class DuplicationDetector {
|
|
11
|
+
minLines;
|
|
12
|
+
minSimilarity;
|
|
13
|
+
constructor(minLines = 5, minSimilarity = 0.85) {
|
|
14
|
+
this.minLines = minLines;
|
|
15
|
+
this.minSimilarity = minSimilarity;
|
|
16
|
+
}
|
|
17
|
+
async detectDuplications(files) {
|
|
18
|
+
const codeBlocks = [];
|
|
19
|
+
const findings = [];
|
|
20
|
+
// Extract code blocks from all files
|
|
21
|
+
for (const file of files) {
|
|
22
|
+
try {
|
|
23
|
+
const content = (0, fs_1.readFileSync)(file, 'utf-8');
|
|
24
|
+
const blocks = this.extractCodeBlocks(content, file);
|
|
25
|
+
codeBlocks.push(...blocks);
|
|
26
|
+
}
|
|
27
|
+
catch (error) {
|
|
28
|
+
// Skip files that can't be read
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
// Find duplicates using hash matching for exact duplicates
|
|
33
|
+
const hashMap = new Map();
|
|
34
|
+
for (const block of codeBlocks) {
|
|
35
|
+
if (!hashMap.has(block.hash)) {
|
|
36
|
+
hashMap.set(block.hash, []);
|
|
37
|
+
}
|
|
38
|
+
hashMap.get(block.hash).push(block);
|
|
39
|
+
}
|
|
40
|
+
// Report exact duplicates — deduplicate overlapping same-file windows
|
|
41
|
+
for (const [, blocks] of hashMap.entries()) {
|
|
42
|
+
if (blocks.length < 2)
|
|
43
|
+
continue;
|
|
44
|
+
// Keep only one representative per (file, non-overlapping region)
|
|
45
|
+
const deduped = [];
|
|
46
|
+
for (const block of blocks) {
|
|
47
|
+
const alreadyCovered = deduped.some((d) => d.file === block.file &&
|
|
48
|
+
this.overlaps(d.startLine, d.endLine, block.startLine, block.endLine));
|
|
49
|
+
if (!alreadyCovered)
|
|
50
|
+
deduped.push(block);
|
|
51
|
+
}
|
|
52
|
+
// Only report if duplicates span more than one unique non-overlapping region
|
|
53
|
+
const uniqueFiles = new Set(deduped.map((b) => b.file));
|
|
54
|
+
if (deduped.length < 2)
|
|
55
|
+
continue;
|
|
56
|
+
// If all in the same file, require non-overlapping and meaningful separation
|
|
57
|
+
if (uniqueFiles.size === 1) {
|
|
58
|
+
const sorted = deduped.sort((a, b) => a.startLine - b.startLine);
|
|
59
|
+
if (sorted[sorted.length - 1].startLine - sorted[0].endLine < 5)
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
findings.push({
|
|
63
|
+
type: 'exact-duplicate',
|
|
64
|
+
files: [...uniqueFiles],
|
|
65
|
+
lines: deduped.map((b) => ({
|
|
66
|
+
file: b.file,
|
|
67
|
+
startLine: b.startLine,
|
|
68
|
+
endLine: b.endLine,
|
|
69
|
+
})),
|
|
70
|
+
linesCount: deduped[0].code.split('\n').length,
|
|
71
|
+
similarity: 1.0,
|
|
72
|
+
code: deduped[0].code,
|
|
73
|
+
description: `${deduped[0].code.split('\n').length} lines of code duplicated ${deduped.length} times`,
|
|
74
|
+
recommendation: `Extract to a shared function or module`,
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
// Find similar code (not exact matches)
|
|
78
|
+
const compared = new Set();
|
|
79
|
+
for (let i = 0; i < codeBlocks.length; i++) {
|
|
80
|
+
for (let j = i + 1; j < codeBlocks.length; j++) {
|
|
81
|
+
const block1 = codeBlocks[i];
|
|
82
|
+
const block2 = codeBlocks[j];
|
|
83
|
+
const key = `${block1.file}:${block1.startLine}-${block2.file}:${block2.startLine}`;
|
|
84
|
+
if (compared.has(key))
|
|
85
|
+
continue;
|
|
86
|
+
compared.add(key);
|
|
87
|
+
// Skip if same file and overlapping lines
|
|
88
|
+
if (block1.file === block2.file &&
|
|
89
|
+
this.overlaps(block1.startLine, block1.endLine, block2.startLine, block2.endLine)) {
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
const similarity = this.calculateSimilarity(block1.code, block2.code);
|
|
93
|
+
if (similarity >= this.minSimilarity && similarity < 1.0) {
|
|
94
|
+
findings.push({
|
|
95
|
+
type: 'similar-code',
|
|
96
|
+
files: [block1.file, block2.file],
|
|
97
|
+
lines: [
|
|
98
|
+
{ file: block1.file, startLine: block1.startLine, endLine: block1.endLine },
|
|
99
|
+
{ file: block2.file, startLine: block2.startLine, endLine: block2.endLine },
|
|
100
|
+
],
|
|
101
|
+
linesCount: block1.code.split('\n').length,
|
|
102
|
+
similarity,
|
|
103
|
+
description: `Similar code (${(similarity * 100).toFixed(0)}% match) found in 2 locations`,
|
|
104
|
+
recommendation: `Consider extracting common logic to reduce duplication`,
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
// Sort by lines count (biggest duplications first)
|
|
110
|
+
findings.sort((a, b) => b.linesCount - a.linesCount);
|
|
111
|
+
return findings;
|
|
112
|
+
}
|
|
113
|
+
extractCodeBlocks(content, file) {
|
|
114
|
+
const lines = content.split('\n');
|
|
115
|
+
const blocks = [];
|
|
116
|
+
// Use non-overlapping windows (step = minLines) to avoid sliding-window noise.
|
|
117
|
+
// Also try half-step offset to catch duplicates not aligned to the same boundary.
|
|
118
|
+
const offsets = [0, Math.floor(this.minLines / 2)];
|
|
119
|
+
for (const offset of offsets) {
|
|
120
|
+
for (let i = offset; i < lines.length - this.minLines; i += this.minLines) {
|
|
121
|
+
const block = lines.slice(i, i + this.minLines).join('\n');
|
|
122
|
+
const normalized = this.normalizeCode(block);
|
|
123
|
+
if (this.isSignificantCode(normalized)) {
|
|
124
|
+
blocks.push({
|
|
125
|
+
file,
|
|
126
|
+
startLine: i + 1,
|
|
127
|
+
endLine: i + this.minLines,
|
|
128
|
+
code: block,
|
|
129
|
+
hash: this.hashCode(normalized),
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return blocks;
|
|
135
|
+
}
|
|
136
|
+
normalizeCode(code) {
|
|
137
|
+
return code
|
|
138
|
+
.replace(/\/\*[\s\S]*?\*\/|\/\/.*/g, '') // Remove comments
|
|
139
|
+
.replace(/\s+/g, ' ') // Normalize whitespace
|
|
140
|
+
.replace(/['"]([^'"]*)['"]/g, '""') // Normalize strings
|
|
141
|
+
.trim();
|
|
142
|
+
}
|
|
143
|
+
isSignificantCode(code) {
|
|
144
|
+
// Filter out mostly empty lines, imports, simple declarations
|
|
145
|
+
const significantChars = code.replace(/[{}();,\s]/g, '').length;
|
|
146
|
+
return significantChars > 20;
|
|
147
|
+
}
|
|
148
|
+
hashCode(str) {
|
|
149
|
+
let hash = 0;
|
|
150
|
+
for (let i = 0; i < str.length; i++) {
|
|
151
|
+
const char = str.charCodeAt(i);
|
|
152
|
+
hash = (hash << 5) - hash + char;
|
|
153
|
+
hash = hash & hash;
|
|
154
|
+
}
|
|
155
|
+
return hash.toString(36);
|
|
156
|
+
}
|
|
157
|
+
calculateSimilarity(code1, code2) {
|
|
158
|
+
const norm1 = this.normalizeCode(code1);
|
|
159
|
+
const norm2 = this.normalizeCode(code2);
|
|
160
|
+
// Use Jaro-Winkler distance (package exports the function as default)
|
|
161
|
+
const distanceFn = typeof jaro_winkler_1.default === 'function' ? jaro_winkler_1.default : jaro_winkler_1.default.distance;
|
|
162
|
+
return distanceFn(norm1, norm2);
|
|
163
|
+
}
|
|
164
|
+
overlaps(start1, end1, start2, end2) {
|
|
165
|
+
return start1 <= end2 && start2 <= end1;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
exports.DuplicationDetector = DuplicationDetector;
|
|
169
|
+
//# sourceMappingURL=duplication-detector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"duplication-detector.js","sourceRoot":"","sources":["../../src/analyzers/duplication-detector.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { ASTAnalyzer } from './ast-analyzer.js';
|
|
2
|
+
export { DuplicationDetector } from './duplication-detector.js';
|
|
3
|
+
export { STRIDEAnalyzer } from './stride-analyzer.js';
|
|
4
|
+
export type { STRIDECategory, STRIDEThreat } from './stride-analyzer.js';
|
|
5
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/analyzers/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,YAAY,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.STRIDEAnalyzer = exports.DuplicationDetector = exports.ASTAnalyzer = void 0;
|
|
4
|
+
var ast_analyzer_js_1 = require("./ast-analyzer.js");
|
|
5
|
+
Object.defineProperty(exports, "ASTAnalyzer", { enumerable: true, get: function () { return ast_analyzer_js_1.ASTAnalyzer; } });
|
|
6
|
+
var duplication_detector_js_1 = require("./duplication-detector.js");
|
|
7
|
+
Object.defineProperty(exports, "DuplicationDetector", { enumerable: true, get: function () { return duplication_detector_js_1.DuplicationDetector; } });
|
|
8
|
+
var stride_analyzer_js_1 = require("./stride-analyzer.js");
|
|
9
|
+
Object.defineProperty(exports, "STRIDEAnalyzer", { enumerable: true, get: function () { return stride_analyzer_js_1.STRIDEAnalyzer; } });
|
|
10
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/analyzers/index.ts"],"names":[],"mappings":";;;AAAA,qDAAgD;AAAvC,8GAAA,WAAW,OAAA;AACpB,qEAAgE;AAAvD,8HAAA,mBAAmB,OAAA;AAC5B,2DAAsD;AAA7C,oHAAA,cAAc,OAAA"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Finding, DreadScore } from '../types.js';
|
|
2
|
+
export type STRIDECategory = 'Spoofing' | 'Tampering' | 'Repudiation' | 'Information Disclosure' | 'Denial of Service' | 'Elevation of Privilege';
|
|
3
|
+
export interface STRIDEThreat {
|
|
4
|
+
id: string;
|
|
5
|
+
category: STRIDECategory;
|
|
6
|
+
threat: string;
|
|
7
|
+
component: string;
|
|
8
|
+
attackVector?: string;
|
|
9
|
+
mitigation?: string;
|
|
10
|
+
status: 'open' | 'mitigated' | 'partial' | 'accepted';
|
|
11
|
+
dreadScore?: DreadScore;
|
|
12
|
+
relatedFindings?: string[];
|
|
13
|
+
}
|
|
14
|
+
export declare class STRIDEAnalyzer {
|
|
15
|
+
calculateDREAD(finding: Finding): DreadScore;
|
|
16
|
+
classifySTRIDE(finding: Finding): STRIDECategory[];
|
|
17
|
+
generateThreatModel(findings: Finding[]): STRIDEThreat[];
|
|
18
|
+
private inferStatus;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=stride-analyzer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stride-analyzer.d.ts","sourceRoot":"","sources":["../../src/analyzers/stride-analyzer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAElD,MAAM,MAAM,cAAc,GAAG,UAAU,GAAG,WAAW,GAAG,aAAa,GAAG,wBAAwB,GAAG,mBAAmB,GAAG,wBAAwB,CAAC;AAElJ,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,cAAc,CAAC;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS,GAAG,UAAU,CAAC;IACtD,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;CAC5B;AAED,qBAAa,cAAc;IACzB,cAAc,CAAC,OAAO,EAAE,OAAO,GAAG,UAAU;IA2E5C,cAAc,CAAC,OAAO,EAAE,OAAO,GAAG,cAAc,EAAE;IA8ElD,mBAAmB,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,YAAY,EAAE;IA4BxD,OAAO,CAAC,WAAW;CAkBpB"}
|