guardrail-cli 1.0.6 → 2.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 +483 -10
- package/dist/commands/baseline.d.ts +7 -0
- package/dist/commands/baseline.d.ts.map +1 -0
- package/dist/commands/baseline.js +79 -0
- package/dist/commands/baseline.js.map +1 -0
- package/dist/commands/cache.d.ts +13 -0
- package/dist/commands/cache.d.ts.map +1 -0
- package/dist/commands/cache.js +165 -0
- package/dist/commands/cache.js.map +1 -0
- package/dist/commands/evidence.d.ts +45 -0
- package/dist/commands/evidence.d.ts.map +1 -0
- package/dist/commands/evidence.js +197 -0
- package/dist/commands/evidence.js.map +1 -0
- package/dist/commands/index.d.ts +8 -0
- package/dist/commands/index.d.ts.map +1 -0
- package/dist/commands/index.js +15 -0
- package/dist/commands/index.js.map +1 -0
- package/dist/commands/scan-secrets.d.ts +47 -0
- package/dist/commands/scan-secrets.d.ts.map +1 -0
- package/dist/commands/scan-secrets.js +225 -0
- package/dist/commands/scan-secrets.js.map +1 -0
- package/dist/commands/scan-vulnerabilities-enhanced.d.ts +41 -0
- package/dist/commands/scan-vulnerabilities-enhanced.d.ts.map +1 -0
- package/dist/commands/scan-vulnerabilities-enhanced.js +368 -0
- package/dist/commands/scan-vulnerabilities-enhanced.js.map +1 -0
- package/dist/commands/scan-vulnerabilities-osv.d.ts +58 -0
- package/dist/commands/scan-vulnerabilities-osv.d.ts.map +1 -0
- package/dist/commands/scan-vulnerabilities-osv.js +716 -0
- package/dist/commands/scan-vulnerabilities-osv.js.map +1 -0
- package/dist/commands/scan-vulnerabilities.d.ts +32 -0
- package/dist/commands/scan-vulnerabilities.d.ts.map +1 -0
- package/dist/commands/scan-vulnerabilities.js +283 -0
- package/dist/commands/scan-vulnerabilities.js.map +1 -0
- package/dist/commands/secrets-allowlist.d.ts +7 -0
- package/dist/commands/secrets-allowlist.d.ts.map +1 -0
- package/dist/commands/secrets-allowlist.js +85 -0
- package/dist/commands/secrets-allowlist.js.map +1 -0
- package/dist/fix/applicator.d.ts +44 -0
- package/dist/fix/applicator.d.ts.map +1 -0
- package/dist/fix/applicator.js +144 -0
- package/dist/fix/applicator.js.map +1 -0
- package/dist/fix/backup.d.ts +38 -0
- package/dist/fix/backup.d.ts.map +1 -0
- package/dist/fix/backup.js +154 -0
- package/dist/fix/backup.js.map +1 -0
- package/dist/fix/engine.d.ts +55 -0
- package/dist/fix/engine.d.ts.map +1 -0
- package/dist/fix/engine.js +285 -0
- package/dist/fix/engine.js.map +1 -0
- package/dist/fix/index.d.ts +5 -0
- package/dist/fix/index.d.ts.map +1 -0
- package/dist/fix/index.js +12 -0
- package/dist/fix/index.js.map +1 -0
- package/dist/fix/interactive.d.ts +22 -0
- package/dist/fix/interactive.d.ts.map +1 -0
- package/dist/fix/interactive.js +172 -0
- package/dist/fix/interactive.js.map +1 -0
- package/dist/formatters/index.d.ts +6 -0
- package/dist/formatters/index.d.ts.map +1 -0
- package/dist/formatters/index.js +11 -0
- package/dist/formatters/index.js.map +1 -0
- package/dist/formatters/sarif-enhanced.d.ts +78 -0
- package/dist/formatters/sarif-enhanced.d.ts.map +1 -0
- package/dist/formatters/sarif-enhanced.js +144 -0
- package/dist/formatters/sarif-enhanced.js.map +1 -0
- package/dist/formatters/sarif-v2.d.ts +121 -0
- package/dist/formatters/sarif-v2.d.ts.map +1 -0
- package/dist/formatters/sarif-v2.js +356 -0
- package/dist/formatters/sarif-v2.js.map +1 -0
- package/dist/formatters/sarif.d.ts +72 -0
- package/dist/formatters/sarif.d.ts.map +1 -0
- package/dist/formatters/sarif.js +146 -0
- package/dist/formatters/sarif.js.map +1 -0
- package/dist/index.js +3362 -1397
- package/dist/index.js.map +1 -1
- package/dist/init/ci-generator.d.ts +18 -0
- package/dist/init/ci-generator.d.ts.map +1 -0
- package/dist/init/ci-generator.js +251 -0
- package/dist/init/ci-generator.js.map +1 -0
- package/dist/init/detect-framework.d.ts +15 -0
- package/dist/init/detect-framework.d.ts.map +1 -0
- package/dist/init/detect-framework.js +299 -0
- package/dist/init/detect-framework.js.map +1 -0
- package/dist/init/hooks-installer.d.ts +22 -0
- package/dist/init/hooks-installer.d.ts.map +1 -0
- package/dist/init/hooks-installer.js +302 -0
- package/dist/init/hooks-installer.js.map +1 -0
- package/dist/init/index.d.ts +8 -0
- package/dist/init/index.d.ts.map +1 -0
- package/dist/init/index.js +22 -0
- package/dist/init/index.js.map +1 -0
- package/dist/init/templates.d.ts +401 -0
- package/dist/init/templates.d.ts.map +1 -0
- package/dist/init/templates.js +240 -0
- package/dist/init/templates.js.map +1 -0
- package/dist/reality/reality-runner.d.ts +76 -0
- package/dist/reality/reality-runner.d.ts.map +1 -0
- package/dist/reality/reality-runner.js +454 -0
- package/dist/reality/reality-runner.js.map +1 -0
- package/dist/runtime/auth-utils.d.ts +43 -0
- package/dist/runtime/auth-utils.d.ts.map +1 -0
- package/dist/runtime/auth-utils.js +126 -0
- package/dist/runtime/auth-utils.js.map +1 -0
- package/dist/runtime/client.d.ts +74 -0
- package/dist/runtime/client.d.ts.map +1 -0
- package/dist/runtime/client.js +222 -0
- package/dist/runtime/client.js.map +1 -0
- package/dist/runtime/creds.d.ts +48 -0
- package/dist/runtime/creds.d.ts.map +1 -0
- package/dist/runtime/creds.js +245 -0
- package/dist/runtime/creds.js.map +1 -0
- package/dist/runtime/exit-codes.d.ts +47 -0
- package/dist/runtime/exit-codes.d.ts.map +1 -0
- package/dist/runtime/exit-codes.js +91 -0
- package/dist/runtime/exit-codes.js.map +1 -0
- package/dist/runtime/index.d.ts +9 -0
- package/dist/runtime/index.d.ts.map +1 -0
- package/dist/runtime/index.js +25 -0
- package/dist/runtime/index.js.map +1 -0
- package/dist/runtime/semver.d.ts +37 -0
- package/dist/runtime/semver.d.ts.map +1 -0
- package/dist/runtime/semver.js +110 -0
- package/dist/runtime/semver.js.map +1 -0
- package/dist/scanner/baseline.d.ts +52 -0
- package/dist/scanner/baseline.d.ts.map +1 -0
- package/dist/scanner/baseline.js +85 -0
- package/dist/scanner/baseline.js.map +1 -0
- package/dist/scanner/incremental.d.ts +30 -0
- package/dist/scanner/incremental.d.ts.map +1 -0
- package/dist/scanner/incremental.js +82 -0
- package/dist/scanner/incremental.js.map +1 -0
- package/dist/scanner/parallel.d.ts +43 -0
- package/dist/scanner/parallel.d.ts.map +1 -0
- package/dist/scanner/parallel.js +99 -0
- package/dist/scanner/parallel.js.map +1 -0
- package/dist/ui/frame.d.ts +68 -0
- package/dist/ui/frame.d.ts.map +1 -0
- package/dist/ui/frame.js +165 -0
- package/dist/ui/frame.js.map +1 -0
- package/dist/ui/index.d.ts +5 -0
- package/dist/ui/index.d.ts.map +1 -0
- package/dist/ui/index.js +16 -0
- package/dist/ui/index.js.map +1 -0
- package/package.json +42 -9
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* scan:secrets command
|
|
4
|
+
* Enterprise-grade secret detection with SecretsGuardian
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.scanSecrets = scanSecrets;
|
|
8
|
+
exports.outputSecretsResults = outputSecretsResults;
|
|
9
|
+
exports.registerScanSecretsCommand = registerScanSecretsCommand;
|
|
10
|
+
const path_1 = require("path");
|
|
11
|
+
const security_1 = require("@guardrail/security");
|
|
12
|
+
const exit_codes_1 = require("../runtime/exit-codes");
|
|
13
|
+
const evidence_1 = require("./evidence");
|
|
14
|
+
const sarif_1 = require("../formatters/sarif");
|
|
15
|
+
const fs_1 = require("fs");
|
|
16
|
+
// Color helpers
|
|
17
|
+
const c = {
|
|
18
|
+
reset: '\x1b[0m',
|
|
19
|
+
bold: (s) => `\x1b[1m${s}\x1b[0m`,
|
|
20
|
+
dim: (s) => `\x1b[2m${s}\x1b[0m`,
|
|
21
|
+
high: (s) => `\x1b[31m${s}\x1b[0m`,
|
|
22
|
+
medium: (s) => `\x1b[33m${s}\x1b[0m`,
|
|
23
|
+
low: (s) => `\x1b[36m${s}\x1b[0m`,
|
|
24
|
+
success: (s) => `\x1b[32m${s}\x1b[0m`,
|
|
25
|
+
info: (s) => `\x1b[34m${s}\x1b[0m`,
|
|
26
|
+
};
|
|
27
|
+
async function scanSecrets(projectPath, options) {
|
|
28
|
+
const guardian = new security_1.SecretsGuardian();
|
|
29
|
+
// Scan git history if requested
|
|
30
|
+
if (options.history) {
|
|
31
|
+
try {
|
|
32
|
+
const historyReport = await (0, security_1.scanGitHistory)(projectPath, 'cli-scan', guardian, {
|
|
33
|
+
depth: options.historyDepth || 50,
|
|
34
|
+
excludeTests: options.excludeTests,
|
|
35
|
+
minConfidence: options.minConfidence,
|
|
36
|
+
useCustomPatterns: !options.noCustomPatterns,
|
|
37
|
+
useAllowlist: !options.noAllowlist,
|
|
38
|
+
useContextualRisk: !options.noContextualRisk,
|
|
39
|
+
});
|
|
40
|
+
const findings = historyReport.detections.map(d => ({
|
|
41
|
+
type: d.secretType,
|
|
42
|
+
file: `${d.filePath} (commit: ${d.commitHash.substring(0, 7)})`,
|
|
43
|
+
line: d.location.line,
|
|
44
|
+
risk: d.risk,
|
|
45
|
+
confidence: d.confidence,
|
|
46
|
+
entropy: d.entropy,
|
|
47
|
+
match: d.maskedValue,
|
|
48
|
+
isTest: d.isTest,
|
|
49
|
+
recommendation: d.recommendation,
|
|
50
|
+
}));
|
|
51
|
+
return {
|
|
52
|
+
projectPath,
|
|
53
|
+
scanType: 'secrets-history',
|
|
54
|
+
filesScanned: historyReport.commitsScanned,
|
|
55
|
+
patterns: Array.from(new Set(findings.map(f => f.type))),
|
|
56
|
+
findings,
|
|
57
|
+
summary: {
|
|
58
|
+
total: findings.length,
|
|
59
|
+
highEntropy: findings.filter(f => f.entropy >= 4.0).length,
|
|
60
|
+
lowEntropy: findings.filter(f => f.entropy < 4.0).length,
|
|
61
|
+
byRisk: historyReport.summary.byType,
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
catch (err) {
|
|
66
|
+
if (err.message.includes('Not a git repository')) {
|
|
67
|
+
console.error(`\n ${c.high('✗')} Not a git repository. Use --history only in git repos.\n`);
|
|
68
|
+
process.exit(1);
|
|
69
|
+
}
|
|
70
|
+
throw err;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
const report = await guardian.scanProject(projectPath, 'cli-scan', {
|
|
74
|
+
excludeTests: options.excludeTests,
|
|
75
|
+
minConfidence: options.minConfidence,
|
|
76
|
+
maxFileSizeBytes: 2 * 1024 * 1024,
|
|
77
|
+
concurrency: 8,
|
|
78
|
+
skipBinaryFiles: true,
|
|
79
|
+
useCustomPatterns: !options.noCustomPatterns,
|
|
80
|
+
useAllowlist: !options.noAllowlist,
|
|
81
|
+
useContextualRisk: !options.noContextualRisk,
|
|
82
|
+
});
|
|
83
|
+
const findings = report.detections.map(d => ({
|
|
84
|
+
type: d.secretType,
|
|
85
|
+
file: d.filePath,
|
|
86
|
+
line: d.location.line,
|
|
87
|
+
risk: d.risk,
|
|
88
|
+
confidence: d.confidence,
|
|
89
|
+
entropy: d.entropy,
|
|
90
|
+
match: d.maskedValue,
|
|
91
|
+
isTest: d.isTest,
|
|
92
|
+
recommendation: d.recommendation,
|
|
93
|
+
}));
|
|
94
|
+
const patternTypes = new Set(findings.map(f => f.type));
|
|
95
|
+
const highEntropy = findings.filter(f => f.entropy >= 4.0).length;
|
|
96
|
+
const lowEntropy = findings.filter(f => f.entropy < 4.0).length;
|
|
97
|
+
// Log performance stats if verbose
|
|
98
|
+
if (report.performance.customPatternsLoaded > 0) {
|
|
99
|
+
console.log(` ${c.info('ℹ')} Loaded ${report.performance.customPatternsLoaded} custom patterns from .guardrail/secrets.yaml`);
|
|
100
|
+
}
|
|
101
|
+
if (report.performance.allowlistSuppressed > 0) {
|
|
102
|
+
console.log(` ${c.info('ℹ')} Suppressed ${report.performance.allowlistSuppressed} allowlisted detections`);
|
|
103
|
+
}
|
|
104
|
+
if (report.performance.skippedLarge > 0 || report.performance.skippedBinary > 0) {
|
|
105
|
+
console.log(` ${c.dim(`Skipped: ${report.performance.skippedLarge} large files, ${report.performance.skippedBinary} binary files`)}`);
|
|
106
|
+
}
|
|
107
|
+
return {
|
|
108
|
+
projectPath,
|
|
109
|
+
scanType: 'secrets',
|
|
110
|
+
filesScanned: report.scannedFiles,
|
|
111
|
+
patterns: patternTypes.size > 0 ? Array.from(patternTypes) : ['API Keys', 'AWS Credentials', 'Private Keys', 'JWT Tokens', 'Database URLs'],
|
|
112
|
+
findings,
|
|
113
|
+
summary: {
|
|
114
|
+
total: findings.length,
|
|
115
|
+
highEntropy,
|
|
116
|
+
lowEntropy,
|
|
117
|
+
byRisk: report.summary.byRisk,
|
|
118
|
+
},
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
function outputSecretsResults(results, options) {
|
|
122
|
+
if (options.format === 'json') {
|
|
123
|
+
console.log(JSON.stringify(results, null, 2));
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
if (options.format === 'sarif') {
|
|
127
|
+
const sarif = (0, sarif_1.toSarif)(results);
|
|
128
|
+
console.log(JSON.stringify(sarif, null, 2));
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
console.log(` ${c.info('Patterns checked:')} ${results.patterns.join(', ')}\n`);
|
|
132
|
+
if (results.findings.length === 0) {
|
|
133
|
+
console.log(` ${c.success('✓')} ${c.bold('No secrets detected!')}\n`);
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
const highRisk = results.findings.filter(f => f.risk === 'high').length;
|
|
137
|
+
const mediumRisk = results.findings.filter(f => f.risk === 'medium').length;
|
|
138
|
+
const lowRisk = results.findings.filter(f => f.risk === 'low').length;
|
|
139
|
+
const testFiles = results.findings.filter(f => f.isTest).length;
|
|
140
|
+
console.log(` ${c.high('⚠')} ${c.bold(`${results.findings.length} potential secrets found:`)}`);
|
|
141
|
+
console.log(` ${c.high('HIGH:')} ${highRisk} ${c.medium('MEDIUM:')} ${mediumRisk} ${c.low('LOW:')} ${lowRisk} ${c.dim(`(${testFiles} in test files)`)}\n`);
|
|
142
|
+
for (const finding of results.findings) {
|
|
143
|
+
const riskLabel = finding.risk === 'high' ? c.high('HIGH') :
|
|
144
|
+
finding.risk === 'medium' ? c.medium('MEDIUM') : c.low('LOW');
|
|
145
|
+
const testTag = finding.isTest ? c.dim(' [TEST]') : '';
|
|
146
|
+
console.log(` ${riskLabel} ${finding.type}${testTag}`);
|
|
147
|
+
console.log(` ${c.dim('├─')} ${c.info('File:')} ${finding.file}:${finding.line}`);
|
|
148
|
+
console.log(` ${c.dim('├─')} ${c.info('Confidence:')} ${(finding.confidence * 100).toFixed(0)}% ${c.dim('Entropy:')} ${finding.entropy.toFixed(1)}`);
|
|
149
|
+
console.log(` ${c.dim('├─')} ${c.info('Match:')} ${finding.match}`);
|
|
150
|
+
console.log(` ${c.dim('└─')} ${c.info('Fix:')} ${finding.recommendation?.remediation || 'Move to environment variables'}\n`);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
function registerScanSecretsCommand(program, requireAuth, printLogo) {
|
|
154
|
+
program
|
|
155
|
+
.command('scan:secrets')
|
|
156
|
+
.description('Scan for hardcoded secrets and credentials')
|
|
157
|
+
.option('-p, --path <path>', 'Project path to scan', '.')
|
|
158
|
+
.option('-f, --format <format>', 'Output format: table, json, sarif', 'table')
|
|
159
|
+
.option('-o, --output <file>', 'Output file path')
|
|
160
|
+
.option('--exclude-tests', 'Exclude test files from scan', false)
|
|
161
|
+
.option('--min-confidence <number>', 'Minimum confidence threshold (0-1)')
|
|
162
|
+
.option('--fail-on-detection', 'Exit with error if secrets found', false)
|
|
163
|
+
.option('--evidence', 'Generate signed evidence pack', false)
|
|
164
|
+
.option('--history', 'Scan git commit history for secrets', false)
|
|
165
|
+
.option('--history-depth <number>', 'Number of commits to scan (default: 50)', '50')
|
|
166
|
+
.option('--no-custom-patterns', 'Disable custom patterns from .guardrail/secrets.yaml')
|
|
167
|
+
.option('--no-allowlist', 'Disable allowlist from .guardrail/secrets.allowlist')
|
|
168
|
+
.option('--no-contextual-risk', 'Disable contextual risk adjustment')
|
|
169
|
+
.action(async (opts) => {
|
|
170
|
+
requireAuth();
|
|
171
|
+
printLogo();
|
|
172
|
+
console.log(`\n${c.bold('🔐 SECRET DETECTION SCAN')}\n`);
|
|
173
|
+
const projectPath = (0, path_1.resolve)(opts.path);
|
|
174
|
+
const options = {
|
|
175
|
+
path: projectPath,
|
|
176
|
+
format: opts.format,
|
|
177
|
+
output: opts.output,
|
|
178
|
+
excludeTests: opts.excludeTests,
|
|
179
|
+
minConfidence: opts.minConfidence ? parseFloat(opts.minConfidence) : undefined,
|
|
180
|
+
failOnDetection: opts.failOnDetection,
|
|
181
|
+
evidence: opts.evidence,
|
|
182
|
+
history: opts.history,
|
|
183
|
+
historyDepth: opts.historyDepth ? parseInt(opts.historyDepth) : 50,
|
|
184
|
+
noCustomPatterns: opts.noCustomPatterns,
|
|
185
|
+
noAllowlist: opts.noAllowlist,
|
|
186
|
+
noContextualRisk: opts.noContextualRisk,
|
|
187
|
+
};
|
|
188
|
+
const startTime = Date.now();
|
|
189
|
+
let results;
|
|
190
|
+
try {
|
|
191
|
+
results = await scanSecrets(projectPath, options);
|
|
192
|
+
}
|
|
193
|
+
catch (err) {
|
|
194
|
+
if (err instanceof security_1.ConfigValidationError) {
|
|
195
|
+
console.error(`\n ${c.high('✗')} Custom patterns validation failed:\n`);
|
|
196
|
+
console.error(` ${err.message}\n`);
|
|
197
|
+
if (err.details) {
|
|
198
|
+
for (const detail of err.details) {
|
|
199
|
+
console.error(` • ${detail}`);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
console.error(`\n Fix .guardrail/secrets.yaml and try again.\n`);
|
|
203
|
+
process.exit(1);
|
|
204
|
+
}
|
|
205
|
+
throw err;
|
|
206
|
+
}
|
|
207
|
+
const duration = Date.now() - startTime;
|
|
208
|
+
console.log(`\n${c.success('✓')} Secret scan complete (${(duration / 1000).toFixed(1)}s)`);
|
|
209
|
+
outputSecretsResults(results, options);
|
|
210
|
+
// Save to output file if specified
|
|
211
|
+
if (options.output) {
|
|
212
|
+
const outputData = options.format === 'sarif' ? (0, sarif_1.toSarif)(results) : results;
|
|
213
|
+
(0, fs_1.writeFileSync)(options.output, JSON.stringify(outputData, null, 2));
|
|
214
|
+
console.log(`\n ${c.success('✓')} Results saved to ${options.output}`);
|
|
215
|
+
}
|
|
216
|
+
if (options.evidence) {
|
|
217
|
+
await (0, evidence_1.generateEvidence)('secrets', results, projectPath);
|
|
218
|
+
}
|
|
219
|
+
if (options.failOnDetection && results.findings.length > 0) {
|
|
220
|
+
const exitCode = (0, exit_codes_1.getExitCodeForFindings)({ high: results.summary.byRisk?.high || 0, medium: results.summary.byRisk?.medium || 0 }, { failOnHigh: true });
|
|
221
|
+
(0, exit_codes_1.exitWith)(exitCode, `${results.findings.length} secrets detected`);
|
|
222
|
+
}
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
//# sourceMappingURL=scan-secrets.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scan-secrets.js","sourceRoot":"","sources":["../../src/commands/scan-secrets.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* scan:vulnerabilities command (Enhanced)
|
|
3
|
+
* Enterprise-grade vulnerability detection using real-time OSV integration
|
|
4
|
+
*
|
|
5
|
+
* Features:
|
|
6
|
+
* - Real-time OSV API queries with 24h caching
|
|
7
|
+
* - Multi-ecosystem support (npm, PyPI, RubyGems, Go)
|
|
8
|
+
* - CVSS scoring and vectors
|
|
9
|
+
* - Remediation path analysis
|
|
10
|
+
* - Direct vs transitive vulnerability grouping
|
|
11
|
+
* - SARIF output support
|
|
12
|
+
*/
|
|
13
|
+
import { Command } from 'commander';
|
|
14
|
+
import { Ecosystem, VulnerabilityCheckResult } from '@guardrail/security/supply-chain/vulnerability-db';
|
|
15
|
+
export interface EnhancedVulnResult {
|
|
16
|
+
projectPath: string;
|
|
17
|
+
scanType: string;
|
|
18
|
+
ecosystem: Ecosystem;
|
|
19
|
+
packagesScanned: number;
|
|
20
|
+
findings: VulnerabilityCheckResult[];
|
|
21
|
+
summary: {
|
|
22
|
+
critical: number;
|
|
23
|
+
high: number;
|
|
24
|
+
medium: number;
|
|
25
|
+
low: number;
|
|
26
|
+
};
|
|
27
|
+
directVulnerabilities: number;
|
|
28
|
+
transitiveVulnerabilities: number;
|
|
29
|
+
cacheHitRate: number;
|
|
30
|
+
scanDuration: number;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Scan vulnerabilities with OSV integration
|
|
34
|
+
*/
|
|
35
|
+
export declare function scanVulnerabilitiesEnhanced(projectPath: string, options: any): Promise<EnhancedVulnResult>;
|
|
36
|
+
/**
|
|
37
|
+
* Output enhanced vulnerability results
|
|
38
|
+
*/
|
|
39
|
+
export declare function outputEnhancedVulnResults(results: EnhancedVulnResult, options: any): void;
|
|
40
|
+
export declare function registerScanVulnerabilitiesEnhancedCommand(program: Command, requireAuth: () => any, printLogo: () => void): void;
|
|
41
|
+
//# sourceMappingURL=scan-vulnerabilities-enhanced.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scan-vulnerabilities-enhanced.d.ts","sourceRoot":"","sources":["../../src/commands/scan-vulnerabilities-enhanced.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAIpC,OAAO,EAAyB,SAAS,EAAE,wBAAwB,EAAE,MAAM,mDAAmD,CAAC;AAe/H,MAAM,WAAW,kBAAkB;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,SAAS,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC;IACxB,QAAQ,EAAE,wBAAwB,EAAE,CAAC;IACrC,OAAO,EAAE;QACP,QAAQ,EAAE,MAAM,CAAC;QACjB,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,EAAE,MAAM,CAAC;QACf,GAAG,EAAE,MAAM,CAAC;KACb,CAAC;IACF,qBAAqB,EAAE,MAAM,CAAC;IAC9B,yBAAyB,EAAE,MAAM,CAAC;IAClC,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;CACtB;AAoMD;;GAEG;AACH,wBAAsB,2BAA2B,CAC/C,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,GAAG,GACX,OAAO,CAAC,kBAAkB,CAAC,CAiF7B;AAED;;GAEG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,kBAAkB,EAAE,OAAO,EAAE,GAAG,GAAG,IAAI,CA6CzF;AA6BD,wBAAgB,0CAA0C,CACxD,OAAO,EAAE,OAAO,EAChB,WAAW,EAAE,MAAM,GAAG,EACtB,SAAS,EAAE,MAAM,IAAI,GACpB,IAAI,CAmCN"}
|
|
@@ -0,0 +1,368 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* scan:vulnerabilities command (Enhanced)
|
|
4
|
+
* Enterprise-grade vulnerability detection using real-time OSV integration
|
|
5
|
+
*
|
|
6
|
+
* Features:
|
|
7
|
+
* - Real-time OSV API queries with 24h caching
|
|
8
|
+
* - Multi-ecosystem support (npm, PyPI, RubyGems, Go)
|
|
9
|
+
* - CVSS scoring and vectors
|
|
10
|
+
* - Remediation path analysis
|
|
11
|
+
* - Direct vs transitive vulnerability grouping
|
|
12
|
+
* - SARIF output support
|
|
13
|
+
*/
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.scanVulnerabilitiesEnhanced = scanVulnerabilitiesEnhanced;
|
|
16
|
+
exports.outputEnhancedVulnResults = outputEnhancedVulnResults;
|
|
17
|
+
exports.registerScanVulnerabilitiesEnhancedCommand = registerScanVulnerabilitiesEnhancedCommand;
|
|
18
|
+
const path_1 = require("path");
|
|
19
|
+
const fs_1 = require("fs");
|
|
20
|
+
const exit_codes_1 = require("../runtime/exit-codes");
|
|
21
|
+
const vulnerability_db_1 = require("@guardrail/security/supply-chain/vulnerability-db");
|
|
22
|
+
const evidence_1 = require("./evidence");
|
|
23
|
+
const sarif_enhanced_1 = require("../formatters/sarif-enhanced");
|
|
24
|
+
const c = {
|
|
25
|
+
bold: (s) => `\x1b[1m${s}\x1b[0m`,
|
|
26
|
+
dim: (s) => `\x1b[2m${s}\x1b[0m`,
|
|
27
|
+
critical: (s) => `\x1b[35m${s}\x1b[0m`,
|
|
28
|
+
high: (s) => `\x1b[31m${s}\x1b[0m`,
|
|
29
|
+
medium: (s) => `\x1b[33m${s}\x1b[0m`,
|
|
30
|
+
low: (s) => `\x1b[36m${s}\x1b[0m`,
|
|
31
|
+
success: (s) => `\x1b[32m${s}\x1b[0m`,
|
|
32
|
+
info: (s) => `\x1b[34m${s}\x1b[0m`,
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* Detect ecosystem from project files
|
|
36
|
+
*/
|
|
37
|
+
function detectEcosystems(projectPath) {
|
|
38
|
+
const ecosystems = [];
|
|
39
|
+
if ((0, fs_1.existsSync)((0, path_1.join)(projectPath, 'package.json')) ||
|
|
40
|
+
(0, fs_1.existsSync)((0, path_1.join)(projectPath, 'package-lock.json')) ||
|
|
41
|
+
(0, fs_1.existsSync)((0, path_1.join)(projectPath, 'pnpm-lock.yaml')) ||
|
|
42
|
+
(0, fs_1.existsSync)((0, path_1.join)(projectPath, 'yarn.lock'))) {
|
|
43
|
+
ecosystems.push('npm');
|
|
44
|
+
}
|
|
45
|
+
if ((0, fs_1.existsSync)((0, path_1.join)(projectPath, 'requirements.txt')) ||
|
|
46
|
+
(0, fs_1.existsSync)((0, path_1.join)(projectPath, 'Pipfile')) ||
|
|
47
|
+
(0, fs_1.existsSync)((0, path_1.join)(projectPath, 'poetry.lock')) ||
|
|
48
|
+
(0, fs_1.existsSync)((0, path_1.join)(projectPath, 'pyproject.toml'))) {
|
|
49
|
+
ecosystems.push('PyPI');
|
|
50
|
+
}
|
|
51
|
+
if ((0, fs_1.existsSync)((0, path_1.join)(projectPath, 'Gemfile')) ||
|
|
52
|
+
(0, fs_1.existsSync)((0, path_1.join)(projectPath, 'Gemfile.lock'))) {
|
|
53
|
+
ecosystems.push('RubyGems');
|
|
54
|
+
}
|
|
55
|
+
if ((0, fs_1.existsSync)((0, path_1.join)(projectPath, 'go.mod')) ||
|
|
56
|
+
(0, fs_1.existsSync)((0, path_1.join)(projectPath, 'go.sum'))) {
|
|
57
|
+
ecosystems.push('Go');
|
|
58
|
+
}
|
|
59
|
+
return ecosystems;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Parse npm dependencies
|
|
63
|
+
*/
|
|
64
|
+
function parseNpmDependencies(projectPath) {
|
|
65
|
+
const packages = [];
|
|
66
|
+
const packageJsonPath = (0, path_1.join)(projectPath, 'package.json');
|
|
67
|
+
if (!(0, fs_1.existsSync)(packageJsonPath))
|
|
68
|
+
return packages;
|
|
69
|
+
try {
|
|
70
|
+
const packageJson = JSON.parse((0, fs_1.readFileSync)(packageJsonPath, 'utf-8'));
|
|
71
|
+
const deps = packageJson.dependencies || {};
|
|
72
|
+
const devDeps = packageJson.devDependencies || {};
|
|
73
|
+
for (const [name, version] of Object.entries(deps)) {
|
|
74
|
+
const cleanVersion = String(version).replace(/^[\^~>=<]+/, '');
|
|
75
|
+
packages.push({ name, version: cleanVersion, ecosystem: 'npm', isDirect: true });
|
|
76
|
+
}
|
|
77
|
+
for (const [name, version] of Object.entries(devDeps)) {
|
|
78
|
+
const cleanVersion = String(version).replace(/^[\^~>=<]+/, '');
|
|
79
|
+
packages.push({ name, version: cleanVersion, ecosystem: 'npm', isDirect: true });
|
|
80
|
+
}
|
|
81
|
+
// Parse lockfile for transitive dependencies
|
|
82
|
+
const lockPath = (0, path_1.join)(projectPath, 'package-lock.json');
|
|
83
|
+
if ((0, fs_1.existsSync)(lockPath)) {
|
|
84
|
+
try {
|
|
85
|
+
const lockData = JSON.parse((0, fs_1.readFileSync)(lockPath, 'utf-8'));
|
|
86
|
+
const lockPackages = lockData.packages || {};
|
|
87
|
+
for (const [pkgPath, pkgInfo] of Object.entries(lockPackages)) {
|
|
88
|
+
if (typeof pkgInfo === 'object' && pkgInfo !== null) {
|
|
89
|
+
const info = pkgInfo;
|
|
90
|
+
const name = info.name || pkgPath.replace(/^node_modules\//, '');
|
|
91
|
+
const version = info.version;
|
|
92
|
+
if (name && version && !packages.find(p => p.name === name)) {
|
|
93
|
+
packages.push({ name, version, ecosystem: 'npm', isDirect: false });
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
// Lockfile parsing failed
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
// Package.json parsing failed
|
|
105
|
+
}
|
|
106
|
+
return packages;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Parse Python dependencies
|
|
110
|
+
*/
|
|
111
|
+
function parsePythonDependencies(projectPath) {
|
|
112
|
+
const packages = [];
|
|
113
|
+
const requirementsPath = (0, path_1.join)(projectPath, 'requirements.txt');
|
|
114
|
+
if ((0, fs_1.existsSync)(requirementsPath)) {
|
|
115
|
+
try {
|
|
116
|
+
const content = (0, fs_1.readFileSync)(requirementsPath, 'utf-8');
|
|
117
|
+
const lines = content.split('\n');
|
|
118
|
+
for (const line of lines) {
|
|
119
|
+
const trimmed = line.trim();
|
|
120
|
+
if (!trimmed || trimmed.startsWith('#'))
|
|
121
|
+
continue;
|
|
122
|
+
const match = trimmed.match(/^([a-zA-Z0-9_-]+)(?:==|>=|<=|~=|>|<)?([\d.]+)?/);
|
|
123
|
+
if (match) {
|
|
124
|
+
const name = match[1];
|
|
125
|
+
const version = match[2] || 'latest';
|
|
126
|
+
packages.push({ name, version, ecosystem: 'PyPI', isDirect: true });
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
catch {
|
|
131
|
+
// Requirements.txt parsing failed
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return packages;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Parse Ruby dependencies
|
|
138
|
+
*/
|
|
139
|
+
function parseRubyDependencies(projectPath) {
|
|
140
|
+
const packages = [];
|
|
141
|
+
const gemfilePath = (0, path_1.join)(projectPath, 'Gemfile');
|
|
142
|
+
if ((0, fs_1.existsSync)(gemfilePath)) {
|
|
143
|
+
try {
|
|
144
|
+
const content = (0, fs_1.readFileSync)(gemfilePath, 'utf-8');
|
|
145
|
+
const lines = content.split('\n');
|
|
146
|
+
for (const line of lines) {
|
|
147
|
+
const trimmed = line.trim();
|
|
148
|
+
const match = trimmed.match(/gem\s+['"]([^'"]+)['"]\s*,?\s*['"]?([~>=<\d.]+)?['"]?/);
|
|
149
|
+
if (match) {
|
|
150
|
+
const name = match[1];
|
|
151
|
+
const version = match[2]?.replace(/[~>=<]/g, '') || 'latest';
|
|
152
|
+
packages.push({ name, version, ecosystem: 'RubyGems', isDirect: true });
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
catch {
|
|
157
|
+
// Gemfile parsing failed
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
return packages;
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Parse Go dependencies
|
|
164
|
+
*/
|
|
165
|
+
function parseGoDependencies(projectPath) {
|
|
166
|
+
const packages = [];
|
|
167
|
+
const goModPath = (0, path_1.join)(projectPath, 'go.mod');
|
|
168
|
+
if ((0, fs_1.existsSync)(goModPath)) {
|
|
169
|
+
try {
|
|
170
|
+
const content = (0, fs_1.readFileSync)(goModPath, 'utf-8');
|
|
171
|
+
const lines = content.split('\n');
|
|
172
|
+
let inRequire = false;
|
|
173
|
+
for (const line of lines) {
|
|
174
|
+
const trimmed = line.trim();
|
|
175
|
+
if (trimmed.startsWith('require (')) {
|
|
176
|
+
inRequire = true;
|
|
177
|
+
continue;
|
|
178
|
+
}
|
|
179
|
+
if (inRequire && trimmed === ')') {
|
|
180
|
+
inRequire = false;
|
|
181
|
+
continue;
|
|
182
|
+
}
|
|
183
|
+
const match = trimmed.match(/^(?:require\s+)?([^\s]+)\s+v?([\d.]+)/);
|
|
184
|
+
if (match) {
|
|
185
|
+
const name = match[1];
|
|
186
|
+
const version = match[2];
|
|
187
|
+
packages.push({ name, version, ecosystem: 'Go', isDirect: true });
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
catch {
|
|
192
|
+
// go.mod parsing failed
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
return packages;
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Scan vulnerabilities with OSV integration
|
|
199
|
+
*/
|
|
200
|
+
async function scanVulnerabilitiesEnhanced(projectPath, options) {
|
|
201
|
+
const startTime = Date.now();
|
|
202
|
+
const ecosystems = detectEcosystems(projectPath);
|
|
203
|
+
if (ecosystems.length === 0) {
|
|
204
|
+
return {
|
|
205
|
+
projectPath,
|
|
206
|
+
scanType: 'vulnerabilities',
|
|
207
|
+
ecosystem: 'npm',
|
|
208
|
+
packagesScanned: 0,
|
|
209
|
+
findings: [],
|
|
210
|
+
summary: { critical: 0, high: 0, medium: 0, low: 0 },
|
|
211
|
+
directVulnerabilities: 0,
|
|
212
|
+
transitiveVulnerabilities: 0,
|
|
213
|
+
cacheHitRate: 0,
|
|
214
|
+
scanDuration: Date.now() - startTime,
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
// Parse dependencies from all detected ecosystems
|
|
218
|
+
let allPackages = [];
|
|
219
|
+
for (const ecosystem of ecosystems) {
|
|
220
|
+
switch (ecosystem) {
|
|
221
|
+
case 'npm':
|
|
222
|
+
allPackages.push(...parseNpmDependencies(projectPath));
|
|
223
|
+
break;
|
|
224
|
+
case 'PyPI':
|
|
225
|
+
allPackages.push(...parsePythonDependencies(projectPath));
|
|
226
|
+
break;
|
|
227
|
+
case 'RubyGems':
|
|
228
|
+
allPackages.push(...parseRubyDependencies(projectPath));
|
|
229
|
+
break;
|
|
230
|
+
case 'Go':
|
|
231
|
+
allPackages.push(...parseGoDependencies(projectPath));
|
|
232
|
+
break;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
// Query OSV for vulnerabilities
|
|
236
|
+
const db = new vulnerability_db_1.VulnerabilityDatabase();
|
|
237
|
+
const results = await db.checkPackages(allPackages);
|
|
238
|
+
// Calculate summary
|
|
239
|
+
const summary = {
|
|
240
|
+
critical: 0,
|
|
241
|
+
high: 0,
|
|
242
|
+
medium: 0,
|
|
243
|
+
low: 0,
|
|
244
|
+
};
|
|
245
|
+
let directVulnerabilities = 0;
|
|
246
|
+
let transitiveVulnerabilities = 0;
|
|
247
|
+
for (const result of results) {
|
|
248
|
+
if (result.isVulnerable) {
|
|
249
|
+
for (const vuln of result.vulnerabilities) {
|
|
250
|
+
summary[vuln.severity]++;
|
|
251
|
+
}
|
|
252
|
+
if (result.isDirect) {
|
|
253
|
+
directVulnerabilities += result.vulnerabilities.length;
|
|
254
|
+
}
|
|
255
|
+
else {
|
|
256
|
+
transitiveVulnerabilities += result.vulnerabilities.length;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
const cacheStats = db.getCacheStats();
|
|
261
|
+
return {
|
|
262
|
+
projectPath,
|
|
263
|
+
scanType: 'vulnerabilities',
|
|
264
|
+
ecosystem: ecosystems[0],
|
|
265
|
+
packagesScanned: allPackages.length,
|
|
266
|
+
findings: results.filter(r => r.isVulnerable),
|
|
267
|
+
summary,
|
|
268
|
+
directVulnerabilities,
|
|
269
|
+
transitiveVulnerabilities,
|
|
270
|
+
cacheHitRate: cacheStats.hitRate,
|
|
271
|
+
scanDuration: Date.now() - startTime,
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* Output enhanced vulnerability results
|
|
276
|
+
*/
|
|
277
|
+
function outputEnhancedVulnResults(results, options) {
|
|
278
|
+
if (options.format === 'json') {
|
|
279
|
+
console.log(JSON.stringify(results, null, 2));
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
if (options.format === 'sarif') {
|
|
283
|
+
const sarif = (0, sarif_enhanced_1.toSarifVulnerabilitiesEnhanced)(results);
|
|
284
|
+
console.log(JSON.stringify(sarif, null, 2));
|
|
285
|
+
return;
|
|
286
|
+
}
|
|
287
|
+
console.log(`\n ${c.info('Ecosystem:')} ${results.ecosystem}`);
|
|
288
|
+
console.log(` ${c.info('Packages scanned:')} ${results.packagesScanned}`);
|
|
289
|
+
console.log(` ${c.info('Cache hit rate:')} ${(results.cacheHitRate * 100).toFixed(1)}%`);
|
|
290
|
+
console.log(` ${c.info('Scan duration:')} ${(results.scanDuration / 1000).toFixed(2)}s\n`);
|
|
291
|
+
const { summary } = results;
|
|
292
|
+
const total = summary.critical + summary.high + summary.medium + summary.low;
|
|
293
|
+
if (total === 0) {
|
|
294
|
+
console.log(` ${c.success('✓')} ${c.bold('No vulnerabilities found!')}\n`);
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
297
|
+
console.log(` ${c.critical('CRITICAL')} ${summary.critical}`);
|
|
298
|
+
console.log(` ${c.high('HIGH')} ${summary.high}`);
|
|
299
|
+
console.log(` ${c.medium('MEDIUM')} ${summary.medium}`);
|
|
300
|
+
console.log(` ${c.low('LOW')} ${summary.low}\n`);
|
|
301
|
+
console.log(` ${c.info('Direct:')} ${results.directVulnerabilities} | ${c.info('Transitive:')} ${results.transitiveVulnerabilities}\n`);
|
|
302
|
+
// Group by direct vs transitive
|
|
303
|
+
const directFindings = results.findings.filter(f => f.isDirect);
|
|
304
|
+
const transitiveFindings = results.findings.filter(f => !f.isDirect);
|
|
305
|
+
if (directFindings.length > 0) {
|
|
306
|
+
console.log(`${c.bold(' DIRECT DEPENDENCIES:')}\n`);
|
|
307
|
+
outputFindingsList(directFindings);
|
|
308
|
+
}
|
|
309
|
+
if (transitiveFindings.length > 0) {
|
|
310
|
+
console.log(`\n${c.bold(' TRANSITIVE DEPENDENCIES:')}\n`);
|
|
311
|
+
outputFindingsList(transitiveFindings);
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
function outputFindingsList(findings) {
|
|
315
|
+
for (const finding of findings) {
|
|
316
|
+
for (const vuln of finding.vulnerabilities) {
|
|
317
|
+
const severityLabel = vuln.severity === 'critical' ? c.critical('CRITICAL') :
|
|
318
|
+
vuln.severity === 'high' ? c.high('HIGH') :
|
|
319
|
+
vuln.severity === 'medium' ? c.medium('MEDIUM') :
|
|
320
|
+
c.low('LOW');
|
|
321
|
+
console.log(` ${severityLabel} ${finding.package}@${finding.version}`);
|
|
322
|
+
console.log(` ${c.dim('├─')} ${c.info('ID:')} ${vuln.id}`);
|
|
323
|
+
console.log(` ${c.dim('├─')} ${c.info('Title:')} ${vuln.title}`);
|
|
324
|
+
if (vuln.cvssScore) {
|
|
325
|
+
console.log(` ${c.dim('├─')} ${c.info('CVSS:')} ${vuln.cvssScore.toFixed(1)}${vuln.cvssVector ? ` (${vuln.cvssVector})` : ''}`);
|
|
326
|
+
}
|
|
327
|
+
if (finding.remediationPath) {
|
|
328
|
+
const remed = finding.remediationPath;
|
|
329
|
+
const breakingLabel = remed.breakingChange ? c.medium(' [BREAKING]') : c.success(' [NON-BREAKING]');
|
|
330
|
+
console.log(` ${c.dim('└─')} ${c.info('Fix:')} ${remed.description}${breakingLabel}\n`);
|
|
331
|
+
}
|
|
332
|
+
else {
|
|
333
|
+
console.log(` ${c.dim('└─')} ${c.info('Fix:')} ${finding.recommendedVersion || 'No fix available'}\n`);
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
function registerScanVulnerabilitiesEnhancedCommand(program, requireAuth, printLogo) {
|
|
339
|
+
program
|
|
340
|
+
.command('scan:vulnerabilities')
|
|
341
|
+
.description('Scan dependencies for known vulnerabilities (OSV integration)')
|
|
342
|
+
.option('-p, --path <path>', 'Project path to scan', '.')
|
|
343
|
+
.option('-f, --format <format>', 'Output format: table, json, sarif', 'table')
|
|
344
|
+
.option('-o, --output <file>', 'Output file path')
|
|
345
|
+
.option('--fail-on-critical', 'Exit with error if critical vulnerabilities found', false)
|
|
346
|
+
.option('--fail-on-high', 'Exit with error if high+ vulnerabilities found', false)
|
|
347
|
+
.option('--evidence', 'Generate signed evidence pack', false)
|
|
348
|
+
.option('--ecosystem <ecosystem>', 'Filter by ecosystem: npm, PyPI, RubyGems, Go')
|
|
349
|
+
.action(async (opts) => {
|
|
350
|
+
requireAuth();
|
|
351
|
+
printLogo();
|
|
352
|
+
console.log(`\n${c.bold('🛡️ VULNERABILITY SCAN (OSV Integration)')}\n`);
|
|
353
|
+
const projectPath = (0, path_1.resolve)(opts.path);
|
|
354
|
+
const results = await scanVulnerabilitiesEnhanced(projectPath, opts);
|
|
355
|
+
console.log(`${c.success('✓')} Vulnerability scan complete`);
|
|
356
|
+
outputEnhancedVulnResults(results, opts);
|
|
357
|
+
if (opts.evidence) {
|
|
358
|
+
await (0, evidence_1.generateEvidence)('vulnerabilities', results, projectPath);
|
|
359
|
+
}
|
|
360
|
+
if (opts.failOnCritical && results.summary.critical > 0) {
|
|
361
|
+
(0, exit_codes_1.exitWith)(exit_codes_1.ExitCode.POLICY_FAIL, `${results.summary.critical} critical vulnerabilities found`);
|
|
362
|
+
}
|
|
363
|
+
if (opts.failOnHigh && (results.summary.critical + results.summary.high) > 0) {
|
|
364
|
+
(0, exit_codes_1.exitWith)(exit_codes_1.ExitCode.POLICY_FAIL, `${results.summary.critical + results.summary.high} high+ vulnerabilities found`);
|
|
365
|
+
}
|
|
366
|
+
});
|
|
367
|
+
}
|
|
368
|
+
//# sourceMappingURL=scan-vulnerabilities-enhanced.js.map
|