codeprobe-scanner 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.
Files changed (96) hide show
  1. package/.claude/settings.local.json +19 -0
  2. package/.dockerignore +17 -0
  3. package/.env.development +8 -0
  4. package/.env.example +20 -0
  5. package/.env.setup +214 -0
  6. package/.github/workflows/codeprobe-scan.yml +137 -0
  7. package/.github/workflows/codeprobe.yml +84 -0
  8. package/.github/workflows/scan-schedule.yml +28 -0
  9. package/ANALYSIS_SUMMARY.md +365 -0
  10. package/API_INTEGRATIONS.md +469 -0
  11. package/BUILD_PLAYBOOK.md +349 -0
  12. package/CLAUDE.md +106 -0
  13. package/DEPLOY.md +452 -0
  14. package/DEPLOYMENT_STATUS.md +240 -0
  15. package/DEPLOY_CHECKLIST.md +316 -0
  16. package/Dockerfile +24 -0
  17. package/EXECUTION_PLAN.html +1086 -0
  18. package/IMPLEMENTATION_COMPLETE.md +288 -0
  19. package/IMPLEMENTATION_SUMMARY.md +443 -0
  20. package/INTERACTIVE_FIX_FLOW.md +308 -0
  21. package/MIGRATION_COMPLETE.md +327 -0
  22. package/ORCHESTRATOR_SYNTHESIS.json +80 -0
  23. package/PENDING_WORK.md +308 -0
  24. package/PREFLIGHT_PLAN.md +182 -0
  25. package/QUICKSTART.md +305 -0
  26. package/README.md +15 -0
  27. package/STAGE_1_SETUP_ENGINE.md +245 -0
  28. package/STAGE_2_ARCHITECTURE.md +714 -0
  29. package/STAGE_2_CLI_VERIFICATION.md +269 -0
  30. package/STAGE_2_COMPLETE.md +332 -0
  31. package/STAGE_2_IMPLEMENTATION_PLAN.md +679 -0
  32. package/STAGE_3_COMPLETE.md +246 -0
  33. package/STAGE_3_DASHBOARD_POLISH.md +371 -0
  34. package/STAGE_3_SETUP.md +155 -0
  35. package/VIDEODB_INTEGRATION.md +237 -0
  36. package/archived/DASHBOARD_UI_WALKTHROUGH.md +392 -0
  37. package/archived/FRONTEND_SETUP.md +236 -0
  38. package/archived/auth.ts +40 -0
  39. package/archived/dashboard/components/BusinessImpactCard.tsx +48 -0
  40. package/archived/dashboard/components/CVETable.tsx +104 -0
  41. package/archived/dashboard/components/ErrorBoundary.tsx +48 -0
  42. package/archived/dashboard/components/PatchDiffViewer.tsx +43 -0
  43. package/archived/dashboard/components/RiskGauge.tsx +64 -0
  44. package/archived/dashboard/frontend.tsx +104 -0
  45. package/archived/dashboard/hooks/useAuth.ts +32 -0
  46. package/archived/dashboard/hooks/useScan.ts +65 -0
  47. package/archived/dashboard/index.html +15 -0
  48. package/archived/dashboard/pages/LoginPage.tsx +28 -0
  49. package/archived/dashboard/pages/ScanDetailPage.tsx +143 -0
  50. package/archived/dashboard/pages/ScansListPage.tsx +160 -0
  51. package/bin/install-and-run.sh +91 -0
  52. package/bun.lock +603 -0
  53. package/codeprobe-prd.md +674 -0
  54. package/cve-cache.json +25 -0
  55. package/demo-vulnerable-app/.github/workflows/codeprobe.yml +32 -0
  56. package/demo-vulnerable-app/README.md +70 -0
  57. package/demo-vulnerable-app/package-lock.json +27 -0
  58. package/demo-vulnerable-app/package.json +15 -0
  59. package/demo-vulnerable-app/server.js +34 -0
  60. package/demo.sh +45 -0
  61. package/index.ts +19 -0
  62. package/package.json +28 -0
  63. package/patches.json +12 -0
  64. package/serve-dashboard.ts +23 -0
  65. package/src/api/server-cli.ts +270 -0
  66. package/src/api/server.ts +293 -0
  67. package/src/bot/server.ts +113 -0
  68. package/src/cli/commands/report.ts +92 -0
  69. package/src/cli/commands/scan-with-fix.ts +123 -0
  70. package/src/cli/commands/scan.ts +137 -0
  71. package/src/cli/config.ts +188 -0
  72. package/src/cli/errors.ts +120 -0
  73. package/src/cli/index.ts +137 -0
  74. package/src/cli/progress.ts +119 -0
  75. package/src/cli-server.ts +523 -0
  76. package/src/engine/index.ts +90 -0
  77. package/src/engine/matcher.ts +115 -0
  78. package/src/engine/parser.ts +91 -0
  79. package/src/engine/patcher.ts +280 -0
  80. package/src/engine/report.ts +137 -0
  81. package/src/engine/sandbox.ts +222 -0
  82. package/src/engine/scraper.ts +122 -0
  83. package/src/integrations/videodb.ts +153 -0
  84. package/src/mcp/server.ts +149 -0
  85. package/src/scraper-cron.ts +103 -0
  86. package/src/shared/constants.ts +88 -0
  87. package/src/shared/types.ts +123 -0
  88. package/src/shared/utils.ts +80 -0
  89. package/src/test/cli.test.ts +211 -0
  90. package/src/test/dashboard.test.ts +38 -0
  91. package/src/test/demo-scan.json +32 -0
  92. package/src/test/engine.test.ts +157 -0
  93. package/tailwind.config.js +11 -0
  94. package/tsconfig.json +30 -0
  95. package/verify-dashboard.ts +87 -0
  96. package/verify-env.sh +98 -0
@@ -0,0 +1,32 @@
1
+ name: CodeProbe Demo - Security Scan
2
+
3
+ on: [push, pull_request]
4
+
5
+ jobs:
6
+ scan:
7
+ runs-on: ubuntu-latest
8
+ steps:
9
+ - uses: actions/checkout@v4
10
+ with:
11
+ fetch-depth: 0
12
+
13
+ - name: Setup Bun
14
+ uses: oven-sh/setup-bun@v1
15
+
16
+ - name: Install CodeProbe
17
+ run: |
18
+ cd ..
19
+ bun install
20
+
21
+ - name: Run CodeProbe scan
22
+ run: |
23
+ cd ..
24
+ bun run src/cli/index.ts scan ./demo-vulnerable-app --json
25
+ env:
26
+ BRIGHT_DATA_API_KEY: ${{ secrets.BRIGHT_DATA_API_KEY }}
27
+ DAYTONA_API_KEY: ${{ secrets.DAYTONA_API_KEY }}
28
+
29
+ - name: Check for exploitable vulnerabilities
30
+ run: |
31
+ cd ..
32
+ bun run src/cli/index.ts scan ./demo-vulnerable-app --json | grep -q '"exploitable": true' && echo "✅ Vulnerability verified" || echo "⚠️ No exploitable vulnerabilities found"
@@ -0,0 +1,70 @@
1
+ # CodeProbe Demo: Vulnerable Node.js App
2
+
3
+ This is a deliberately vulnerable Node.js application used to demonstrate CodeProbe's exploit verification capabilities.
4
+
5
+ ## Vulnerabilities
6
+
7
+ ### CVE-2022-29078: EJS Template Injection RCE
8
+
9
+ **Affected Package:** `ejs@3.1.6`
10
+ **Severity:** CRITICAL (CVSS 9.8)
11
+ **Issue:** The EJS template engine allows template injection attacks that lead to arbitrary code execution.
12
+
13
+ **How it's vulnerable:**
14
+ - Line in `server.js`: `ejs.render(req.query.template, ...)`
15
+ - User can inject malicious EJS template expressions
16
+ - Server executes arbitrary JavaScript code
17
+
18
+ **Exploit:**
19
+ ```bash
20
+ curl "http://localhost:3000/?template=<%= require('child_process').execSync('whoami') %>"
21
+ ```
22
+
23
+ **Fix:** Upgrade `ejs` to version 3.1.7 or higher.
24
+
25
+ ## Running the Demo App
26
+
27
+ ```bash
28
+ cd demo-vulnerable-app
29
+ npm install
30
+ npm start
31
+ ```
32
+
33
+ The app listens on `http://localhost:3000`.
34
+
35
+ ## Using CodeProbe to Scan
36
+
37
+ ```bash
38
+ # From the codeprobe root directory:
39
+ bun run src/cli/index.ts scan ./demo-vulnerable-app
40
+
41
+ # Or with JSON output:
42
+ bun run src/cli/index.ts scan ./demo-vulnerable-app --json
43
+ ```
44
+
45
+ ## Expected Output
46
+
47
+ CodeProbe will:
48
+ 1. **Parse dependencies** — Extract EJS 3.1.6 from package.json
49
+ 2. **Scrape CVE data** — Find CVE-2022-29078 in NVD (via Bright Data)
50
+ 3. **Match versions** — Detect that EJS 3.1.6 is vulnerable
51
+ 4. **Verify in sandbox** — Spawn a Daytona container and execute the PoC exploit
52
+ 5. **Generate patch** — Create a patch to upgrade EJS to 3.1.7
53
+ 6. **Report findings** — Display "CONFIRMED EXPLOITABLE" with business impact ($4.9M breach cost)
54
+
55
+ ## Why This Demo?
56
+
57
+ - **Realistic vulnerability**: EJS template injection is a real, widely-exploited vulnerability
58
+ - **Node.js native**: Works in isolated containers without external dependencies
59
+ - **Clear proof**: Exploit evidence is captured in sandbox logs
60
+ - **Fast verification**: Exploit runs in < 2 seconds
61
+
62
+ ## Files
63
+
64
+ - `package.json` — Intentionally pinned to vulnerable EJS 3.1.6
65
+ - `server.js` — Express server with template injection vulnerability
66
+ - `.github/workflows/codeprobe.yml` — CI/CD integration example
67
+
68
+ ## Disclaimer
69
+
70
+ This app is for **security research and education only**. Do not use in production or with untrusted code.
@@ -0,0 +1,27 @@
1
+ {
2
+ "name": "demo-vulnerable-app",
3
+ "version": "1.0.0",
4
+ "lockfileVersion": 3,
5
+ "requires": true,
6
+ "packages": {
7
+ "": {
8
+ "name": "demo-vulnerable-app",
9
+ "version": "1.0.0",
10
+ "dependencies": {
11
+ "express": "^4.18.2",
12
+ "ejs": "3.1.6"
13
+ }
14
+ },
15
+ "node_modules/express": {
16
+ "version": "4.18.2",
17
+ "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz"
18
+ },
19
+ "node_modules/ejs": {
20
+ "version": "3.1.6",
21
+ "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.6.tgz",
22
+ "engines": {
23
+ "node": ">=0.10.0"
24
+ }
25
+ }
26
+ }
27
+ }
@@ -0,0 +1,15 @@
1
+ {
2
+ "name": "demo-vulnerable-app",
3
+ "version": "1.0.0",
4
+ "description": "Demo application with intentional vulnerability for CodeProbe testing",
5
+ "main": "server.js",
6
+ "scripts": {
7
+ "start": "node server.js",
8
+ "test": "bun test"
9
+ },
10
+ "dependencies": {
11
+ "express": "^4.18.2",
12
+ "ejs": "3.1.6"
13
+ },
14
+ "devDependencies": {}
15
+ }
@@ -0,0 +1,34 @@
1
+ const express = require("express");
2
+ const ejs = require("ejs");
3
+ const app = express();
4
+
5
+ app.use(express.urlencoded({ extended: false }));
6
+
7
+ // Vulnerable endpoint: directly renders user input as template
8
+ app.get("/render", (req, res) => {
9
+ const template = req.query.template || "Hello <%= name %>";
10
+
11
+ try {
12
+ // VULNERABLE: ejs.render() executes arbitrary code in templates
13
+ // An attacker can inject: <%= require('child_process').execSync('id') %>
14
+ const result = ejs.render(template, { name: "World" });
15
+ res.send(`<pre>${result}</pre>`);
16
+ } catch (error) {
17
+ res.status(500).send(`<pre>Error: ${error.message}</pre>`);
18
+ }
19
+ });
20
+
21
+ app.get("/", (req, res) => {
22
+ res.send(`
23
+ <h1>CodeProbe Demo - EJS Template Injection</h1>
24
+ <p>This app uses EJS ${require("ejs/package.json").version}</p>
25
+ <p>Visit: <a href="/render?template=&lt;%= 'VULNERABLE' %>">/render</a> to test</p>
26
+ <p>Or send a template parameter to exploit</p>
27
+ `);
28
+ });
29
+
30
+ const port = 3000;
31
+ app.listen(port, () => {
32
+ console.log(`Demo app listening on http://localhost:${port}`);
33
+ console.log(`Vulnerable ejs version: ${require("ejs/package.json").version}`);
34
+ });
package/demo.sh ADDED
@@ -0,0 +1,45 @@
1
+ #!/bin/bash
2
+ set -e
3
+
4
+ echo "=== CodeProbe Demo Script ==="
5
+ echo ""
6
+
7
+ # Colors for output
8
+ RED='\033[0;31m'
9
+ GREEN='\033[0;32m'
10
+ YELLOW='\033[1;33m'
11
+ BLUE='\033[0;34m'
12
+ NC='\033[0m' # No Color
13
+
14
+ # Check if bun is installed
15
+ if ! command -v bun &> /dev/null; then
16
+ echo -e "${RED}Error: bun is not installed${NC}"
17
+ exit 1
18
+ fi
19
+
20
+ echo -e "${BLUE}1. Clearing previous scans...${NC}"
21
+ rm -rf ~/.codeprobe/scans/*
22
+ echo -e "${GREEN}✓ Scans cleared${NC}"
23
+ echo ""
24
+
25
+ echo -e "${BLUE}2. Running scan...${NC}"
26
+ time bun run src/cli/index.ts scan .
27
+ echo -e "${GREEN}✓ Scan complete${NC}"
28
+ echo ""
29
+
30
+ echo -e "${BLUE}3. Displaying report...${NC}"
31
+ bun run src/cli/index.ts report
32
+ echo ""
33
+
34
+ echo -e "${BLUE}4. Testing with --json flag...${NC}"
35
+ bun run src/cli/index.ts scan . --json | head -20
36
+ echo "..."
37
+ echo ""
38
+
39
+ echo -e "${GREEN}✅ Demo successful!${NC}"
40
+ echo ""
41
+ echo -e "${YELLOW}Next steps:${NC}"
42
+ echo " • Run scan with fix: bun run src/cli/index.ts scan . --fix"
43
+ echo " • View config: bun run src/cli/index.ts config get"
44
+ echo " • Set API key: bun run src/cli/index.ts config set bright_data_api_key <key>"
45
+ echo ""
package/index.ts ADDED
@@ -0,0 +1,19 @@
1
+ import { createEngine } from "./src/engine/index";
2
+
3
+ const engine = createEngine();
4
+ const repoPath = process.argv[2] || "./demo-vulnerable-app";
5
+
6
+ console.log(`\n⚡ CodeProbe v1.0.0`);
7
+ console.log(`Scanning repository: ${repoPath}\n`);
8
+
9
+ try {
10
+ const report = await engine.scan(repoPath);
11
+ const formatted = (await import("./src/engine/report")).createReportBuilder().formatForTerminal(report);
12
+ console.log(formatted);
13
+
14
+ // Exit with appropriate code
15
+ process.exit(report.summary.exploitable_count > 0 ? 1 : 0);
16
+ } catch (error) {
17
+ console.error("❌ Scan failed:", error instanceof Error ? error.message : String(error));
18
+ process.exit(2);
19
+ }
package/package.json ADDED
@@ -0,0 +1,28 @@
1
+ {
2
+ "name": "codeprobe-scanner",
3
+ "version": "1.0.0",
4
+ "description": "Automated vulnerability scanner with exploit verification and video evidence",
5
+ "type": "module",
6
+ "bin": {
7
+ "codeprobe": "bin/install-and-run.sh"
8
+ },
9
+ "publishConfig": {
10
+ "access": "public"
11
+ },
12
+ "scripts": {
13
+ "setup": "bin/install-and-run.sh"
14
+ },
15
+ "dependencies": {
16
+ "@daytona/sdk": "^0.187.0",
17
+ "axios": "^1.6.5",
18
+ "chalk": "^5.3.0",
19
+ "cli-table3": "^0.6.3",
20
+ "dayjs": "^1.11.10",
21
+ "ora": "^8.0.1",
22
+ "react": "^18.2.0",
23
+ "react-dom": "^18.2.0",
24
+ "tailwindcss": "^3.3.0",
25
+ "videodb": "^0.2.7",
26
+ "zod": "^3.22.4"
27
+ }
28
+ }
package/patches.json ADDED
@@ -0,0 +1,12 @@
1
+ [
2
+ {
3
+ "cve_id": "CVE-2022-29078",
4
+ "package": "ejs",
5
+ "from_version": "3.1.0",
6
+ "to_version": "3.1.7",
7
+ "description": "Fixes template injection RCE vulnerability by sanitizing template inputs",
8
+ "diff": "--- a/package.json\n+++ b/package.json\n@@ -5,1 +5,1 @@\n- \"ejs\": \"3.1.6\"\n+ \"ejs\": \"3.1.7\"\n--- a/package-lock.json\n+++ b/package-lock.json\n@@ -10,1 +10,1 @@\n- \"version\": \"3.1.6\",\n+ \"version\": \"3.1.7\",",
9
+ "severity": "CRITICAL",
10
+ "cvss": 9.8
11
+ }
12
+ ]
@@ -0,0 +1,23 @@
1
+ import { serve } from "bun";
2
+ import path from "path";
3
+
4
+ const distDir = "dist";
5
+
6
+ export default serve({
7
+ port: 5173,
8
+ fetch(req) {
9
+ const url = new URL(req.url);
10
+ let filePath = url.pathname;
11
+
12
+ if (filePath === "/" || filePath === "") {
13
+ filePath = "index.html";
14
+ }
15
+
16
+ const file = Bun.file(path.join(distDir, filePath));
17
+ return file.exists().then(() => new Response(file));
18
+ },
19
+ });
20
+
21
+ console.log("🎨 Dashboard serving on http://localhost:5173");
22
+ console.log("📡 API on http://localhost:3000");
23
+ console.log("📂 Serving: dist/");
@@ -0,0 +1,270 @@
1
+ import { createEngine } from "../engine/index";
2
+ import { Report } from "../shared/types";
3
+
4
+ // Environment validation
5
+ const GOOGLE_CLOUD_URL = process.env.GOOGLE_CLOUD_URL;
6
+ const API_SECRET_TOKEN = process.env.API_SECRET_TOKEN;
7
+ const PORT = parseInt(process.env.PORT || "8080");
8
+ const NODE_ENV = process.env.NODE_ENV || "development";
9
+
10
+ // Validate required environment variables
11
+ if (NODE_ENV === "production") {
12
+ if (!GOOGLE_CLOUD_URL) {
13
+ throw new Error(
14
+ "GOOGLE_CLOUD_URL environment variable is required in production"
15
+ );
16
+ }
17
+ if (!API_SECRET_TOKEN) {
18
+ throw new Error(
19
+ "API_SECRET_TOKEN environment variable is required in production"
20
+ );
21
+ }
22
+ }
23
+
24
+ // Rate limiting: max 5 requests per minute per IP
25
+ interface RateLimitEntry {
26
+ count: number;
27
+ resetTime: number;
28
+ }
29
+
30
+ const rateLimitMap = new Map<string, RateLimitEntry>();
31
+ const RATE_LIMIT_WINDOW = 60 * 1000; // 1 minute
32
+ const RATE_LIMIT_MAX = 5;
33
+
34
+ function getClientIP(req: Request): string {
35
+ const forwarded = req.headers.get("x-forwarded-for");
36
+ if (forwarded) {
37
+ return forwarded.split(",")[0].trim();
38
+ }
39
+ // In production on Google Cloud, you should rely on x-forwarded-for
40
+ // For local testing, use localhost
41
+ return req.headers.get("cf-connecting-ip") || "127.0.0.1";
42
+ }
43
+
44
+ function checkRateLimit(ip: string): { allowed: boolean; remaining: number } {
45
+ const now = Date.now();
46
+ const entry = rateLimitMap.get(ip);
47
+
48
+ if (!entry || now > entry.resetTime) {
49
+ // Window expired, create new entry
50
+ rateLimitMap.set(ip, { count: 1, resetTime: now + RATE_LIMIT_WINDOW });
51
+ return { allowed: true, remaining: RATE_LIMIT_MAX - 1 };
52
+ }
53
+
54
+ if (entry.count >= RATE_LIMIT_MAX) {
55
+ return { allowed: false, remaining: 0 };
56
+ }
57
+
58
+ entry.count++;
59
+ return { allowed: true, remaining: RATE_LIMIT_MAX - entry.count };
60
+ }
61
+
62
+ // Type for scan request
63
+ interface ScanRequest {
64
+ dependencies?: Array<{ name: string; version: string }>;
65
+ repoPath?: string;
66
+ }
67
+
68
+ interface ScanResponse {
69
+ success: boolean;
70
+ data?: Report;
71
+ error?: string;
72
+ riskScore?: number;
73
+ executiveSummary?: {
74
+ totalCVEs: number;
75
+ exploitableCVEs: number;
76
+ theoreticalCVEs: number;
77
+ scanDurationMs: number;
78
+ timestamp: string;
79
+ };
80
+ }
81
+
82
+ async function handleScan(
83
+ req: Request,
84
+ ip: string
85
+ ): Promise<Response> {
86
+ try {
87
+ // Parse request body
88
+ const body = await req.json() as ScanRequest;
89
+
90
+ // Validate request
91
+ if (!body.repoPath && (!body.dependencies || body.dependencies.length === 0)) {
92
+ return new Response(
93
+ JSON.stringify({
94
+ success: false,
95
+ error:
96
+ "Request must include either repoPath or dependencies array",
97
+ }),
98
+ {
99
+ status: 400,
100
+ headers: { "Content-Type": "application/json" },
101
+ }
102
+ );
103
+ }
104
+
105
+ const repoPath = body.repoPath || process.cwd();
106
+
107
+ // Log sponsor branding
108
+ console.log("[Bright Data] Scraping CVE data from NVD, Exploit-DB, Snyk...");
109
+ console.log("[Daytona] Sandboxing exploits for verification...");
110
+ console.log("[Nosana] Patching vulnerable dependencies...");
111
+
112
+ // Run scan
113
+ const engine = createEngine();
114
+ console.log(`\n🔍 Starting security scan for: ${repoPath}`);
115
+ const report = await engine.scan(repoPath);
116
+
117
+ const response: ScanResponse = {
118
+ success: true,
119
+ data: report,
120
+ riskScore: report.scan.risk_score,
121
+ executiveSummary: {
122
+ totalCVEs: report.summary.total_cves,
123
+ exploitableCVEs: report.summary.exploitable_count,
124
+ theoreticalCVEs: report.summary.theoretical_count,
125
+ scanDurationMs: report.summary.scan_duration_ms,
126
+ timestamp: report.scan.timestamp,
127
+ },
128
+ };
129
+
130
+ return new Response(JSON.stringify(response), {
131
+ status: 200,
132
+ headers: {
133
+ "Content-Type": "application/json",
134
+ "X-RateLimit-Remaining": String(rateLimitMap.get(ip)?.count || 0),
135
+ },
136
+ });
137
+ } catch (error) {
138
+ console.error("Scan error:", error);
139
+
140
+ const errorMessage =
141
+ error instanceof Error ? error.message : String(error);
142
+
143
+ const errorResponse: ScanResponse = {
144
+ success: false,
145
+ error: errorMessage,
146
+ };
147
+
148
+ return new Response(JSON.stringify(errorResponse), {
149
+ status: 500,
150
+ headers: { "Content-Type": "application/json" },
151
+ });
152
+ }
153
+ }
154
+
155
+ async function handleHealth(): Promise<Response> {
156
+ return new Response(JSON.stringify({ status: "ok" }), {
157
+ status: 200,
158
+ headers: { "Content-Type": "application/json" },
159
+ });
160
+ }
161
+
162
+ // Main server
163
+ const server = Bun.serve({
164
+ port: PORT,
165
+ development: NODE_ENV !== "production",
166
+ async fetch(req) {
167
+ const url = new URL(req.url);
168
+ const pathname = url.pathname;
169
+ const method = req.method;
170
+ const ip = getClientIP(req);
171
+
172
+ // Health check
173
+ if (pathname === "/health" && method === "GET") {
174
+ return handleHealth();
175
+ }
176
+
177
+ // Scan endpoint
178
+ if (pathname === "/api/scan" && method === "POST") {
179
+ // Rate limiting check
180
+ const rateLimit = checkRateLimit(ip);
181
+ if (!rateLimit.allowed) {
182
+ console.warn(`Rate limit exceeded for IP: ${ip}`);
183
+ return new Response(
184
+ JSON.stringify({
185
+ success: false,
186
+ error: "Rate limit exceeded. Maximum 5 requests per minute.",
187
+ }),
188
+ {
189
+ status: 429,
190
+ headers: {
191
+ "Content-Type": "application/json",
192
+ "Retry-After": "60",
193
+ },
194
+ }
195
+ );
196
+ }
197
+
198
+ // Token validation in production
199
+ if (NODE_ENV === "production") {
200
+ const authHeader = req.headers.get("Authorization") || "";
201
+ const token = authHeader.replace("Bearer ", "");
202
+
203
+ if (token !== API_SECRET_TOKEN) {
204
+ console.warn(`Invalid API token from IP: ${ip}`);
205
+ return new Response(
206
+ JSON.stringify({
207
+ success: false,
208
+ error: "Invalid or missing API token",
209
+ }),
210
+ {
211
+ status: 401,
212
+ headers: { "Content-Type": "application/json" },
213
+ }
214
+ );
215
+ }
216
+ }
217
+
218
+ // Handle scan
219
+ return handleScan(req, ip);
220
+ }
221
+
222
+ // 404 for unknown routes
223
+ return new Response(
224
+ JSON.stringify({
225
+ success: false,
226
+ error: `Unknown route: ${pathname}`,
227
+ }),
228
+ {
229
+ status: 404,
230
+ headers: { "Content-Type": "application/json" },
231
+ }
232
+ );
233
+ },
234
+ });
235
+
236
+ // Log startup information
237
+ console.log("\n╔════════════════════════════════════════════════════════╗");
238
+ console.log("║ CodeProbe Security Scan API Server (CLI-only) ║");
239
+ console.log("╚════════════════════════════════════════════════════════╝\n");
240
+ console.log(`📍 Environment: ${NODE_ENV}`);
241
+ console.log(`🚀 Server running on http://localhost:${PORT}`);
242
+ console.log(`\n📊 Available endpoints:`);
243
+ console.log(` GET /health - Health check`);
244
+ console.log(` POST /api/scan - Run vulnerability scan\n`);
245
+
246
+ if (NODE_ENV === "production") {
247
+ console.log(`✅ Production mode enabled`);
248
+ console.log(` - Google Cloud URL configured: ${GOOGLE_CLOUD_URL}`);
249
+ console.log(` - API authentication required (Bearer token)\n`);
250
+ } else {
251
+ console.log(`⚠️ Development mode - authentication disabled\n`);
252
+ }
253
+
254
+ console.log(`📈 Rate limiting: 5 requests per minute per IP`);
255
+ console.log(
256
+ `\n💡 Example request:\n`
257
+ );
258
+ console.log(` curl -X POST http://localhost:${PORT}/api/scan \\`);
259
+ console.log(` -H "Content-Type: application/json" \\`);
260
+ if (NODE_ENV === "production") {
261
+ console.log(` -H "Authorization: Bearer $API_SECRET_TOKEN" \\`);
262
+ }
263
+ console.log(` -d '{"repoPath": "/path/to/repo"}'\n`);
264
+
265
+ console.log(`🔗 Sponsor credits:`);
266
+ console.log(` [Bright Data] - CVE data scraping from NVD, Exploit-DB, Snyk`);
267
+ console.log(` [Daytona] - Sandboxed exploit verification`);
268
+ console.log(` [Nosana] - LLM-powered patch generation\n`);
269
+
270
+ export default server;