codeprobe-scanner 1.0.3 → 1.0.5
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/package.json +2 -2
- package/.claude/settings.local.json +0 -19
- package/.dockerignore +0 -17
- package/.env.development +0 -8
- package/.env.setup +0 -214
- package/.github/workflows/codeprobe-scan.yml +0 -137
- package/.github/workflows/codeprobe.yml +0 -84
- package/.github/workflows/scan-schedule.yml +0 -28
- package/ANALYSIS_SUMMARY.md +0 -365
- package/API_INTEGRATIONS.md +0 -469
- package/BUILD_PLAYBOOK.md +0 -349
- package/CLAUDE.md +0 -106
- package/DEPLOY.md +0 -452
- package/DEPLOYMENT_STATUS.md +0 -240
- package/DEPLOY_CHECKLIST.md +0 -316
- package/Dockerfile +0 -24
- package/EXECUTION_PLAN.html +0 -1086
- package/IMPLEMENTATION_COMPLETE.md +0 -288
- package/IMPLEMENTATION_SUMMARY.md +0 -443
- package/INTERACTIVE_FIX_FLOW.md +0 -308
- package/MIGRATION_COMPLETE.md +0 -327
- package/ORCHESTRATOR_SYNTHESIS.json +0 -80
- package/PENDING_WORK.md +0 -308
- package/PREFLIGHT_PLAN.md +0 -182
- package/QUICKSTART.md +0 -305
- package/STAGE_1_SETUP_ENGINE.md +0 -245
- package/STAGE_2_ARCHITECTURE.md +0 -714
- package/STAGE_2_CLI_VERIFICATION.md +0 -269
- package/STAGE_2_COMPLETE.md +0 -332
- package/STAGE_2_IMPLEMENTATION_PLAN.md +0 -679
- package/STAGE_3_COMPLETE.md +0 -246
- package/STAGE_3_DASHBOARD_POLISH.md +0 -371
- package/STAGE_3_SETUP.md +0 -155
- package/VIDEODB_INTEGRATION.md +0 -237
- package/archived/DASHBOARD_UI_WALKTHROUGH.md +0 -392
- package/archived/FRONTEND_SETUP.md +0 -236
- package/archived/auth.ts +0 -40
- package/archived/dashboard/components/BusinessImpactCard.tsx +0 -48
- package/archived/dashboard/components/CVETable.tsx +0 -104
- package/archived/dashboard/components/ErrorBoundary.tsx +0 -48
- package/archived/dashboard/components/PatchDiffViewer.tsx +0 -43
- package/archived/dashboard/components/RiskGauge.tsx +0 -64
- package/archived/dashboard/frontend.tsx +0 -104
- package/archived/dashboard/hooks/useAuth.ts +0 -32
- package/archived/dashboard/hooks/useScan.ts +0 -65
- package/archived/dashboard/index.html +0 -15
- package/archived/dashboard/pages/LoginPage.tsx +0 -28
- package/archived/dashboard/pages/ScanDetailPage.tsx +0 -143
- package/archived/dashboard/pages/ScansListPage.tsx +0 -160
- package/bun.lock +0 -603
- package/codeprobe-prd.md +0 -674
- package/cve-cache.json +0 -25
- package/demo-vulnerable-app/.github/workflows/codeprobe.yml +0 -32
- package/demo-vulnerable-app/README.md +0 -70
- package/demo-vulnerable-app/package-lock.json +0 -27
- package/demo-vulnerable-app/package.json +0 -15
- package/demo-vulnerable-app/server.js +0 -34
- package/demo.sh +0 -45
- package/index.ts +0 -19
- package/patches.json +0 -12
- package/serve-dashboard.ts +0 -23
- package/src/cli/index.ts +0 -137
- package/src/engine/index.ts +0 -90
- package/src/test/cli.test.ts +0 -211
- package/src/test/dashboard.test.ts +0 -38
- package/src/test/demo-scan.json +0 -32
- package/src/test/engine.test.ts +0 -157
- package/tailwind.config.js +0 -11
- package/tsconfig.json +0 -30
- package/verify-dashboard.ts +0 -87
- package/verify-env.sh +0 -98
- /package/bin/{codeprobe.js → codeprobe.cjs} +0 -0
|
@@ -1,143 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import { useScan } from "../hooks/useScan.ts";
|
|
3
|
-
import { RiskGauge } from "../components/RiskGauge.tsx";
|
|
4
|
-
import { CVETable } from "../components/CVETable.tsx";
|
|
5
|
-
import { PatchDiffViewer } from "../components/PatchDiffViewer.tsx";
|
|
6
|
-
import { BusinessImpactCard } from "../components/BusinessImpactCard.tsx";
|
|
7
|
-
|
|
8
|
-
interface ScanDetailPageProps {
|
|
9
|
-
scanId: string;
|
|
10
|
-
token: string | null;
|
|
11
|
-
onBack: () => void;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export function ScanDetailPage({ scanId, token, onBack }: ScanDetailPageProps) {
|
|
15
|
-
const { scan, loading, error } = useScan(scanId, token);
|
|
16
|
-
|
|
17
|
-
if (error) {
|
|
18
|
-
return (
|
|
19
|
-
<div className="space-y-4">
|
|
20
|
-
<button onClick={onBack} className="text-blue-400 hover:text-blue-300">
|
|
21
|
-
← Back
|
|
22
|
-
</button>
|
|
23
|
-
<div className="bg-red-900 border border-red-600 rounded p-4 text-white">
|
|
24
|
-
Failed to load scan. Try refreshing.
|
|
25
|
-
</div>
|
|
26
|
-
</div>
|
|
27
|
-
);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
if (loading) {
|
|
31
|
-
return (
|
|
32
|
-
<div className="space-y-4">
|
|
33
|
-
<button onClick={onBack} className="text-blue-400 hover:text-blue-300">
|
|
34
|
-
← Back
|
|
35
|
-
</button>
|
|
36
|
-
<p className="text-gray-400">Loading scan details...</p>
|
|
37
|
-
</div>
|
|
38
|
-
);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
if (!scan) {
|
|
42
|
-
return (
|
|
43
|
-
<div className="space-y-4">
|
|
44
|
-
<button onClick={onBack} className="text-blue-400 hover:text-blue-300">
|
|
45
|
-
← Back
|
|
46
|
-
</button>
|
|
47
|
-
<div className="text-center py-8 text-gray-400">
|
|
48
|
-
Scan not found. It may have been deleted.
|
|
49
|
-
</div>
|
|
50
|
-
</div>
|
|
51
|
-
);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
const copyUrl = () => {
|
|
55
|
-
const url = `${window.location.origin}?scan=${scanId}`;
|
|
56
|
-
navigator.clipboard.writeText(url);
|
|
57
|
-
alert("Scan URL copied!");
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
const exportJson = () => {
|
|
61
|
-
const element = document.createElement("a");
|
|
62
|
-
element.setAttribute("href", "data:text/plain;charset=utf-8," + encodeURIComponent(JSON.stringify(scan, null, 2)));
|
|
63
|
-
element.setAttribute("download", `${scanId}.json`);
|
|
64
|
-
element.style.display = "none";
|
|
65
|
-
document.body.appendChild(element);
|
|
66
|
-
element.click();
|
|
67
|
-
document.body.removeChild(element);
|
|
68
|
-
};
|
|
69
|
-
|
|
70
|
-
return (
|
|
71
|
-
<div className="space-y-8">
|
|
72
|
-
<button onClick={onBack} className="text-blue-400 hover:text-blue-300 text-sm font-semibold">
|
|
73
|
-
← Back to Scans
|
|
74
|
-
</button>
|
|
75
|
-
|
|
76
|
-
<div className="space-y-4">
|
|
77
|
-
<h2 className="text-2xl font-bold">{scan.repo}</h2>
|
|
78
|
-
<p className="text-gray-400 text-sm">
|
|
79
|
-
Scan ID: <code className="bg-gray-800 px-2 py-1 rounded">{scan.id}</code>
|
|
80
|
-
</p>
|
|
81
|
-
<p className="text-gray-400 text-sm">
|
|
82
|
-
Timestamp: {new Date(scan.timestamp * 1000).toLocaleString()}
|
|
83
|
-
</p>
|
|
84
|
-
</div>
|
|
85
|
-
|
|
86
|
-
<div className="bg-gray-800 rounded-lg p-6">
|
|
87
|
-
<RiskGauge score={scan.riskScore || 0} />
|
|
88
|
-
</div>
|
|
89
|
-
|
|
90
|
-
{scan.cves && scan.cves.length > 0 && (
|
|
91
|
-
<BusinessImpactCard riskScore={scan.riskScore} cveCount={scan.cves.length} />
|
|
92
|
-
)}
|
|
93
|
-
|
|
94
|
-
<div className="grid grid-cols-3 gap-4">
|
|
95
|
-
<div className="bg-gray-800 rounded p-4">
|
|
96
|
-
<p className="text-gray-400 text-xs font-semibold mb-1">Confirmed Exploitable</p>
|
|
97
|
-
<p className="text-2xl font-bold text-red-400">
|
|
98
|
-
{scan.cves?.filter((c: any) => c.status.includes("Confirmed")).length || 0}
|
|
99
|
-
</p>
|
|
100
|
-
</div>
|
|
101
|
-
<div className="bg-gray-800 rounded p-4">
|
|
102
|
-
<p className="text-gray-400 text-xs font-semibold mb-1">Theoretical Risk</p>
|
|
103
|
-
<p className="text-2xl font-bold text-yellow-400">
|
|
104
|
-
{scan.cves?.filter((c: any) => c.status.includes("Theoretical")).length || 0}
|
|
105
|
-
</p>
|
|
106
|
-
</div>
|
|
107
|
-
<div className="bg-gray-800 rounded p-4">
|
|
108
|
-
<p className="text-gray-400 text-xs font-semibold mb-1">Supply Chain Warnings</p>
|
|
109
|
-
<p className="text-2xl font-bold text-orange-400">{scan.supplyChainWarnings || 0}</p>
|
|
110
|
-
</div>
|
|
111
|
-
</div>
|
|
112
|
-
|
|
113
|
-
{scan.cves && scan.cves.length > 0 && (
|
|
114
|
-
<div className="bg-gray-800 rounded-lg p-6">
|
|
115
|
-
<h3 className="text-xl font-bold mb-4">Vulnerabilities</h3>
|
|
116
|
-
<CVETable cves={scan.cves} />
|
|
117
|
-
</div>
|
|
118
|
-
)}
|
|
119
|
-
|
|
120
|
-
{scan.cves?.[0]?.patch && (
|
|
121
|
-
<div className="bg-gray-800 rounded-lg p-6">
|
|
122
|
-
<h3 className="text-xl font-bold mb-4">Patch Diff</h3>
|
|
123
|
-
<PatchDiffViewer diff={scan.cves[0].patch} />
|
|
124
|
-
</div>
|
|
125
|
-
)}
|
|
126
|
-
|
|
127
|
-
<div className="flex gap-2 flex-wrap">
|
|
128
|
-
<button
|
|
129
|
-
onClick={copyUrl}
|
|
130
|
-
className="px-4 py-2 bg-blue-600 hover:bg-blue-700 rounded font-semibold text-sm transition"
|
|
131
|
-
>
|
|
132
|
-
Copy Scan URL
|
|
133
|
-
</button>
|
|
134
|
-
<button
|
|
135
|
-
onClick={exportJson}
|
|
136
|
-
className="px-4 py-2 bg-gray-700 hover:bg-gray-600 rounded font-semibold text-sm transition"
|
|
137
|
-
>
|
|
138
|
-
Export as JSON
|
|
139
|
-
</button>
|
|
140
|
-
</div>
|
|
141
|
-
</div>
|
|
142
|
-
);
|
|
143
|
-
}
|
|
@@ -1,160 +0,0 @@
|
|
|
1
|
-
import React, { useState } from "react";
|
|
2
|
-
import { useScans } from "../hooks/useScan.ts";
|
|
3
|
-
|
|
4
|
-
interface ScansListPageProps {
|
|
5
|
-
token: string | null;
|
|
6
|
-
onSelectScan: (scanId: string) => void;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export function ScansListPage({ token, onSelectScan }: ScansListPageProps) {
|
|
10
|
-
const { scans, loading, error } = useScans(token);
|
|
11
|
-
const [page, setPage] = useState(1);
|
|
12
|
-
const [filter, setFilter] = useState<string | null>(null);
|
|
13
|
-
|
|
14
|
-
const itemsPerPage = 10;
|
|
15
|
-
const filtered = filter
|
|
16
|
-
? scans.filter((s) => {
|
|
17
|
-
const risk = s.riskScore || 0;
|
|
18
|
-
if (filter === "CRITICAL") return risk >= 8;
|
|
19
|
-
if (filter === "HIGH") return risk >= 6 && risk < 8;
|
|
20
|
-
if (filter === "MEDIUM") return risk >= 4 && risk < 6;
|
|
21
|
-
return risk < 4;
|
|
22
|
-
})
|
|
23
|
-
: scans;
|
|
24
|
-
|
|
25
|
-
const paginated = filtered.slice((page - 1) * itemsPerPage, page * itemsPerPage);
|
|
26
|
-
const maxPages = Math.ceil(filtered.length / itemsPerPage);
|
|
27
|
-
|
|
28
|
-
if (error) {
|
|
29
|
-
return (
|
|
30
|
-
<div className="bg-red-900 border border-red-600 rounded p-4 text-white">
|
|
31
|
-
Failed to load scans. Try refreshing.
|
|
32
|
-
</div>
|
|
33
|
-
);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
if (filtered.length === 0 && !loading) {
|
|
37
|
-
return (
|
|
38
|
-
<div className="text-center py-12">
|
|
39
|
-
<p className="text-gray-400 mb-4">No scans yet.</p>
|
|
40
|
-
<p className="text-gray-500 text-sm">
|
|
41
|
-
Run <code className="bg-gray-800 px-2 py-1 rounded">codeprobe scan</code> from CLI
|
|
42
|
-
</p>
|
|
43
|
-
</div>
|
|
44
|
-
);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
return (
|
|
48
|
-
<div className="space-y-6">
|
|
49
|
-
<div className="flex gap-2 flex-wrap">
|
|
50
|
-
<button
|
|
51
|
-
onClick={() => {
|
|
52
|
-
setFilter(null);
|
|
53
|
-
setPage(1);
|
|
54
|
-
}}
|
|
55
|
-
className={`px-4 py-2 rounded text-sm font-semibold transition ${
|
|
56
|
-
filter === null
|
|
57
|
-
? "bg-blue-600 text-white"
|
|
58
|
-
: "bg-gray-700 text-gray-300 hover:bg-gray-600"
|
|
59
|
-
}`}
|
|
60
|
-
>
|
|
61
|
-
All
|
|
62
|
-
</button>
|
|
63
|
-
{["CRITICAL", "HIGH", "MEDIUM", "LOW"].map((level) => (
|
|
64
|
-
<button
|
|
65
|
-
key={level}
|
|
66
|
-
onClick={() => {
|
|
67
|
-
setFilter(level);
|
|
68
|
-
setPage(1);
|
|
69
|
-
}}
|
|
70
|
-
className={`px-4 py-2 rounded text-sm font-semibold transition ${
|
|
71
|
-
filter === level
|
|
72
|
-
? "bg-blue-600 text-white"
|
|
73
|
-
: "bg-gray-700 text-gray-300 hover:bg-gray-600"
|
|
74
|
-
}`}
|
|
75
|
-
>
|
|
76
|
-
{level}
|
|
77
|
-
</button>
|
|
78
|
-
))}
|
|
79
|
-
</div>
|
|
80
|
-
|
|
81
|
-
{loading && <p className="text-gray-400">Loading scans...</p>}
|
|
82
|
-
|
|
83
|
-
{!loading && (
|
|
84
|
-
<>
|
|
85
|
-
<div className="overflow-x-auto">
|
|
86
|
-
<table className="w-full text-sm">
|
|
87
|
-
<thead>
|
|
88
|
-
<tr className="border-b border-gray-700">
|
|
89
|
-
<th className="text-left py-3 px-4 font-semibold text-gray-300">Scan ID</th>
|
|
90
|
-
<th className="text-left py-3 px-4 font-semibold text-gray-300">Repo</th>
|
|
91
|
-
<th className="text-left py-3 px-4 font-semibold text-gray-300">Risk</th>
|
|
92
|
-
<th className="text-left py-3 px-4 font-semibold text-gray-300">CVEs</th>
|
|
93
|
-
<th className="text-left py-3 px-4 font-semibold text-gray-300">Timestamp</th>
|
|
94
|
-
<th className="text-left py-3 px-4 font-semibold text-gray-300">Action</th>
|
|
95
|
-
</tr>
|
|
96
|
-
</thead>
|
|
97
|
-
<tbody>
|
|
98
|
-
{paginated.map((scan: any) => (
|
|
99
|
-
<tr key={scan.id} className="border-b border-gray-800 hover:bg-gray-800 transition">
|
|
100
|
-
<td className="py-4 px-4 font-mono text-blue-400 text-xs">{scan.id}</td>
|
|
101
|
-
<td className="py-4 px-4 text-gray-300 max-w-xs truncate">{scan.repo}</td>
|
|
102
|
-
<td className="py-4 px-4">
|
|
103
|
-
<span
|
|
104
|
-
className={`px-2 py-1 rounded text-xs font-semibold ${
|
|
105
|
-
scan.riskScore >= 8
|
|
106
|
-
? "bg-red-900 text-red-300"
|
|
107
|
-
: scan.riskScore >= 6
|
|
108
|
-
? "bg-orange-900 text-orange-300"
|
|
109
|
-
: scan.riskScore >= 4
|
|
110
|
-
? "bg-yellow-900 text-yellow-300"
|
|
111
|
-
: "bg-green-900 text-green-300"
|
|
112
|
-
}`}
|
|
113
|
-
>
|
|
114
|
-
{scan.riskScore?.toFixed(1) || "N/A"}
|
|
115
|
-
</span>
|
|
116
|
-
</td>
|
|
117
|
-
<td className="py-4 px-4 text-gray-300">{scan.cves?.length || 0}</td>
|
|
118
|
-
<td className="py-4 px-4 text-gray-400 text-xs">
|
|
119
|
-
{new Date(scan.timestamp * 1000).toLocaleString()}
|
|
120
|
-
</td>
|
|
121
|
-
<td className="py-4 px-4">
|
|
122
|
-
<button
|
|
123
|
-
onClick={() => onSelectScan(scan.id)}
|
|
124
|
-
className="text-blue-400 hover:text-blue-300 text-sm font-semibold"
|
|
125
|
-
>
|
|
126
|
-
View →
|
|
127
|
-
</button>
|
|
128
|
-
</td>
|
|
129
|
-
</tr>
|
|
130
|
-
))}
|
|
131
|
-
</tbody>
|
|
132
|
-
</table>
|
|
133
|
-
</div>
|
|
134
|
-
|
|
135
|
-
{maxPages > 1 && (
|
|
136
|
-
<div className="flex justify-between items-center">
|
|
137
|
-
<button
|
|
138
|
-
onClick={() => setPage(Math.max(1, page - 1))}
|
|
139
|
-
disabled={page === 1}
|
|
140
|
-
className="px-4 py-2 bg-gray-700 hover:bg-gray-600 disabled:opacity-50 disabled:cursor-not-allowed rounded transition"
|
|
141
|
-
>
|
|
142
|
-
Previous
|
|
143
|
-
</button>
|
|
144
|
-
<span className="text-gray-400 text-sm">
|
|
145
|
-
Page {page} of {maxPages}
|
|
146
|
-
</span>
|
|
147
|
-
<button
|
|
148
|
-
onClick={() => setPage(Math.min(maxPages, page + 1))}
|
|
149
|
-
disabled={page === maxPages}
|
|
150
|
-
className="px-4 py-2 bg-gray-700 hover:bg-gray-600 disabled:opacity-50 disabled:cursor-not-allowed rounded transition"
|
|
151
|
-
>
|
|
152
|
-
Next
|
|
153
|
-
</button>
|
|
154
|
-
</div>
|
|
155
|
-
)}
|
|
156
|
-
</>
|
|
157
|
-
)}
|
|
158
|
-
</div>
|
|
159
|
-
);
|
|
160
|
-
}
|