@darrenjcoxon/vibeguard 1.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/LICENSE +21 -0
- package/README.md +58 -0
- package/dist/agent-report.d.ts +36 -0
- package/dist/agent-report.d.ts.map +1 -0
- package/dist/agent-report.js +329 -0
- package/dist/agent-report.js.map +1 -0
- package/dist/ai-summary.d.ts +55 -0
- package/dist/ai-summary.d.ts.map +1 -0
- package/dist/ai-summary.js +267 -0
- package/dist/ai-summary.js.map +1 -0
- package/dist/cli.d.ts +9 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +328 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +27 -0
- package/dist/index.js.map +1 -0
- package/dist/orchestrator.d.ts +63 -0
- package/dist/orchestrator.d.ts.map +1 -0
- package/dist/orchestrator.js +331 -0
- package/dist/orchestrator.js.map +1 -0
- package/dist/scanners/complexity.d.ts +48 -0
- package/dist/scanners/complexity.d.ts.map +1 -0
- package/dist/scanners/complexity.js +512 -0
- package/dist/scanners/complexity.js.map +1 -0
- package/dist/scanners/eslint.d.ts +21 -0
- package/dist/scanners/eslint.d.ts.map +1 -0
- package/dist/scanners/eslint.js +196 -0
- package/dist/scanners/eslint.js.map +1 -0
- package/dist/scanners/gitleaks.d.ts +21 -0
- package/dist/scanners/gitleaks.d.ts.map +1 -0
- package/dist/scanners/gitleaks.js +158 -0
- package/dist/scanners/gitleaks.js.map +1 -0
- package/dist/scanners/index.d.ts +56 -0
- package/dist/scanners/index.d.ts.map +1 -0
- package/dist/scanners/index.js +71 -0
- package/dist/scanners/index.js.map +1 -0
- package/dist/scanners/npm-audit.d.ts +19 -0
- package/dist/scanners/npm-audit.d.ts.map +1 -0
- package/dist/scanners/npm-audit.js +176 -0
- package/dist/scanners/npm-audit.js.map +1 -0
- package/dist/scanners/semgrep.d.ts +22 -0
- package/dist/scanners/semgrep.d.ts.map +1 -0
- package/dist/scanners/semgrep.js +175 -0
- package/dist/scanners/semgrep.js.map +1 -0
- package/dist/types.d.ts +522 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +194 -0
- package/dist/types.js.map +1 -0
- package/package.json +53 -0
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ESLint Scanner
|
|
3
|
+
*
|
|
4
|
+
* Code quality and style scanning for JavaScript/TypeScript projects
|
|
5
|
+
* Covers: quality, style, security (with security plugins)
|
|
6
|
+
*/
|
|
7
|
+
import { exec } from 'child_process';
|
|
8
|
+
import { promisify } from 'util';
|
|
9
|
+
import { existsSync } from 'fs';
|
|
10
|
+
import { join } from 'path';
|
|
11
|
+
import { generateFingerprint } from '../types.js';
|
|
12
|
+
const execAsync = promisify(exec);
|
|
13
|
+
export class ESLintScanner {
|
|
14
|
+
name = 'eslint';
|
|
15
|
+
categories = ['quality', 'style', 'security'];
|
|
16
|
+
// Security-related ESLint rule prefixes
|
|
17
|
+
securityRulePrefixes = [
|
|
18
|
+
'security/',
|
|
19
|
+
'@typescript-eslint/no-unsafe',
|
|
20
|
+
'no-eval',
|
|
21
|
+
'no-implied-eval',
|
|
22
|
+
'no-new-func',
|
|
23
|
+
'no-script-url'
|
|
24
|
+
];
|
|
25
|
+
async isAvailable() {
|
|
26
|
+
try {
|
|
27
|
+
await execAsync('npx eslint --version', { timeout: 10000 });
|
|
28
|
+
return true;
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
async scan(target, config) {
|
|
35
|
+
const startTime = Date.now();
|
|
36
|
+
// Check for ESLint config or package.json
|
|
37
|
+
const hasESLintConfig = this.hasESLintConfig(target.path);
|
|
38
|
+
const hasPackageJson = existsSync(join(target.path, 'package.json'));
|
|
39
|
+
if (!hasESLintConfig && !hasPackageJson) {
|
|
40
|
+
return {
|
|
41
|
+
scanner: this.name,
|
|
42
|
+
success: true,
|
|
43
|
+
findings: [],
|
|
44
|
+
metrics: { duration: Date.now() - startTime },
|
|
45
|
+
metadata: { skipped: true, reason: 'No ESLint config or package.json found' }
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
if (!await this.isAvailable()) {
|
|
49
|
+
return {
|
|
50
|
+
scanner: this.name,
|
|
51
|
+
success: false,
|
|
52
|
+
error: 'ESLint not available. Run `npm install eslint` in your project',
|
|
53
|
+
findings: [],
|
|
54
|
+
metrics: { duration: Date.now() - startTime }
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
try {
|
|
58
|
+
const findings = await this.runESLint(target);
|
|
59
|
+
return {
|
|
60
|
+
scanner: this.name,
|
|
61
|
+
success: true,
|
|
62
|
+
findings,
|
|
63
|
+
metrics: {
|
|
64
|
+
duration: Date.now() - startTime,
|
|
65
|
+
filesScanned: findings.length > 0 ? new Set(findings.map(f => f.file)).size : 0
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
return {
|
|
71
|
+
scanner: this.name,
|
|
72
|
+
success: false,
|
|
73
|
+
error: error instanceof Error ? error.message : String(error),
|
|
74
|
+
findings: [],
|
|
75
|
+
metrics: { duration: Date.now() - startTime }
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
hasESLintConfig(path) {
|
|
80
|
+
const configFiles = [
|
|
81
|
+
'.eslintrc',
|
|
82
|
+
'.eslintrc.js',
|
|
83
|
+
'.eslintrc.cjs',
|
|
84
|
+
'.eslintrc.json',
|
|
85
|
+
'.eslintrc.yml',
|
|
86
|
+
'.eslintrc.yaml',
|
|
87
|
+
'eslint.config.js',
|
|
88
|
+
'eslint.config.mjs',
|
|
89
|
+
'eslint.config.cjs'
|
|
90
|
+
];
|
|
91
|
+
return configFiles.some(f => existsSync(join(path, f)));
|
|
92
|
+
}
|
|
93
|
+
async runESLint(target) {
|
|
94
|
+
const extensions = '--ext .js,.jsx,.ts,.tsx,.mjs,.cjs';
|
|
95
|
+
const ignorePattern = '--ignore-pattern "node_modules/**" --ignore-pattern "dist/**" --ignore-pattern "build/**"';
|
|
96
|
+
const cmd = `cd "${target.path}" && npx eslint . ${extensions} ${ignorePattern} --format json --no-error-on-unmatched-pattern 2>/dev/null || true`;
|
|
97
|
+
try {
|
|
98
|
+
const { stdout, stderr } = await execAsync(cmd, {
|
|
99
|
+
timeout: 180000, // 3 minutes
|
|
100
|
+
maxBuffer: 20 * 1024 * 1024
|
|
101
|
+
});
|
|
102
|
+
if (!stdout.trim() || stdout.trim() === '[]') {
|
|
103
|
+
return [];
|
|
104
|
+
}
|
|
105
|
+
const results = JSON.parse(stdout);
|
|
106
|
+
return this.transformFindings(results, target.path);
|
|
107
|
+
}
|
|
108
|
+
catch (error) {
|
|
109
|
+
// ESLint exits with 1 when there are linting errors
|
|
110
|
+
if (error.stdout) {
|
|
111
|
+
try {
|
|
112
|
+
const results = JSON.parse(error.stdout);
|
|
113
|
+
return this.transformFindings(results, target.path);
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
return [];
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
// Config errors etc. - just return empty
|
|
120
|
+
return [];
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
transformFindings(results, basePath) {
|
|
124
|
+
const findings = [];
|
|
125
|
+
for (const result of results) {
|
|
126
|
+
for (const msg of result.messages) {
|
|
127
|
+
if (!msg.ruleId)
|
|
128
|
+
continue; // Skip parsing errors without rule IDs
|
|
129
|
+
const category = this.categorizeRule(msg.ruleId);
|
|
130
|
+
const severity = this.mapSeverity(msg.severity, category);
|
|
131
|
+
// Make path relative
|
|
132
|
+
const relativePath = result.filePath.startsWith(basePath)
|
|
133
|
+
? result.filePath.slice(basePath.length + 1)
|
|
134
|
+
: result.filePath;
|
|
135
|
+
const finding = {
|
|
136
|
+
id: `eslint-${msg.ruleId}-${relativePath}-${msg.line}`,
|
|
137
|
+
source: this.name,
|
|
138
|
+
severity,
|
|
139
|
+
category,
|
|
140
|
+
file: relativePath,
|
|
141
|
+
line: msg.line,
|
|
142
|
+
endLine: msg.endLine,
|
|
143
|
+
column: msg.column,
|
|
144
|
+
endColumn: msg.endColumn,
|
|
145
|
+
title: msg.ruleId,
|
|
146
|
+
description: msg.message,
|
|
147
|
+
suggestion: msg.suggestions?.[0]?.desc || (msg.fix ? 'Auto-fix available' : undefined),
|
|
148
|
+
fixAvailable: !!(msg.fix || msg.suggestions?.length),
|
|
149
|
+
autoFixable: !!msg.fix,
|
|
150
|
+
ruleId: msg.ruleId,
|
|
151
|
+
ruleUrl: `https://eslint.org/docs/rules/${msg.ruleId}`,
|
|
152
|
+
confidence: 'high',
|
|
153
|
+
effort: msg.fix ? 'trivial' : 'easy',
|
|
154
|
+
fingerprint: ''
|
|
155
|
+
};
|
|
156
|
+
finding.fingerprint = generateFingerprint(finding);
|
|
157
|
+
findings.push(finding);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
return findings;
|
|
161
|
+
}
|
|
162
|
+
categorizeRule(ruleId) {
|
|
163
|
+
// Check if it's a security rule
|
|
164
|
+
if (this.securityRulePrefixes.some(prefix => ruleId.startsWith(prefix) || ruleId.includes(prefix))) {
|
|
165
|
+
return 'security';
|
|
166
|
+
}
|
|
167
|
+
// Style rules
|
|
168
|
+
const stylePatterns = [
|
|
169
|
+
'indent', 'quotes', 'semi', 'comma', 'spacing', 'newline',
|
|
170
|
+
'brace', 'curly', 'padding', 'wrap', 'linebreak'
|
|
171
|
+
];
|
|
172
|
+
if (stylePatterns.some(p => ruleId.toLowerCase().includes(p))) {
|
|
173
|
+
return 'style';
|
|
174
|
+
}
|
|
175
|
+
// Complexity rules
|
|
176
|
+
if (ruleId.includes('complexity') || ruleId.includes('max-')) {
|
|
177
|
+
return 'complexity';
|
|
178
|
+
}
|
|
179
|
+
// Default to quality
|
|
180
|
+
return 'quality';
|
|
181
|
+
}
|
|
182
|
+
mapSeverity(eslintSeverity, category) {
|
|
183
|
+
// Security issues get elevated severity
|
|
184
|
+
if (category === 'security') {
|
|
185
|
+
return eslintSeverity === 2 ? 'high' : 'medium';
|
|
186
|
+
}
|
|
187
|
+
// Style issues are low priority
|
|
188
|
+
if (category === 'style') {
|
|
189
|
+
return 'low';
|
|
190
|
+
}
|
|
191
|
+
// Quality issues
|
|
192
|
+
return eslintSeverity === 2 ? 'medium' : 'low';
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
export default ESLintScanner;
|
|
196
|
+
//# sourceMappingURL=eslint.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"eslint.js","sourceRoot":"","sources":["../../src/scanners/eslint.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AACrC,OAAO,EAAE,SAAS,EAAE,MAAM,MAAM,CAAC;AACjC,OAAO,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AAChC,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAQL,mBAAmB,EACpB,MAAM,aAAa,CAAC;AAErB,MAAM,SAAS,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;AA8BlC,MAAM,OAAO,aAAa;IACxB,IAAI,GAAG,QAAQ,CAAC;IAChB,UAAU,GAAsB,CAAC,SAAS,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;IAEjE,wCAAwC;IAChC,oBAAoB,GAAG;QAC7B,WAAW;QACX,8BAA8B;QAC9B,SAAS;QACT,iBAAiB;QACjB,aAAa;QACb,eAAe;KAChB,CAAC;IAEF,KAAK,CAAC,WAAW;QACf,IAAI,CAAC;YACH,MAAM,SAAS,CAAC,sBAAsB,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;YAC5D,OAAO,IAAI,CAAC;QACd,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,MAAkB,EAAE,MAAsB;QACnD,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAE7B,0CAA0C;QAC1C,MAAM,eAAe,GAAG,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAC1D,MAAM,cAAc,GAAG,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,cAAc,CAAC,CAAC,CAAC;QAErE,IAAI,CAAC,eAAe,IAAI,CAAC,cAAc,EAAE,CAAC;YACxC,OAAO;gBACL,OAAO,EAAE,IAAI,CAAC,IAAI;gBAClB,OAAO,EAAE,IAAI;gBACb,QAAQ,EAAE,EAAE;gBACZ,OAAO,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,EAAE;gBAC7C,QAAQ,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,wCAAwC,EAAE;aAC9E,CAAC;QACJ,CAAC;QAED,IAAI,CAAC,MAAM,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC;YAC9B,OAAO;gBACL,OAAO,EAAE,IAAI,CAAC,IAAI;gBAClB,OAAO,EAAE,KAAK;gBACd,KAAK,EAAE,gEAAgE;gBACvE,QAAQ,EAAE,EAAE;gBACZ,OAAO,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,EAAE;aAC9C,CAAC;QACJ,CAAC;QAED,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;YAE9C,OAAO;gBACL,OAAO,EAAE,IAAI,CAAC,IAAI;gBAClB,OAAO,EAAE,IAAI;gBACb,QAAQ;gBACR,OAAO,EAAE;oBACP,QAAQ,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS;oBAChC,YAAY,EAAE,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;iBAChF;aACF,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO;gBACL,OAAO,EAAE,IAAI,CAAC,IAAI;gBAClB,OAAO,EAAE,KAAK;gBACd,KAAK,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;gBAC7D,QAAQ,EAAE,EAAE;gBACZ,OAAO,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,EAAE;aAC9C,CAAC;QACJ,CAAC;IACH,CAAC;IAEO,eAAe,CAAC,IAAY;QAClC,MAAM,WAAW,GAAG;YAClB,WAAW;YACX,cAAc;YACd,eAAe;YACf,gBAAgB;YAChB,eAAe;YACf,gBAAgB;YAChB,kBAAkB;YAClB,mBAAmB;YACnB,mBAAmB;SACpB,CAAC;QAEF,OAAO,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IAC1D,CAAC;IAEO,KAAK,CAAC,SAAS,CAAC,MAAkB;QACxC,MAAM,UAAU,GAAG,mCAAmC,CAAC;QACvD,MAAM,aAAa,GAAG,2FAA2F,CAAC;QAElH,MAAM,GAAG,GAAG,OAAO,MAAM,CAAC,IAAI,qBAAqB,UAAU,IAAI,aAAa,oEAAoE,CAAC;QAEnJ,IAAI,CAAC;YACH,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,SAAS,CAAC,GAAG,EAAE;gBAC9C,OAAO,EAAE,MAAM,EAAE,YAAY;gBAC7B,SAAS,EAAE,EAAE,GAAG,IAAI,GAAG,IAAI;aAC5B,CAAC,CAAC;YAEH,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,MAAM,CAAC,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC;gBAC7C,OAAO,EAAE,CAAC;YACZ,CAAC;YAED,MAAM,OAAO,GAAmB,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;YACnD,OAAO,IAAI,CAAC,iBAAiB,CAAC,OAAO,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC;QAEtD,CAAC;QAAC,OAAO,KAAU,EAAE,CAAC;YACpB,oDAAoD;YACpD,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;gBACjB,IAAI,CAAC;oBACH,MAAM,OAAO,GAAmB,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;oBACzD,OAAO,IAAI,CAAC,iBAAiB,CAAC,OAAO,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC;gBACtD,CAAC;gBAAC,MAAM,CAAC;oBACP,OAAO,EAAE,CAAC;gBACZ,CAAC;YACH,CAAC;YACD,yCAAyC;YACzC,OAAO,EAAE,CAAC;QACZ,CAAC;IACH,CAAC;IAEO,iBAAiB,CAAC,OAAuB,EAAE,QAAgB;QACjE,MAAM,QAAQ,GAAc,EAAE,CAAC;QAE/B,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;YAC7B,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;gBAClC,IAAI,CAAC,GAAG,CAAC,MAAM;oBAAE,SAAS,CAAC,uCAAuC;gBAElE,MAAM,QAAQ,GAAG,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;gBACjD,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;gBAE1D,qBAAqB;gBACrB,MAAM,YAAY,GAAG,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC,QAAQ,CAAC;oBACvD,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC;oBAC5C,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC;gBAEpB,MAAM,OAAO,GAAY;oBACvB,EAAE,EAAE,UAAU,GAAG,CAAC,MAAM,IAAI,YAAY,IAAI,GAAG,CAAC,IAAI,EAAE;oBACtD,MAAM,EAAE,IAAI,CAAC,IAAI;oBACjB,QAAQ;oBACR,QAAQ;oBACR,IAAI,EAAE,YAAY;oBAClB,IAAI,EAAE,GAAG,CAAC,IAAI;oBACd,OAAO,EAAE,GAAG,CAAC,OAAO;oBACpB,MAAM,EAAE,GAAG,CAAC,MAAM;oBAClB,SAAS,EAAE,GAAG,CAAC,SAAS;oBACxB,KAAK,EAAE,GAAG,CAAC,MAAM;oBACjB,WAAW,EAAE,GAAG,CAAC,OAAO;oBACxB,UAAU,EAAE,GAAG,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,SAAS,CAAC;oBACtF,YAAY,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,WAAW,EAAE,MAAM,CAAC;oBACpD,WAAW,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG;oBACtB,MAAM,EAAE,GAAG,CAAC,MAAM;oBAClB,OAAO,EAAE,iCAAiC,GAAG,CAAC,MAAM,EAAE;oBACtD,UAAU,EAAE,MAAM;oBAClB,MAAM,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM;oBACpC,WAAW,EAAE,EAAE;iBAChB,CAAC;gBAEF,OAAO,CAAC,WAAW,GAAG,mBAAmB,CAAC,OAAO,CAAC,CAAC;gBACnD,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YACzB,CAAC;QACH,CAAC;QAED,OAAO,QAAQ,CAAC;IAClB,CAAC;IAEO,cAAc,CAAC,MAAc;QACnC,gCAAgC;QAChC,IAAI,IAAI,CAAC,oBAAoB,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC;YACnG,OAAO,UAAU,CAAC;QACpB,CAAC;QAED,cAAc;QACd,MAAM,aAAa,GAAG;YACpB,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;YACzD,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,WAAW;SACjD,CAAC;QACF,IAAI,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YAC9D,OAAO,OAAO,CAAC;QACjB,CAAC;QAED,mBAAmB;QACnB,IAAI,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;YAC7D,OAAO,YAAY,CAAC;QACtB,CAAC;QAED,qBAAqB;QACrB,OAAO,SAAS,CAAC;IACnB,CAAC;IAEO,WAAW,CAAC,cAAqB,EAAE,QAAyB;QAClE,wCAAwC;QACxC,IAAI,QAAQ,KAAK,UAAU,EAAE,CAAC;YAC5B,OAAO,cAAc,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC;QAClD,CAAC;QAED,gCAAgC;QAChC,IAAI,QAAQ,KAAK,OAAO,EAAE,CAAC;YACzB,OAAO,KAAK,CAAC;QACf,CAAC;QAED,iBAAiB;QACjB,OAAO,cAAc,KAAK,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC;IACjD,CAAC;CACF;AAED,eAAe,aAAa,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gitleaks Scanner
|
|
3
|
+
*
|
|
4
|
+
* Secret detection scanner using Gitleaks CLI
|
|
5
|
+
* Covers: secret category
|
|
6
|
+
*/
|
|
7
|
+
import { Scanner, ScanTarget, ScannerConfig, ScannerResult, FindingCategory } from '../types.js';
|
|
8
|
+
export declare class GitleaksScanner implements Scanner {
|
|
9
|
+
name: string;
|
|
10
|
+
categories: FindingCategory[];
|
|
11
|
+
isAvailable(): Promise<boolean>;
|
|
12
|
+
scan(target: ScanTarget, config?: ScannerConfig): Promise<ScannerResult>;
|
|
13
|
+
private runGitleaks;
|
|
14
|
+
private transformFindings;
|
|
15
|
+
private determineSeverity;
|
|
16
|
+
private redactSecret;
|
|
17
|
+
private redactSnippet;
|
|
18
|
+
private getSuggestion;
|
|
19
|
+
}
|
|
20
|
+
export default GitleaksScanner;
|
|
21
|
+
//# sourceMappingURL=gitleaks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gitleaks.d.ts","sourceRoot":"","sources":["../../src/scanners/gitleaks.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,EACL,OAAO,EACP,UAAU,EACV,aAAa,EACb,aAAa,EAEb,eAAe,EAGhB,MAAM,aAAa,CAAC;AAyBrB,qBAAa,eAAgB,YAAW,OAAO;IAC7C,IAAI,SAAc;IAClB,UAAU,EAAE,eAAe,EAAE,CAAc;IAErC,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;IAS/B,IAAI,CAAC,MAAM,EAAE,UAAU,EAAE,MAAM,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC;YAoChE,WAAW;IAkCzB,OAAO,CAAC,iBAAiB;IAgCzB,OAAO,CAAC,iBAAiB;IA4BzB,OAAO,CAAC,YAAY;IAQpB,OAAO,CAAC,aAAa;IAKrB,OAAO,CAAC,aAAa;CAYtB;AAED,eAAe,eAAe,CAAC"}
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gitleaks Scanner
|
|
3
|
+
*
|
|
4
|
+
* Secret detection scanner using Gitleaks CLI
|
|
5
|
+
* Covers: secret category
|
|
6
|
+
*/
|
|
7
|
+
import { execSync, exec } from 'child_process';
|
|
8
|
+
import { promisify } from 'util';
|
|
9
|
+
const execAsync = promisify(exec);
|
|
10
|
+
export class GitleaksScanner {
|
|
11
|
+
name = 'gitleaks';
|
|
12
|
+
categories = ['secret'];
|
|
13
|
+
async isAvailable() {
|
|
14
|
+
try {
|
|
15
|
+
execSync('gitleaks version', { stdio: 'pipe' });
|
|
16
|
+
return true;
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
async scan(target, config) {
|
|
23
|
+
const startTime = Date.now();
|
|
24
|
+
if (!await this.isAvailable()) {
|
|
25
|
+
return {
|
|
26
|
+
scanner: this.name,
|
|
27
|
+
success: false,
|
|
28
|
+
error: 'Gitleaks not installed. Install with: brew install gitleaks (or download from GitHub)',
|
|
29
|
+
findings: [],
|
|
30
|
+
metrics: { duration: Date.now() - startTime }
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
try {
|
|
34
|
+
const findings = await this.runGitleaks(target);
|
|
35
|
+
return {
|
|
36
|
+
scanner: this.name,
|
|
37
|
+
success: true,
|
|
38
|
+
findings,
|
|
39
|
+
metrics: {
|
|
40
|
+
duration: Date.now() - startTime,
|
|
41
|
+
filesScanned: findings.length > 0 ? new Set(findings.map(f => f.file)).size : 0
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
return {
|
|
47
|
+
scanner: this.name,
|
|
48
|
+
success: false,
|
|
49
|
+
error: error instanceof Error ? error.message : String(error),
|
|
50
|
+
findings: [],
|
|
51
|
+
metrics: { duration: Date.now() - startTime }
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
async runGitleaks(target) {
|
|
56
|
+
// Use 'dir' mode for scanning directories, 'git' mode for git repos
|
|
57
|
+
const scanMode = target.git ? 'git' : 'dir';
|
|
58
|
+
const cmd = `gitleaks ${scanMode} --source "${target.path}" --report-format json --report-path /dev/stdout --no-banner 2>/dev/null || true`;
|
|
59
|
+
try {
|
|
60
|
+
const { stdout } = await execAsync(cmd, {
|
|
61
|
+
timeout: 120000, // 2 minutes
|
|
62
|
+
maxBuffer: 10 * 1024 * 1024
|
|
63
|
+
});
|
|
64
|
+
if (!stdout.trim() || stdout.trim() === '[]') {
|
|
65
|
+
return [];
|
|
66
|
+
}
|
|
67
|
+
const findings = JSON.parse(stdout);
|
|
68
|
+
return this.transformFindings(findings);
|
|
69
|
+
}
|
|
70
|
+
catch (error) {
|
|
71
|
+
// Try to parse output even on error
|
|
72
|
+
if (error.stdout) {
|
|
73
|
+
try {
|
|
74
|
+
const findings = JSON.parse(error.stdout);
|
|
75
|
+
return this.transformFindings(findings);
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
// Empty or invalid output - no findings
|
|
79
|
+
return [];
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
throw error;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
transformFindings(gitleaksFindings) {
|
|
86
|
+
return gitleaksFindings.map(gf => {
|
|
87
|
+
const severity = this.determineSeverity(gf);
|
|
88
|
+
// Redact the actual secret value
|
|
89
|
+
const redactedSecret = this.redactSecret(gf.Secret);
|
|
90
|
+
const finding = {
|
|
91
|
+
id: `gitleaks-${gf.Fingerprint}`,
|
|
92
|
+
source: this.name,
|
|
93
|
+
severity,
|
|
94
|
+
category: 'secret',
|
|
95
|
+
file: gf.File,
|
|
96
|
+
line: gf.StartLine,
|
|
97
|
+
endLine: gf.EndLine,
|
|
98
|
+
column: gf.StartColumn,
|
|
99
|
+
endColumn: gf.EndColumn,
|
|
100
|
+
title: `Exposed Secret: ${gf.RuleID}`,
|
|
101
|
+
description: `${gf.Description}\n\nRedacted value: ${redactedSecret}`,
|
|
102
|
+
snippet: gf.Match ? this.redactSnippet(gf.Match, gf.Secret) : undefined,
|
|
103
|
+
suggestion: this.getSuggestion(gf.RuleID),
|
|
104
|
+
fixAvailable: true,
|
|
105
|
+
autoFixable: false, // Secrets require manual rotation
|
|
106
|
+
ruleId: gf.RuleID,
|
|
107
|
+
confidence: gf.Entropy > 4 ? 'high' : 'medium',
|
|
108
|
+
fingerprint: gf.Fingerprint
|
|
109
|
+
};
|
|
110
|
+
return finding;
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
determineSeverity(gf) {
|
|
114
|
+
const ruleId = gf.RuleID.toLowerCase();
|
|
115
|
+
// Critical: Production/API keys, AWS credentials
|
|
116
|
+
if (ruleId.includes('aws') ||
|
|
117
|
+
ruleId.includes('private-key') ||
|
|
118
|
+
ruleId.includes('api-key') ||
|
|
119
|
+
ruleId.includes('stripe') ||
|
|
120
|
+
ruleId.includes('github-token')) {
|
|
121
|
+
return 'critical';
|
|
122
|
+
}
|
|
123
|
+
// High: Database credentials, generic secrets
|
|
124
|
+
if (ruleId.includes('password') ||
|
|
125
|
+
ruleId.includes('database') ||
|
|
126
|
+
ruleId.includes('jwt') ||
|
|
127
|
+
ruleId.includes('oauth')) {
|
|
128
|
+
return 'high';
|
|
129
|
+
}
|
|
130
|
+
// Medium: Other secrets
|
|
131
|
+
return 'high'; // Default to high for any exposed secret
|
|
132
|
+
}
|
|
133
|
+
redactSecret(secret) {
|
|
134
|
+
if (secret.length <= 8) {
|
|
135
|
+
return '*'.repeat(secret.length);
|
|
136
|
+
}
|
|
137
|
+
const visible = Math.min(4, Math.floor(secret.length / 4));
|
|
138
|
+
return secret.slice(0, visible) + '*'.repeat(secret.length - visible * 2) + secret.slice(-visible);
|
|
139
|
+
}
|
|
140
|
+
redactSnippet(snippet, secret) {
|
|
141
|
+
if (!secret)
|
|
142
|
+
return snippet;
|
|
143
|
+
return snippet.replace(secret, this.redactSecret(secret));
|
|
144
|
+
}
|
|
145
|
+
getSuggestion(ruleId) {
|
|
146
|
+
const suggestions = {
|
|
147
|
+
'aws-access-key-id': 'Rotate the AWS access key immediately and use environment variables or AWS Secrets Manager',
|
|
148
|
+
'aws-secret-access-key': 'Rotate the AWS secret key immediately and use environment variables or AWS Secrets Manager',
|
|
149
|
+
'github-token': 'Revoke this GitHub token and generate a new one with minimum required permissions',
|
|
150
|
+
'generic-api-key': 'Rotate this API key and store securely using environment variables or a secrets manager',
|
|
151
|
+
'private-key': 'This private key is exposed. Generate a new key pair and revoke the compromised one',
|
|
152
|
+
'jwt-base64': 'Rotate the JWT signing secret and invalidate any tokens signed with the old secret'
|
|
153
|
+
};
|
|
154
|
+
return suggestions[ruleId] || 'Rotate this credential immediately and store it securely using environment variables or a secrets manager';
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
export default GitleaksScanner;
|
|
158
|
+
//# sourceMappingURL=gitleaks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gitleaks.js","sourceRoot":"","sources":["../../src/scanners/gitleaks.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Scanner Index
|
|
3
|
+
*
|
|
4
|
+
* Exports all available scanners
|
|
5
|
+
*/
|
|
6
|
+
export { SemgrepScanner } from './semgrep.js';
|
|
7
|
+
export { GitleaksScanner } from './gitleaks.js';
|
|
8
|
+
export { NpmAuditScanner } from './npm-audit.js';
|
|
9
|
+
export { ESLintScanner } from './eslint.js';
|
|
10
|
+
export { ComplexityScanner } from './complexity.js';
|
|
11
|
+
import type { Scanner } from '../types.js';
|
|
12
|
+
/**
|
|
13
|
+
* Get all available scanners
|
|
14
|
+
* Ordered by priority (security first)
|
|
15
|
+
*/
|
|
16
|
+
export declare function getAllScanners(): Scanner[];
|
|
17
|
+
/**
|
|
18
|
+
* Get scanners by category
|
|
19
|
+
*/
|
|
20
|
+
export declare function getScannersByCategory(categories: string[]): Scanner[];
|
|
21
|
+
/**
|
|
22
|
+
* Scanner coverage matrix for documentation
|
|
23
|
+
*/
|
|
24
|
+
export declare const SCANNER_COVERAGE: {
|
|
25
|
+
semgrep: {
|
|
26
|
+
categories: string[];
|
|
27
|
+
description: string;
|
|
28
|
+
languages: string[];
|
|
29
|
+
requirements: string;
|
|
30
|
+
};
|
|
31
|
+
gitleaks: {
|
|
32
|
+
categories: string[];
|
|
33
|
+
description: string;
|
|
34
|
+
languages: string[];
|
|
35
|
+
requirements: string;
|
|
36
|
+
};
|
|
37
|
+
'npm-audit': {
|
|
38
|
+
categories: string[];
|
|
39
|
+
description: string;
|
|
40
|
+
languages: string[];
|
|
41
|
+
requirements: string;
|
|
42
|
+
};
|
|
43
|
+
eslint: {
|
|
44
|
+
categories: string[];
|
|
45
|
+
description: string;
|
|
46
|
+
languages: string[];
|
|
47
|
+
requirements: string;
|
|
48
|
+
};
|
|
49
|
+
complexity: {
|
|
50
|
+
categories: string[];
|
|
51
|
+
description: string;
|
|
52
|
+
languages: string[];
|
|
53
|
+
requirements: string;
|
|
54
|
+
};
|
|
55
|
+
};
|
|
56
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/scanners/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAOpD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAE3C;;;GAGG;AACH,wBAAgB,cAAc,IAAI,OAAO,EAAE,CAQ1C;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,OAAO,EAAE,CAKrE;AAED;;GAEG;AACH,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+B5B,CAAC"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Scanner Index
|
|
3
|
+
*
|
|
4
|
+
* Exports all available scanners
|
|
5
|
+
*/
|
|
6
|
+
export { SemgrepScanner } from './semgrep.js';
|
|
7
|
+
export { GitleaksScanner } from './gitleaks.js';
|
|
8
|
+
export { NpmAuditScanner } from './npm-audit.js';
|
|
9
|
+
export { ESLintScanner } from './eslint.js';
|
|
10
|
+
export { ComplexityScanner } from './complexity.js';
|
|
11
|
+
import { SemgrepScanner } from './semgrep.js';
|
|
12
|
+
import { GitleaksScanner } from './gitleaks.js';
|
|
13
|
+
import { NpmAuditScanner } from './npm-audit.js';
|
|
14
|
+
import { ESLintScanner } from './eslint.js';
|
|
15
|
+
import { ComplexityScanner } from './complexity.js';
|
|
16
|
+
/**
|
|
17
|
+
* Get all available scanners
|
|
18
|
+
* Ordered by priority (security first)
|
|
19
|
+
*/
|
|
20
|
+
export function getAllScanners() {
|
|
21
|
+
return [
|
|
22
|
+
new SemgrepScanner(), // Security + Quality (SAST)
|
|
23
|
+
new GitleaksScanner(), // Secrets
|
|
24
|
+
new NpmAuditScanner(), // Dependencies (SCA)
|
|
25
|
+
new ESLintScanner(), // Quality + Style
|
|
26
|
+
new ComplexityScanner() // Complexity + Code Smells
|
|
27
|
+
];
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Get scanners by category
|
|
31
|
+
*/
|
|
32
|
+
export function getScannersByCategory(categories) {
|
|
33
|
+
const allScanners = getAllScanners();
|
|
34
|
+
return allScanners.filter(scanner => scanner.categories.some(cat => categories.includes(cat)));
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Scanner coverage matrix for documentation
|
|
38
|
+
*/
|
|
39
|
+
export const SCANNER_COVERAGE = {
|
|
40
|
+
semgrep: {
|
|
41
|
+
categories: ['security', 'quality', 'style'],
|
|
42
|
+
description: 'Static Application Security Testing (SAST)',
|
|
43
|
+
languages: ['JavaScript', 'TypeScript', 'Python', 'Go', 'Ruby', 'Java', 'C', 'PHP', 'and more'],
|
|
44
|
+
requirements: 'semgrep CLI'
|
|
45
|
+
},
|
|
46
|
+
gitleaks: {
|
|
47
|
+
categories: ['secret'],
|
|
48
|
+
description: 'Secret and credential detection',
|
|
49
|
+
languages: ['All (content-based scanning)'],
|
|
50
|
+
requirements: 'gitleaks CLI'
|
|
51
|
+
},
|
|
52
|
+
'npm-audit': {
|
|
53
|
+
categories: ['dependency'],
|
|
54
|
+
description: 'Dependency vulnerability scanning',
|
|
55
|
+
languages: ['JavaScript', 'TypeScript (Node.js)'],
|
|
56
|
+
requirements: 'npm'
|
|
57
|
+
},
|
|
58
|
+
eslint: {
|
|
59
|
+
categories: ['quality', 'style', 'security'],
|
|
60
|
+
description: 'JavaScript/TypeScript linting',
|
|
61
|
+
languages: ['JavaScript', 'TypeScript'],
|
|
62
|
+
requirements: 'eslint (project dependency)'
|
|
63
|
+
},
|
|
64
|
+
complexity: {
|
|
65
|
+
categories: ['complexity', 'quality'],
|
|
66
|
+
description: 'Code complexity and smell detection',
|
|
67
|
+
languages: ['JavaScript', 'TypeScript', 'Python', 'Ruby', 'PHP', 'Java', 'C#', 'Go'],
|
|
68
|
+
requirements: 'None (built-in)'
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/scanners/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAEpD,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAGpD;;;GAGG;AACH,MAAM,UAAU,cAAc;IAC5B,OAAO;QACL,IAAI,cAAc,EAAE,EAAO,4BAA4B;QACvD,IAAI,eAAe,EAAE,EAAM,UAAU;QACrC,IAAI,eAAe,EAAE,EAAM,qBAAqB;QAChD,IAAI,aAAa,EAAE,EAAQ,kBAAkB;QAC7C,IAAI,iBAAiB,EAAE,CAAI,2BAA2B;KACvD,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,qBAAqB,CAAC,UAAoB;IACxD,MAAM,WAAW,GAAG,cAAc,EAAE,CAAC;IACrC,OAAO,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAClC,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CACzD,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B,OAAO,EAAE;QACP,UAAU,EAAE,CAAC,UAAU,EAAE,SAAS,EAAE,OAAO,CAAC;QAC5C,WAAW,EAAE,4CAA4C;QACzD,SAAS,EAAE,CAAC,YAAY,EAAE,YAAY,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,UAAU,CAAC;QAC/F,YAAY,EAAE,aAAa;KAC5B;IACD,QAAQ,EAAE;QACR,UAAU,EAAE,CAAC,QAAQ,CAAC;QACtB,WAAW,EAAE,iCAAiC;QAC9C,SAAS,EAAE,CAAC,8BAA8B,CAAC;QAC3C,YAAY,EAAE,cAAc;KAC7B;IACD,WAAW,EAAE;QACX,UAAU,EAAE,CAAC,YAAY,CAAC;QAC1B,WAAW,EAAE,mCAAmC;QAChD,SAAS,EAAE,CAAC,YAAY,EAAE,sBAAsB,CAAC;QACjD,YAAY,EAAE,KAAK;KACpB;IACD,MAAM,EAAE;QACN,UAAU,EAAE,CAAC,SAAS,EAAE,OAAO,EAAE,UAAU,CAAC;QAC5C,WAAW,EAAE,+BAA+B;QAC5C,SAAS,EAAE,CAAC,YAAY,EAAE,YAAY,CAAC;QACvC,YAAY,EAAE,6BAA6B;KAC5C;IACD,UAAU,EAAE;QACV,UAAU,EAAE,CAAC,YAAY,EAAE,SAAS,CAAC;QACrC,WAAW,EAAE,qCAAqC;QAClD,SAAS,EAAE,CAAC,YAAY,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC;QACpF,YAAY,EAAE,iBAAiB;KAChC;CACF,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NPM Audit Scanner
|
|
3
|
+
*
|
|
4
|
+
* Dependency vulnerability scanning for JavaScript/Node.js projects
|
|
5
|
+
* Covers: dependency category
|
|
6
|
+
*/
|
|
7
|
+
import { Scanner, ScanTarget, ScannerConfig, ScannerResult, FindingCategory } from '../types.js';
|
|
8
|
+
export declare class NpmAuditScanner implements Scanner {
|
|
9
|
+
name: string;
|
|
10
|
+
categories: FindingCategory[];
|
|
11
|
+
isAvailable(): Promise<boolean>;
|
|
12
|
+
scan(target: ScanTarget, config?: ScannerConfig): Promise<ScannerResult>;
|
|
13
|
+
private runNpmAudit;
|
|
14
|
+
private transformFindings;
|
|
15
|
+
private mapSeverity;
|
|
16
|
+
private getFixInfo;
|
|
17
|
+
}
|
|
18
|
+
export default NpmAuditScanner;
|
|
19
|
+
//# sourceMappingURL=npm-audit.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"npm-audit.d.ts","sourceRoot":"","sources":["../../src/scanners/npm-audit.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,OAAO,EACL,OAAO,EACP,UAAU,EACV,aAAa,EACb,aAAa,EAEb,eAAe,EAGhB,MAAM,aAAa,CAAC;AAuDrB,qBAAa,eAAgB,YAAW,OAAO;IAC7C,IAAI,SAAe;IACnB,UAAU,EAAE,eAAe,EAAE,CAAkB;IAEzC,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;IAS/B,IAAI,CAAC,MAAM,EAAE,UAAU,EAAE,MAAM,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC;YA+ChE,WAAW;IA8BzB,OAAO,CAAC,iBAAiB;IA2CzB,OAAO,CAAC,WAAW;IAWnB,OAAO,CAAC,UAAU;CAuCnB;AAED,eAAe,eAAe,CAAC"}
|