@vibecheckai/cli 3.3.0 → 3.5.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/bin/registry.js +389 -269
- package/bin/runners/cli-utils.js +2 -33
- package/bin/runners/context/generators/cursor.js +49 -2
- package/bin/runners/lib/agent-firewall/learning/learning-engine.js +849 -0
- package/bin/runners/lib/analyzers.js +599 -142
- package/bin/runners/lib/audit-logger.js +532 -0
- package/bin/runners/lib/authority/authorities/architecture.js +364 -0
- package/bin/runners/lib/authority/authorities/compliance.js +341 -0
- package/bin/runners/lib/authority/authorities/human.js +343 -0
- package/bin/runners/lib/authority/authorities/quality.js +420 -0
- package/bin/runners/lib/authority/authorities/security.js +228 -0
- package/bin/runners/lib/authority/index.js +293 -0
- package/bin/runners/lib/authority-badge.js +425 -425
- package/bin/runners/lib/bundle/bundle-intelligence.js +846 -0
- package/bin/runners/lib/cli-charts.js +368 -0
- package/bin/runners/lib/cli-config-display.js +405 -0
- package/bin/runners/lib/cli-demo.js +275 -0
- package/bin/runners/lib/cli-errors.js +438 -0
- package/bin/runners/lib/cli-help-formatter.js +439 -0
- package/bin/runners/lib/cli-interactive-menu.js +509 -0
- package/bin/runners/lib/cli-prompts.js +441 -0
- package/bin/runners/lib/cli-scan-cards.js +362 -0
- package/bin/runners/lib/compliance-reporter.js +710 -0
- package/bin/runners/lib/conductor/index.js +671 -0
- package/bin/runners/lib/easy/README.md +123 -0
- package/bin/runners/lib/easy/index.js +140 -0
- package/bin/runners/lib/easy/interactive-wizard.js +788 -0
- package/bin/runners/lib/easy/one-click-firewall.js +564 -0
- package/bin/runners/lib/easy/zero-config-reality.js +714 -0
- package/bin/runners/lib/engines/accessibility-engine.js +218 -18
- package/bin/runners/lib/engines/api-consistency-engine.js +335 -30
- package/bin/runners/lib/engines/async-patterns-engine.js +444 -0
- package/bin/runners/lib/engines/bundle-size-engine.js +433 -0
- package/bin/runners/lib/engines/confidence-scoring.js +276 -0
- package/bin/runners/lib/engines/context-detection.js +264 -0
- package/bin/runners/lib/engines/cross-file-analysis-engine.js +292 -27
- package/bin/runners/lib/engines/database-patterns-engine.js +429 -0
- package/bin/runners/lib/engines/duplicate-code-engine.js +354 -0
- package/bin/runners/lib/engines/empty-catch-engine.js +127 -17
- package/bin/runners/lib/engines/env-variables-engine.js +458 -0
- package/bin/runners/lib/engines/error-handling-engine.js +437 -0
- package/bin/runners/lib/engines/false-positive-prevention.js +630 -0
- package/bin/runners/lib/engines/framework-adapters/index.js +607 -0
- package/bin/runners/lib/engines/framework-detection.js +508 -0
- package/bin/runners/lib/engines/import-order-engine.js +429 -0
- package/bin/runners/lib/engines/mock-data-engine.js +53 -10
- package/bin/runners/lib/engines/naming-conventions-engine.js +544 -0
- package/bin/runners/lib/engines/noise-reduction-engine.js +452 -0
- package/bin/runners/lib/engines/orchestrator.js +334 -0
- package/bin/runners/lib/engines/performance-issues-engine.js +176 -36
- package/bin/runners/lib/engines/react-patterns-engine.js +457 -0
- package/bin/runners/lib/engines/security-vulnerabilities-engine.js +382 -54
- package/bin/runners/lib/engines/type-aware-engine.js +263 -39
- package/bin/runners/lib/engines/vibecheck-engines/index.js +122 -13
- package/bin/runners/lib/engines/vibecheck-engines/lib/ai-hallucination-engine.js +806 -0
- package/bin/runners/lib/engines/vibecheck-engines/lib/hardcoded-secrets-engine.js +373 -73
- package/bin/runners/lib/engines/vibecheck-engines/lib/smart-fix-engine.js +577 -0
- package/bin/runners/lib/engines/vibecheck-engines/lib/vibe-score-engine.js +543 -0
- package/bin/runners/lib/engines/vibecheck-engines.js +514 -0
- package/bin/runners/lib/enhanced-features/index.js +305 -0
- package/bin/runners/lib/enhanced-output.js +631 -0
- package/bin/runners/lib/enterprise.js +300 -0
- package/bin/runners/lib/entitlements-v2.js +161 -478
- package/bin/runners/lib/firewall/command-validator.js +351 -0
- package/bin/runners/lib/firewall/config.js +341 -0
- package/bin/runners/lib/firewall/content-validator.js +519 -0
- package/bin/runners/lib/firewall/index.js +101 -0
- package/bin/runners/lib/firewall/path-validator.js +256 -0
- package/bin/runners/lib/html-proof-report.js +350 -700
- package/bin/runners/lib/intelligence/cross-repo-intelligence.js +817 -0
- package/bin/runners/lib/mcp-utils.js +425 -0
- package/bin/runners/lib/missions/plan.js +46 -6
- package/bin/runners/lib/missions/templates.js +232 -0
- package/bin/runners/lib/output/index.js +1022 -0
- package/bin/runners/lib/policy-engine.js +652 -0
- package/bin/runners/lib/polish/autofix/accessibility-fixes.js +333 -0
- package/bin/runners/lib/polish/autofix/async-handlers.js +273 -0
- package/bin/runners/lib/polish/autofix/dead-code.js +280 -0
- package/bin/runners/lib/polish/autofix/imports-optimizer.js +344 -0
- package/bin/runners/lib/polish/autofix/index.js +200 -0
- package/bin/runners/lib/polish/autofix/remove-consoles.js +209 -0
- package/bin/runners/lib/polish/autofix/strengthen-types.js +245 -0
- package/bin/runners/lib/polish/backend-checks.js +148 -0
- package/bin/runners/lib/polish/documentation-checks.js +111 -0
- package/bin/runners/lib/polish/frontend-checks.js +168 -0
- package/bin/runners/lib/polish/index.js +71 -0
- package/bin/runners/lib/polish/infrastructure-checks.js +131 -0
- package/bin/runners/lib/polish/library-detection.js +175 -0
- package/bin/runners/lib/polish/performance-checks.js +100 -0
- package/bin/runners/lib/polish/security-checks.js +148 -0
- package/bin/runners/lib/polish/utils.js +203 -0
- package/bin/runners/lib/prompt-builder.js +540 -0
- package/bin/runners/lib/proof-certificate.js +634 -0
- package/bin/runners/lib/reality/accessibility-audit.js +946 -0
- package/bin/runners/lib/reality/api-contract-validator.js +1012 -0
- package/bin/runners/lib/reality/chaos-engineering.js +1084 -0
- package/bin/runners/lib/reality/performance-tracker.js +1077 -0
- package/bin/runners/lib/reality/scenario-generator.js +1404 -0
- package/bin/runners/lib/reality/visual-regression.js +852 -0
- package/bin/runners/lib/reality-profiler.js +717 -0
- package/bin/runners/lib/replay/flight-recorder-viewer.js +1160 -0
- package/bin/runners/lib/review/ai-code-review.js +832 -0
- package/bin/runners/lib/rules/custom-rule-engine.js +985 -0
- package/bin/runners/lib/sbom-generator.js +641 -0
- package/bin/runners/lib/scan-output-enhanced.js +512 -0
- package/bin/runners/lib/scan-output.js +65 -19
- package/bin/runners/lib/security/owasp-scanner.js +939 -0
- package/bin/runners/lib/ship-output.js +18 -25
- package/bin/runners/lib/terminal-ui.js +113 -1
- package/bin/runners/lib/unified-cli-output.js +603 -430
- package/bin/runners/lib/upsell.js +90 -338
- package/bin/runners/lib/validators/contract-validator.js +283 -0
- package/bin/runners/lib/validators/dead-export-detector.js +279 -0
- package/bin/runners/lib/validators/dep-audit.js +245 -0
- package/bin/runners/lib/validators/env-validator.js +319 -0
- package/bin/runners/lib/validators/index.js +120 -0
- package/bin/runners/lib/validators/license-checker.js +252 -0
- package/bin/runners/lib/validators/route-validator.js +290 -0
- package/bin/runners/runAIAgent.js +5 -10
- package/bin/runners/runAgent.js +3 -0
- package/bin/runners/runApprove.js +1233 -1200
- package/bin/runners/runAuth.js +22 -1
- package/bin/runners/runAuthority.js +528 -0
- package/bin/runners/runCheckpoint.js +4 -24
- package/bin/runners/runClassify.js +862 -859
- package/bin/runners/runConductor.js +772 -0
- package/bin/runners/runContainer.js +366 -0
- package/bin/runners/runContext.js +3 -0
- package/bin/runners/runDoctor.js +28 -41
- package/bin/runners/runEasy.js +410 -0
- package/bin/runners/runFirewall.js +3 -0
- package/bin/runners/runFirewallHook.js +3 -0
- package/bin/runners/runFix.js +76 -66
- package/bin/runners/runGuard.js +411 -18
- package/bin/runners/runIaC.js +372 -0
- package/bin/runners/runInit.js +10 -60
- package/bin/runners/runMcp.js +11 -12
- package/bin/runners/runPolish.js +240 -64
- package/bin/runners/runPromptFirewall.js +5 -12
- package/bin/runners/runProve.js +20 -55
- package/bin/runners/runReality.js +68 -59
- package/bin/runners/runReport.js +31 -5
- package/bin/runners/runRuntime.js +5 -8
- package/bin/runners/runScan.js +194 -1273
- package/bin/runners/runShip.js +695 -47
- package/bin/runners/runTruth.js +3 -0
- package/bin/runners/runValidate.js +7 -11
- package/bin/runners/runVibe.js +791 -0
- package/bin/runners/runWatch.js +14 -23
- package/bin/vibecheck.js +179 -65
- package/mcp-server/index.js +202 -636
- package/mcp-server/lib/api-client.cjs +7 -299
- package/mcp-server/package.json +1 -1
- package/mcp-server/tier-auth.js +175 -574
- package/mcp-server/tools-v3.js +800 -505
- package/mcp-server/tools.js +495 -0
- package/package.json +1 -1
- package/bin/runners/lib/engines/vibecheck-engines/lib/ast-cache.js +0 -164
- package/bin/runners/lib/engines/vibecheck-engines/lib/code-quality-engine.js +0 -291
- package/bin/runners/lib/engines/vibecheck-engines/lib/console-logs-engine.js +0 -83
- package/bin/runners/lib/engines/vibecheck-engines/lib/dead-code-engine.js +0 -198
- package/bin/runners/lib/engines/vibecheck-engines/lib/deprecated-api-engine.js +0 -275
- package/bin/runners/lib/engines/vibecheck-engines/lib/empty-catch-engine.js +0 -167
- package/bin/runners/lib/engines/vibecheck-engines/lib/file-filter.js +0 -217
- package/bin/runners/lib/engines/vibecheck-engines/lib/mock-data-engine.js +0 -140
- package/bin/runners/lib/engines/vibecheck-engines/lib/parallel-processor.js +0 -164
- package/bin/runners/lib/engines/vibecheck-engines/lib/performance-issues-engine.js +0 -234
- package/bin/runners/lib/engines/vibecheck-engines/lib/type-aware-engine.js +0 -217
- package/bin/runners/lib/engines/vibecheck-engines/lib/unsafe-regex-engine.js +0 -78
- package/mcp-server/index-v1.js +0 -698
|
@@ -0,0 +1,634 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Proof Certificate Generator
|
|
3
|
+
*
|
|
4
|
+
* Enterprise-grade proof certificates with:
|
|
5
|
+
* - Risk Radar visualization
|
|
6
|
+
* - Pre-flight checklist
|
|
7
|
+
* - Cryptographic verification
|
|
8
|
+
* - Audit trail
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
"use strict";
|
|
12
|
+
|
|
13
|
+
const crypto = require("crypto");
|
|
14
|
+
const path = require("path");
|
|
15
|
+
|
|
16
|
+
// Terminal UI
|
|
17
|
+
let terminalUI;
|
|
18
|
+
try {
|
|
19
|
+
terminalUI = require("./terminal-ui");
|
|
20
|
+
} catch {
|
|
21
|
+
terminalUI = {
|
|
22
|
+
c: { reset: "", bold: "", dim: "", red: "", yellow: "", green: "", cyan: "" },
|
|
23
|
+
rgb: () => "",
|
|
24
|
+
icons: { check: "✓", cross: "✗", warning: "⚠", info: "ℹ" },
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const { c, rgb, icons } = terminalUI;
|
|
29
|
+
|
|
30
|
+
// Colors
|
|
31
|
+
const colors = {
|
|
32
|
+
critical: rgb(255, 80, 80),
|
|
33
|
+
high: rgb(255, 150, 50),
|
|
34
|
+
medium: rgb(255, 200, 0),
|
|
35
|
+
low: rgb(100, 200, 255),
|
|
36
|
+
info: rgb(150, 150, 150),
|
|
37
|
+
success: rgb(0, 255, 150),
|
|
38
|
+
accent: rgb(0, 200, 255),
|
|
39
|
+
gold: rgb(255, 215, 0),
|
|
40
|
+
silver: rgb(192, 192, 192),
|
|
41
|
+
bronze: rgb(205, 127, 50),
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
// Risk categories for radar
|
|
45
|
+
const RISK_CATEGORIES = [
|
|
46
|
+
{ id: "security", label: "Security", icon: "🔒" },
|
|
47
|
+
{ id: "quality", label: "Code Quality", icon: "✨" },
|
|
48
|
+
{ id: "reliability", label: "Reliability", icon: "⚡" },
|
|
49
|
+
{ id: "maintainability", label: "Maintainability", icon: "🔧" },
|
|
50
|
+
{ id: "performance", label: "Performance", icon: "🚀" },
|
|
51
|
+
{ id: "compliance", label: "Compliance", icon: "📋" },
|
|
52
|
+
];
|
|
53
|
+
|
|
54
|
+
// Pre-flight checklist items
|
|
55
|
+
const PREFLIGHT_CHECKS = [
|
|
56
|
+
{ id: "no-critical", label: "No critical issues", category: "blocking", weight: 100 },
|
|
57
|
+
{ id: "no-secrets", label: "No hardcoded secrets", category: "security", weight: 90 },
|
|
58
|
+
{ id: "no-mock-data", label: "No mock/fake data in production paths", category: "quality", weight: 80 },
|
|
59
|
+
{ id: "error-handling", label: "Error handling in place", category: "reliability", weight: 70 },
|
|
60
|
+
{ id: "no-console", label: "No debug console statements", category: "quality", weight: 60 },
|
|
61
|
+
{ id: "type-safety", label: "Type safety enforced", category: "quality", weight: 50 },
|
|
62
|
+
{ id: "deps-secure", label: "Dependencies are secure", category: "security", weight: 85 },
|
|
63
|
+
{ id: "api-consistency", label: "API contracts consistent", category: "reliability", weight: 65 },
|
|
64
|
+
{ id: "auth-verified", label: "Authentication verified", category: "security", weight: 95 },
|
|
65
|
+
{ id: "perf-acceptable", label: "Performance acceptable", category: "performance", weight: 55 },
|
|
66
|
+
];
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Calculate risk scores for each category
|
|
70
|
+
*/
|
|
71
|
+
function calculateRiskRadar(findings) {
|
|
72
|
+
const radar = {};
|
|
73
|
+
|
|
74
|
+
for (const category of RISK_CATEGORIES) {
|
|
75
|
+
radar[category.id] = {
|
|
76
|
+
...category,
|
|
77
|
+
score: 100,
|
|
78
|
+
issues: 0,
|
|
79
|
+
critical: 0,
|
|
80
|
+
high: 0,
|
|
81
|
+
medium: 0,
|
|
82
|
+
low: 0,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Map findings to categories
|
|
87
|
+
const categoryMapping = {
|
|
88
|
+
"hardcoded-secrets": "security",
|
|
89
|
+
"security": "security",
|
|
90
|
+
"credentials": "security",
|
|
91
|
+
"authentication": "security",
|
|
92
|
+
"authorization": "security",
|
|
93
|
+
"injection": "security",
|
|
94
|
+
"xss": "security",
|
|
95
|
+
"csrf": "security",
|
|
96
|
+
"vulnerability": "security",
|
|
97
|
+
|
|
98
|
+
"console-logs": "quality",
|
|
99
|
+
"dead-code": "quality",
|
|
100
|
+
"unused": "quality",
|
|
101
|
+
"duplicate": "quality",
|
|
102
|
+
"complexity": "quality",
|
|
103
|
+
"code-smell": "quality",
|
|
104
|
+
"type-any": "quality",
|
|
105
|
+
"naming": "quality",
|
|
106
|
+
|
|
107
|
+
"error-handling": "reliability",
|
|
108
|
+
"empty-catch": "reliability",
|
|
109
|
+
"promise": "reliability",
|
|
110
|
+
"async": "reliability",
|
|
111
|
+
"null-check": "reliability",
|
|
112
|
+
"validation": "reliability",
|
|
113
|
+
|
|
114
|
+
"deprecated": "maintainability",
|
|
115
|
+
"legacy": "maintainability",
|
|
116
|
+
"documentation": "maintainability",
|
|
117
|
+
"test-coverage": "maintainability",
|
|
118
|
+
|
|
119
|
+
"performance": "performance",
|
|
120
|
+
"memory": "performance",
|
|
121
|
+
"n+1": "performance",
|
|
122
|
+
"bundle-size": "performance",
|
|
123
|
+
"lazy-load": "performance",
|
|
124
|
+
|
|
125
|
+
"mock-data": "compliance",
|
|
126
|
+
"fake": "compliance",
|
|
127
|
+
"stub": "compliance",
|
|
128
|
+
"license": "compliance",
|
|
129
|
+
"gdpr": "compliance",
|
|
130
|
+
"pii": "compliance",
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
// Score findings
|
|
134
|
+
for (const finding of findings) {
|
|
135
|
+
const category = finding.category?.toLowerCase() || "";
|
|
136
|
+
const type = finding.type?.toLowerCase() || "";
|
|
137
|
+
const severity = finding.severity?.toLowerCase() || finding.type?.toLowerCase() || "medium";
|
|
138
|
+
|
|
139
|
+
// Find matching risk category
|
|
140
|
+
let riskCategory = "quality"; // default
|
|
141
|
+
for (const [pattern, cat] of Object.entries(categoryMapping)) {
|
|
142
|
+
if (category.includes(pattern) || type.includes(pattern)) {
|
|
143
|
+
riskCategory = cat;
|
|
144
|
+
break;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Update scores
|
|
149
|
+
const risk = radar[riskCategory];
|
|
150
|
+
if (risk) {
|
|
151
|
+
risk.issues++;
|
|
152
|
+
|
|
153
|
+
switch (severity) {
|
|
154
|
+
case "critical":
|
|
155
|
+
risk.critical++;
|
|
156
|
+
risk.score -= 25;
|
|
157
|
+
break;
|
|
158
|
+
case "high":
|
|
159
|
+
risk.high++;
|
|
160
|
+
risk.score -= 15;
|
|
161
|
+
break;
|
|
162
|
+
case "warning":
|
|
163
|
+
case "medium":
|
|
164
|
+
risk.medium++;
|
|
165
|
+
risk.score -= 8;
|
|
166
|
+
break;
|
|
167
|
+
case "suggestion":
|
|
168
|
+
case "low":
|
|
169
|
+
case "info":
|
|
170
|
+
risk.low++;
|
|
171
|
+
risk.score -= 2;
|
|
172
|
+
break;
|
|
173
|
+
default:
|
|
174
|
+
risk.medium++;
|
|
175
|
+
risk.score -= 5;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
risk.score = Math.max(0, risk.score);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
return radar;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Render risk radar visualization
|
|
187
|
+
*/
|
|
188
|
+
function renderRiskRadar(radar) {
|
|
189
|
+
const lines = [];
|
|
190
|
+
|
|
191
|
+
lines.push(` ${c.dim}╭${"─".repeat(60)}╮${c.reset}`);
|
|
192
|
+
lines.push(` ${c.dim}│${c.reset} ${colors.accent}${c.bold}🎯 RISK RADAR${c.reset} ${c.dim}│${c.reset}`);
|
|
193
|
+
lines.push(` ${c.dim}├${"─".repeat(60)}┤${c.reset}`);
|
|
194
|
+
|
|
195
|
+
for (const category of RISK_CATEGORIES) {
|
|
196
|
+
const risk = radar[category.id];
|
|
197
|
+
const score = risk.score;
|
|
198
|
+
const barLength = Math.round(score / 100 * 30);
|
|
199
|
+
const emptyLength = 30 - barLength;
|
|
200
|
+
|
|
201
|
+
// Color based on score
|
|
202
|
+
let color;
|
|
203
|
+
if (score >= 80) color = colors.success;
|
|
204
|
+
else if (score >= 60) color = colors.medium;
|
|
205
|
+
else if (score >= 40) color = colors.high;
|
|
206
|
+
else color = colors.critical;
|
|
207
|
+
|
|
208
|
+
const bar = `${color}${"█".repeat(barLength)}${c.reset}${c.dim}${"░".repeat(emptyLength)}${c.reset}`;
|
|
209
|
+
const label = `${category.icon} ${category.label}`.padEnd(20);
|
|
210
|
+
const scoreStr = `${score}%`.padStart(4);
|
|
211
|
+
const issues = risk.issues > 0 ? `${c.dim}(${risk.issues} issues)${c.reset}` : "";
|
|
212
|
+
|
|
213
|
+
lines.push(` ${c.dim}│${c.reset} ${label} ${bar} ${color}${scoreStr}${c.reset} ${issues.padEnd(15)}${c.dim}│${c.reset}`);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// Overall score
|
|
217
|
+
const categories = Object.values(radar);
|
|
218
|
+
const overallScore = Math.round(categories.reduce((sum, c) => sum + c.score, 0) / categories.length);
|
|
219
|
+
let overallColor = colors.success;
|
|
220
|
+
if (overallScore < 80) overallColor = colors.medium;
|
|
221
|
+
if (overallScore < 60) overallColor = colors.high;
|
|
222
|
+
if (overallScore < 40) overallColor = colors.critical;
|
|
223
|
+
|
|
224
|
+
lines.push(` ${c.dim}├${"─".repeat(60)}┤${c.reset}`);
|
|
225
|
+
lines.push(` ${c.dim}│${c.reset} ${c.bold}Overall Risk Score:${c.reset} ${overallColor}${c.bold}${overallScore}%${c.reset} ${c.dim}│${c.reset}`);
|
|
226
|
+
lines.push(` ${c.dim}╰${"─".repeat(60)}╯${c.reset}`);
|
|
227
|
+
|
|
228
|
+
return lines.join("\n");
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Run pre-flight checklist
|
|
233
|
+
*/
|
|
234
|
+
function runPreflightChecklist(findings, proofGraph) {
|
|
235
|
+
const results = [];
|
|
236
|
+
const findingsLower = findings.map(f => ({
|
|
237
|
+
category: (f.category || "").toLowerCase(),
|
|
238
|
+
type: (f.type || f.severity || "").toLowerCase(),
|
|
239
|
+
severity: (f.severity || f.type || "").toLowerCase(),
|
|
240
|
+
}));
|
|
241
|
+
|
|
242
|
+
for (const check of PREFLIGHT_CHECKS) {
|
|
243
|
+
let passed = true;
|
|
244
|
+
let details = "";
|
|
245
|
+
|
|
246
|
+
switch (check.id) {
|
|
247
|
+
case "no-critical":
|
|
248
|
+
const criticals = findingsLower.filter(f => f.severity === "critical" || f.type === "critical");
|
|
249
|
+
passed = criticals.length === 0;
|
|
250
|
+
details = passed ? "All clear" : `${criticals.length} critical issue(s)`;
|
|
251
|
+
break;
|
|
252
|
+
|
|
253
|
+
case "no-secrets":
|
|
254
|
+
const secrets = findingsLower.filter(f =>
|
|
255
|
+
f.category.includes("secret") ||
|
|
256
|
+
f.category.includes("credential") ||
|
|
257
|
+
f.category.includes("password") ||
|
|
258
|
+
f.category.includes("api-key")
|
|
259
|
+
);
|
|
260
|
+
passed = secrets.length === 0;
|
|
261
|
+
details = passed ? "No secrets detected" : `${secrets.length} secret(s) found`;
|
|
262
|
+
break;
|
|
263
|
+
|
|
264
|
+
case "no-mock-data":
|
|
265
|
+
const mocks = findingsLower.filter(f =>
|
|
266
|
+
f.category.includes("mock") ||
|
|
267
|
+
f.category.includes("fake") ||
|
|
268
|
+
f.category.includes("stub") ||
|
|
269
|
+
f.category.includes("test-data")
|
|
270
|
+
);
|
|
271
|
+
passed = mocks.length === 0;
|
|
272
|
+
details = passed ? "No mock data" : `${mocks.length} mock data instance(s)`;
|
|
273
|
+
break;
|
|
274
|
+
|
|
275
|
+
case "error-handling":
|
|
276
|
+
const errorIssues = findingsLower.filter(f =>
|
|
277
|
+
f.category.includes("error") ||
|
|
278
|
+
f.category.includes("catch") ||
|
|
279
|
+
f.category.includes("exception")
|
|
280
|
+
);
|
|
281
|
+
passed = errorIssues.length === 0;
|
|
282
|
+
details = passed ? "Error handling OK" : `${errorIssues.length} error handling issue(s)`;
|
|
283
|
+
break;
|
|
284
|
+
|
|
285
|
+
case "no-console":
|
|
286
|
+
const consoles = findingsLower.filter(f =>
|
|
287
|
+
f.category.includes("console")
|
|
288
|
+
);
|
|
289
|
+
passed = consoles.length === 0;
|
|
290
|
+
details = passed ? "No console statements" : `${consoles.length} console statement(s)`;
|
|
291
|
+
break;
|
|
292
|
+
|
|
293
|
+
case "type-safety":
|
|
294
|
+
const typeIssues = findingsLower.filter(f =>
|
|
295
|
+
f.category.includes("type") ||
|
|
296
|
+
f.category.includes("any")
|
|
297
|
+
);
|
|
298
|
+
passed = typeIssues.length <= 2; // Allow some flexibility
|
|
299
|
+
details = passed ? "Types OK" : `${typeIssues.length} type issue(s)`;
|
|
300
|
+
break;
|
|
301
|
+
|
|
302
|
+
case "deps-secure":
|
|
303
|
+
const vulns = findingsLower.filter(f =>
|
|
304
|
+
f.category.includes("vulnerability") ||
|
|
305
|
+
f.category.includes("cve") ||
|
|
306
|
+
f.category.includes("security") && f.category.includes("dep")
|
|
307
|
+
);
|
|
308
|
+
passed = vulns.length === 0;
|
|
309
|
+
details = passed ? "Dependencies secure" : `${vulns.length} vulnerability(ies)`;
|
|
310
|
+
break;
|
|
311
|
+
|
|
312
|
+
case "api-consistency":
|
|
313
|
+
const apiIssues = findingsLower.filter(f =>
|
|
314
|
+
f.category.includes("api") && (
|
|
315
|
+
f.category.includes("inconsistent") ||
|
|
316
|
+
f.category.includes("mismatch")
|
|
317
|
+
)
|
|
318
|
+
);
|
|
319
|
+
passed = apiIssues.length === 0;
|
|
320
|
+
details = passed ? "API contracts OK" : `${apiIssues.length} API issue(s)`;
|
|
321
|
+
break;
|
|
322
|
+
|
|
323
|
+
case "auth-verified":
|
|
324
|
+
const authIssues = findingsLower.filter(f =>
|
|
325
|
+
f.category.includes("auth") && f.severity === "critical"
|
|
326
|
+
);
|
|
327
|
+
passed = authIssues.length === 0;
|
|
328
|
+
details = passed ? "Auth verified" : `${authIssues.length} auth issue(s)`;
|
|
329
|
+
break;
|
|
330
|
+
|
|
331
|
+
case "perf-acceptable":
|
|
332
|
+
const perfIssues = findingsLower.filter(f =>
|
|
333
|
+
f.category.includes("performance") &&
|
|
334
|
+
(f.severity === "critical" || f.severity === "high")
|
|
335
|
+
);
|
|
336
|
+
passed = perfIssues.length === 0;
|
|
337
|
+
details = passed ? "Performance OK" : `${perfIssues.length} perf issue(s)`;
|
|
338
|
+
break;
|
|
339
|
+
|
|
340
|
+
default:
|
|
341
|
+
passed = true;
|
|
342
|
+
details = "Check not implemented";
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
results.push({
|
|
346
|
+
...check,
|
|
347
|
+
passed,
|
|
348
|
+
details,
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
return results;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
/**
|
|
356
|
+
* Render pre-flight checklist
|
|
357
|
+
*/
|
|
358
|
+
function renderPreflightChecklist(checks) {
|
|
359
|
+
const lines = [];
|
|
360
|
+
|
|
361
|
+
lines.push(` ${c.dim}╭${"─".repeat(60)}╮${c.reset}`);
|
|
362
|
+
lines.push(` ${c.dim}│${c.reset} ${colors.accent}${c.bold}✈️ PRE-FLIGHT CHECKLIST${c.reset} ${c.dim}│${c.reset}`);
|
|
363
|
+
lines.push(` ${c.dim}├${"─".repeat(60)}┤${c.reset}`);
|
|
364
|
+
|
|
365
|
+
const passed = checks.filter(c => c.passed).length;
|
|
366
|
+
const total = checks.length;
|
|
367
|
+
const passRate = Math.round(passed / total * 100);
|
|
368
|
+
|
|
369
|
+
for (const check of checks) {
|
|
370
|
+
const icon = check.passed ? `${colors.success}✓${c.reset}` : `${colors.critical}✗${c.reset}`;
|
|
371
|
+
const label = check.label.padEnd(35);
|
|
372
|
+
const details = check.details.padEnd(15);
|
|
373
|
+
const status = check.passed ? `${colors.success}PASS${c.reset}` : `${colors.critical}FAIL${c.reset}`;
|
|
374
|
+
|
|
375
|
+
lines.push(` ${c.dim}│${c.reset} ${icon} ${label} ${c.dim}${details}${c.reset} ${status} ${c.dim}│${c.reset}`);
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
lines.push(` ${c.dim}├${"─".repeat(60)}┤${c.reset}`);
|
|
379
|
+
|
|
380
|
+
const passColor = passRate >= 80 ? colors.success : passRate >= 60 ? colors.medium : colors.critical;
|
|
381
|
+
lines.push(` ${c.dim}│${c.reset} ${c.bold}Pre-flight Status:${c.reset} ${passed}/${total} checks passed ${passColor}(${passRate}%)${c.reset} ${c.dim}│${c.reset}`);
|
|
382
|
+
|
|
383
|
+
const canShip = checks.filter(c => c.category === "blocking" && !c.passed).length === 0;
|
|
384
|
+
const shipStatus = canShip
|
|
385
|
+
? `${colors.success}${c.bold}CLEARED FOR TAKEOFF${c.reset}`
|
|
386
|
+
: `${colors.critical}${c.bold}GROUNDED - BLOCKING ISSUES${c.reset}`;
|
|
387
|
+
|
|
388
|
+
lines.push(` ${c.dim}│${c.reset} ${shipStatus} ${c.dim}│${c.reset}`);
|
|
389
|
+
lines.push(` ${c.dim}╰${"─".repeat(60)}╯${c.reset}`);
|
|
390
|
+
|
|
391
|
+
return lines.join("\n");
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
/**
|
|
395
|
+
* Generate a cryptographic proof certificate
|
|
396
|
+
*/
|
|
397
|
+
function generateProofCertificate(options) {
|
|
398
|
+
const {
|
|
399
|
+
projectPath,
|
|
400
|
+
projectName,
|
|
401
|
+
verdict,
|
|
402
|
+
score,
|
|
403
|
+
findings,
|
|
404
|
+
truthpack,
|
|
405
|
+
proofGraph,
|
|
406
|
+
duration,
|
|
407
|
+
tier,
|
|
408
|
+
version,
|
|
409
|
+
} = options;
|
|
410
|
+
|
|
411
|
+
const timestamp = new Date().toISOString();
|
|
412
|
+
const certificateId = generateCertificateId();
|
|
413
|
+
const shortCode = generateShortCode(certificateId);
|
|
414
|
+
|
|
415
|
+
// Calculate checksums
|
|
416
|
+
const findingsHash = hashObject(findings);
|
|
417
|
+
const truthpackHash = truthpack ? hashObject(truthpack) : null;
|
|
418
|
+
|
|
419
|
+
// Build certificate
|
|
420
|
+
const certificate = {
|
|
421
|
+
certificateId,
|
|
422
|
+
shortCode,
|
|
423
|
+
version: "2.0.0",
|
|
424
|
+
generator: `vibecheck-cli@${version}`,
|
|
425
|
+
timestamp,
|
|
426
|
+
expires: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000).toISOString(), // 7 days
|
|
427
|
+
|
|
428
|
+
project: {
|
|
429
|
+
name: projectName,
|
|
430
|
+
path: projectPath,
|
|
431
|
+
scannedAt: timestamp,
|
|
432
|
+
},
|
|
433
|
+
|
|
434
|
+
verdict: {
|
|
435
|
+
status: verdict,
|
|
436
|
+
score,
|
|
437
|
+
confidence: calculateConfidence(findings, proofGraph),
|
|
438
|
+
tier,
|
|
439
|
+
},
|
|
440
|
+
|
|
441
|
+
summary: {
|
|
442
|
+
totalFindings: findings.length,
|
|
443
|
+
critical: findings.filter(f => f.severity === "critical" || f.type === "critical").length,
|
|
444
|
+
high: findings.filter(f => f.severity === "high" || f.type === "high").length,
|
|
445
|
+
medium: findings.filter(f => f.severity === "warning" || f.type === "warning" || f.severity === "medium").length,
|
|
446
|
+
low: findings.filter(f => f.severity === "suggestion" || f.type === "suggestion" || f.severity === "low").length,
|
|
447
|
+
},
|
|
448
|
+
|
|
449
|
+
riskRadar: calculateRiskRadar(findings),
|
|
450
|
+
preflight: runPreflightChecklist(findings, proofGraph),
|
|
451
|
+
|
|
452
|
+
integrity: {
|
|
453
|
+
findingsHash,
|
|
454
|
+
truthpackHash,
|
|
455
|
+
certificateHash: null, // Set after signing
|
|
456
|
+
},
|
|
457
|
+
|
|
458
|
+
metadata: {
|
|
459
|
+
duration,
|
|
460
|
+
engineVersion: version,
|
|
461
|
+
nodeVersion: process.version,
|
|
462
|
+
platform: process.platform,
|
|
463
|
+
},
|
|
464
|
+
|
|
465
|
+
verificationUrl: `https://verify.vibecheckai.dev/cert/${shortCode}`,
|
|
466
|
+
};
|
|
467
|
+
|
|
468
|
+
// Sign the certificate
|
|
469
|
+
certificate.integrity.certificateHash = hashObject({
|
|
470
|
+
certificateId,
|
|
471
|
+
timestamp,
|
|
472
|
+
verdict: certificate.verdict,
|
|
473
|
+
summary: certificate.summary,
|
|
474
|
+
findingsHash,
|
|
475
|
+
});
|
|
476
|
+
|
|
477
|
+
return {
|
|
478
|
+
certificate,
|
|
479
|
+
shortCode,
|
|
480
|
+
qrCode: generateQRCodeData(certificate.verificationUrl),
|
|
481
|
+
};
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
/**
|
|
485
|
+
* Generate unique certificate ID
|
|
486
|
+
*/
|
|
487
|
+
function generateCertificateId() {
|
|
488
|
+
const timestamp = Date.now().toString(36);
|
|
489
|
+
const random = crypto.randomBytes(8).toString("hex");
|
|
490
|
+
return `VC-${timestamp}-${random}`.toUpperCase();
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
/**
|
|
494
|
+
* Generate short verification code
|
|
495
|
+
*/
|
|
496
|
+
function generateShortCode(certificateId) {
|
|
497
|
+
const hash = crypto.createHash("sha256").update(certificateId).digest("hex");
|
|
498
|
+
return hash.substring(0, 8).toUpperCase();
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
/**
|
|
502
|
+
* Calculate confidence score
|
|
503
|
+
*/
|
|
504
|
+
function calculateConfidence(findings, proofGraph) {
|
|
505
|
+
let confidence = 100;
|
|
506
|
+
|
|
507
|
+
// Reduce confidence based on findings
|
|
508
|
+
const critical = findings.filter(f => f.severity === "critical" || f.type === "critical").length;
|
|
509
|
+
const high = findings.filter(f => f.severity === "high" || f.type === "high").length;
|
|
510
|
+
|
|
511
|
+
confidence -= critical * 15;
|
|
512
|
+
confidence -= high * 8;
|
|
513
|
+
|
|
514
|
+
// Boost confidence if proof graph has verified nodes
|
|
515
|
+
if (proofGraph?.nodes?.length > 0) {
|
|
516
|
+
const verifiedNodes = proofGraph.nodes.filter(n => n.verified).length;
|
|
517
|
+
const totalNodes = proofGraph.nodes.length;
|
|
518
|
+
confidence += Math.round((verifiedNodes / totalNodes) * 10);
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
return Math.max(0, Math.min(100, confidence));
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
/**
|
|
525
|
+
* Hash an object deterministically
|
|
526
|
+
*/
|
|
527
|
+
function hashObject(obj) {
|
|
528
|
+
const str = JSON.stringify(obj, Object.keys(obj).sort());
|
|
529
|
+
return crypto.createHash("sha256").update(str).digest("hex").substring(0, 16);
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
/**
|
|
533
|
+
* Generate QR code data URL (placeholder - would use actual QR library)
|
|
534
|
+
*/
|
|
535
|
+
function generateQRCodeData(url) {
|
|
536
|
+
// In production, this would generate an actual QR code
|
|
537
|
+
return `data:image/svg+xml,${encodeURIComponent(`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><text x="10" y="50" font-size="8">${url}</text></svg>`)}`;
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
/**
|
|
541
|
+
* Render certificate badge for terminal
|
|
542
|
+
*/
|
|
543
|
+
function renderCertificateBadge(certificate) {
|
|
544
|
+
const lines = [];
|
|
545
|
+
const { verdict, score, confidence } = certificate.verdict;
|
|
546
|
+
|
|
547
|
+
// Badge colors
|
|
548
|
+
let badgeColor, badgeIcon, badgeLabel;
|
|
549
|
+
switch (verdict) {
|
|
550
|
+
case "SHIP":
|
|
551
|
+
badgeColor = colors.success;
|
|
552
|
+
badgeIcon = "🚀";
|
|
553
|
+
badgeLabel = "SHIP CERTIFIED";
|
|
554
|
+
break;
|
|
555
|
+
case "WARN":
|
|
556
|
+
badgeColor = colors.medium;
|
|
557
|
+
badgeIcon = "⚠️";
|
|
558
|
+
badgeLabel = "CONDITIONAL";
|
|
559
|
+
break;
|
|
560
|
+
case "BLOCK":
|
|
561
|
+
badgeColor = colors.critical;
|
|
562
|
+
badgeIcon = "🛑";
|
|
563
|
+
badgeLabel = "BLOCKED";
|
|
564
|
+
break;
|
|
565
|
+
default:
|
|
566
|
+
badgeColor = colors.info;
|
|
567
|
+
badgeIcon = "❓";
|
|
568
|
+
badgeLabel = "UNKNOWN";
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
lines.push("");
|
|
572
|
+
lines.push(` ${badgeColor}╭${"═".repeat(40)}╮${c.reset}`);
|
|
573
|
+
lines.push(` ${badgeColor}║${c.reset} ${badgeColor}║${c.reset}`);
|
|
574
|
+
lines.push(` ${badgeColor}║${c.reset} ${badgeIcon} ${c.bold}${badgeColor}${badgeLabel}${c.reset} ${badgeColor}║${c.reset}`);
|
|
575
|
+
lines.push(` ${badgeColor}║${c.reset} ${badgeColor}║${c.reset}`);
|
|
576
|
+
lines.push(` ${badgeColor}║${c.reset} Score: ${c.bold}${score}/100${c.reset} Confidence: ${c.bold}${confidence}%${c.reset} ${badgeColor}║${c.reset}`);
|
|
577
|
+
lines.push(` ${badgeColor}║${c.reset} ${badgeColor}║${c.reset}`);
|
|
578
|
+
lines.push(` ${badgeColor}║${c.reset} ${c.dim}ID: ${certificate.certificateId}${c.reset} ${badgeColor}║${c.reset}`);
|
|
579
|
+
lines.push(` ${badgeColor}║${c.reset} ${c.dim}Verify: ${certificate.shortCode}${c.reset} ${badgeColor}║${c.reset}`);
|
|
580
|
+
lines.push(` ${badgeColor}║${c.reset} ${badgeColor}║${c.reset}`);
|
|
581
|
+
lines.push(` ${badgeColor}╰${"═".repeat(40)}╯${c.reset}`);
|
|
582
|
+
lines.push("");
|
|
583
|
+
|
|
584
|
+
return lines.join("\n");
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
/**
|
|
588
|
+
* Export certificate as Markdown
|
|
589
|
+
*/
|
|
590
|
+
function exportCertificateMarkdown(certificate) {
|
|
591
|
+
const { verdict, score, confidence } = certificate.verdict;
|
|
592
|
+
const { summary, project } = certificate;
|
|
593
|
+
|
|
594
|
+
return `# VibeCheck Proof Certificate
|
|
595
|
+
|
|
596
|
+
## Project: ${project.name}
|
|
597
|
+
|
|
598
|
+
| Metric | Value |
|
|
599
|
+
|--------|-------|
|
|
600
|
+
| Verdict | **${verdict}** |
|
|
601
|
+
| Score | ${score}/100 |
|
|
602
|
+
| Confidence | ${confidence}% |
|
|
603
|
+
| Certificate ID | \`${certificate.certificateId}\` |
|
|
604
|
+
| Short Code | \`${certificate.shortCode}\` |
|
|
605
|
+
| Generated | ${certificate.timestamp} |
|
|
606
|
+
| Expires | ${certificate.expires} |
|
|
607
|
+
|
|
608
|
+
## Summary
|
|
609
|
+
|
|
610
|
+
- Critical Issues: ${summary.critical}
|
|
611
|
+
- High Issues: ${summary.high}
|
|
612
|
+
- Medium Issues: ${summary.medium}
|
|
613
|
+
- Low Issues: ${summary.low}
|
|
614
|
+
|
|
615
|
+
## Verification
|
|
616
|
+
|
|
617
|
+
Verify this certificate at: ${certificate.verificationUrl}
|
|
618
|
+
|
|
619
|
+
---
|
|
620
|
+
*Generated by VibeCheck v${certificate.metadata.engineVersion}*
|
|
621
|
+
`;
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
module.exports = {
|
|
625
|
+
calculateRiskRadar,
|
|
626
|
+
renderRiskRadar,
|
|
627
|
+
runPreflightChecklist,
|
|
628
|
+
renderPreflightChecklist,
|
|
629
|
+
generateProofCertificate,
|
|
630
|
+
renderCertificateBadge,
|
|
631
|
+
exportCertificateMarkdown,
|
|
632
|
+
RISK_CATEGORIES,
|
|
633
|
+
PREFLIGHT_CHECKS,
|
|
634
|
+
};
|