codeprobe-scanner 1.0.5 → 1.0.7
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/codeprobe.cjs +1 -1
- package/package.json +1 -1
- package/src/cli/commands/scan.ts +18 -1
- package/src/engine/patcher.ts +11 -7
- package/src/engine/sandbox.ts +12 -10
- package/src/engine/scraper.ts +13 -7
- package/src/integrations/videodb.ts +9 -8
package/bin/codeprobe.cjs
CHANGED
|
@@ -40,7 +40,7 @@ if (!bunCmd) {
|
|
|
40
40
|
|
|
41
41
|
// Run the CLI
|
|
42
42
|
const args = process.argv.slice(2);
|
|
43
|
-
const cmd = `${bunCmd} run ${path.join(packageRoot, 'src/cli
|
|
43
|
+
const cmd = `${bunCmd} run ${path.join(packageRoot, 'src/cli/index.ts')} ${args.join(' ')}`;
|
|
44
44
|
|
|
45
45
|
try {
|
|
46
46
|
execSync(cmd, {
|
package/package.json
CHANGED
package/src/cli/commands/scan.ts
CHANGED
|
@@ -8,6 +8,7 @@ import { handleError, CodeProbeError } from '../errors.js';
|
|
|
8
8
|
import { generateScanId, formatRiskScore, msToHuman } from '../../shared/utils.js';
|
|
9
9
|
import { Report } from '../../shared/types.js';
|
|
10
10
|
import { createEngine } from '../../engine/index.js';
|
|
11
|
+
import { getConfig } from '../config.js';
|
|
11
12
|
|
|
12
13
|
interface ScanOptions {
|
|
13
14
|
fix: boolean;
|
|
@@ -104,10 +105,26 @@ export async function scanCommand(args: string[]): Promise<void> {
|
|
|
104
105
|
|
|
105
106
|
logger.printHeader();
|
|
106
107
|
|
|
108
|
+
// Check for required API key
|
|
109
|
+
const brightDataKey = process.env.BRIGHT_DATA_API_KEY || await getConfig("bright_data_api_key");
|
|
110
|
+
if (!brightDataKey) {
|
|
111
|
+
console.log(chalk.yellow('\n⚠️ No Bright Data API key configured.'));
|
|
112
|
+
console.log(chalk.dim(' CVE lookup requires a Bright Data account (free tier available).'));
|
|
113
|
+
console.log(chalk.dim(' Get a key at: https://brightdata.com'));
|
|
114
|
+
console.log('');
|
|
115
|
+
console.log(chalk.cyan(' To configure:'));
|
|
116
|
+
console.log(chalk.white(' codeprobe config set bright_data_api_key <your-key>'));
|
|
117
|
+
console.log('');
|
|
118
|
+
console.log(chalk.dim(' Optional keys for full functionality:'));
|
|
119
|
+
console.log(chalk.dim(' codeprobe config set daytona_api_key <key> # exploit verification'));
|
|
120
|
+
console.log(chalk.dim(' codeprobe config set kimi_api_key <key> # AI patch generation'));
|
|
121
|
+
console.log('');
|
|
122
|
+
process.exit(EXIT_CODES.SCAN_FAILED);
|
|
123
|
+
}
|
|
124
|
+
|
|
107
125
|
const startTime = Date.now();
|
|
108
126
|
|
|
109
127
|
try {
|
|
110
|
-
// Initialize engine
|
|
111
128
|
const engine = createEngine();
|
|
112
129
|
|
|
113
130
|
// Run the actual engine scan (not mocked)
|
package/src/engine/patcher.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { ScanCVE } from "../shared/types";
|
|
2
2
|
import { PATHS, DEMO_CVE } from "../shared/constants";
|
|
3
3
|
import axios from "axios";
|
|
4
|
+
import { getConfig } from "../cli/config.js";
|
|
4
5
|
|
|
5
6
|
interface PatchData {
|
|
6
7
|
cve_id: string;
|
|
@@ -13,12 +14,14 @@ interface PatchData {
|
|
|
13
14
|
|
|
14
15
|
export class PatchGenerator {
|
|
15
16
|
private patches: Map<string, PatchData> = new Map();
|
|
16
|
-
private kimiApiKey: string;
|
|
17
|
-
private nosanaApiKey: string;
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
this.kimiApiKey = process.env.KIMI_API_KEY
|
|
21
|
-
|
|
17
|
+
private kimiApiKey: string = "";
|
|
18
|
+
private nosanaApiKey: string = "";
|
|
19
|
+
|
|
20
|
+
private async resolveKeys(): Promise<void> {
|
|
21
|
+
this.kimiApiKey = process.env.KIMI_API_KEY
|
|
22
|
+
|| (typeof await getConfig("kimi_api_key") === "string" ? await getConfig("kimi_api_key") as string : "");
|
|
23
|
+
this.nosanaApiKey = process.env.NOSANA_API_KEY
|
|
24
|
+
|| (typeof await getConfig("nosana_api_key") === "string" ? await getConfig("nosana_api_key") as string : "");
|
|
22
25
|
}
|
|
23
26
|
|
|
24
27
|
async loadPrebakedPatches(): Promise<void> {
|
|
@@ -62,7 +65,8 @@ export class PatchGenerator {
|
|
|
62
65
|
}
|
|
63
66
|
|
|
64
67
|
async generatePatch(cve: ScanCVE): Promise<string | null> {
|
|
65
|
-
|
|
68
|
+
await this.resolveKeys();
|
|
69
|
+
|
|
66
70
|
const prebakedPatch = this.patches.get(cve.id);
|
|
67
71
|
if (prebakedPatch) {
|
|
68
72
|
cve.patch_diff = prebakedPatch.diff;
|
package/src/engine/sandbox.ts
CHANGED
|
@@ -2,34 +2,36 @@ import { Daytona } from "@daytona/sdk";
|
|
|
2
2
|
import { SandboxResult } from "../shared/types";
|
|
3
3
|
import { TIMEOUTS, RETRY_CONFIG, DEMO_CVE } from "../shared/constants";
|
|
4
4
|
import { createVideoDBRecorder } from "../integrations/videodb";
|
|
5
|
+
import { getConfig } from "../cli/config.js";
|
|
5
6
|
|
|
6
7
|
export class SandboxOrchestrator {
|
|
7
|
-
private apiKey: string;
|
|
8
|
+
private apiKey: string = "";
|
|
8
9
|
private daytonaClient: Daytona | null = null;
|
|
9
10
|
private useDaytona: boolean = false;
|
|
10
11
|
private videoRecorder = createVideoDBRecorder();
|
|
11
12
|
|
|
12
|
-
|
|
13
|
-
|
|
13
|
+
private async resolveApiKey(): Promise<string> {
|
|
14
|
+
if (process.env.DAYTONA_API_KEY) return process.env.DAYTONA_API_KEY;
|
|
15
|
+
const stored = await getConfig("daytona_api_key");
|
|
16
|
+
return typeof stored === "string" ? stored : "";
|
|
17
|
+
}
|
|
14
18
|
|
|
15
|
-
|
|
19
|
+
async initialize(): Promise<void> {
|
|
20
|
+
this.apiKey = await this.resolveApiKey();
|
|
16
21
|
if (this.apiKey && this.apiKey.startsWith("dtn_")) {
|
|
17
22
|
try {
|
|
18
23
|
this.daytonaClient = new Daytona({ apiKey: this.apiKey });
|
|
19
24
|
this.useDaytona = true;
|
|
20
25
|
console.log("[Daytona] ✓ Real sandbox enabled");
|
|
21
|
-
} catch
|
|
22
|
-
console.warn("[Daytona] ⚠️ Failed to initialize, will use local simulation:",
|
|
23
|
-
error instanceof Error ? error.message : String(error));
|
|
26
|
+
} catch {
|
|
24
27
|
this.useDaytona = false;
|
|
25
28
|
}
|
|
26
|
-
} else {
|
|
27
|
-
console.log("[Daytona] Using simulated sandbox (no API key provided)");
|
|
28
29
|
}
|
|
29
30
|
}
|
|
30
31
|
|
|
31
32
|
async runExploit(packageName: string, version: string, cveId: string): Promise<SandboxResult> {
|
|
32
|
-
|
|
33
|
+
if (!this.apiKey) await this.initialize();
|
|
34
|
+
|
|
33
35
|
if (packageName === DEMO_CVE.package && cveId === DEMO_CVE.id) {
|
|
34
36
|
if (this.useDaytona && this.daytonaClient) {
|
|
35
37
|
return await this.runEjsWithDaytona(version);
|
package/src/engine/scraper.ts
CHANGED
|
@@ -1,27 +1,33 @@
|
|
|
1
1
|
import axios from "axios";
|
|
2
2
|
import { CVE, ScrapeResult } from "../shared/types";
|
|
3
3
|
import { API_ENDPOINTS, TIMEOUTS, PATHS, DEMO_CVE } from "../shared/constants";
|
|
4
|
+
import { getConfig } from "../cli/config.js";
|
|
4
5
|
|
|
5
6
|
export class CVEScraper {
|
|
6
|
-
private apiKey: string;
|
|
7
|
+
private apiKey: string = "";
|
|
7
8
|
private cache: Map<string, CVE> = new Map();
|
|
8
9
|
|
|
9
|
-
|
|
10
|
-
|
|
10
|
+
private async resolveApiKey(): Promise<string> {
|
|
11
|
+
if (process.env.BRIGHT_DATA_API_KEY) return process.env.BRIGHT_DATA_API_KEY;
|
|
12
|
+
const stored = await getConfig("bright_data_api_key");
|
|
13
|
+
return typeof stored === "string" ? stored : "";
|
|
11
14
|
}
|
|
12
15
|
|
|
13
16
|
async scrapeForCVEs(packageName: string, version: string): Promise<CVE[]> {
|
|
14
|
-
|
|
17
|
+
this.apiKey = await this.resolveApiKey();
|
|
18
|
+
|
|
15
19
|
if (packageName === DEMO_CVE.package) {
|
|
16
20
|
return [this.buildDemoCVE()];
|
|
17
21
|
}
|
|
18
22
|
|
|
19
|
-
|
|
23
|
+
if (!this.apiKey) {
|
|
24
|
+
return [];
|
|
25
|
+
}
|
|
26
|
+
|
|
20
27
|
try {
|
|
21
28
|
return await this.fetchFromBrightData(packageName, version);
|
|
22
29
|
} catch (error) {
|
|
23
|
-
|
|
24
|
-
return await this.loadFromCache();
|
|
30
|
+
return [];
|
|
25
31
|
}
|
|
26
32
|
}
|
|
27
33
|
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { VideoDb } from "videodb";
|
|
2
|
-
|
|
3
1
|
interface ExploitVideoRecord {
|
|
4
2
|
cveId: string;
|
|
5
3
|
package: string;
|
|
@@ -11,7 +9,7 @@ interface ExploitVideoRecord {
|
|
|
11
9
|
}
|
|
12
10
|
|
|
13
11
|
export class VideoDBRecorder {
|
|
14
|
-
private videoDb:
|
|
12
|
+
private videoDb: any = null;
|
|
15
13
|
private apiKey: string;
|
|
16
14
|
private recordedVideos: Map<string, ExploitVideoRecord> = new Map();
|
|
17
15
|
|
|
@@ -22,15 +20,18 @@ export class VideoDBRecorder {
|
|
|
22
20
|
|
|
23
21
|
private initializeVideoDB(): void {
|
|
24
22
|
if (!this.apiKey) {
|
|
25
|
-
console.warn("[VideoDB] API key not found, video recording disabled");
|
|
26
23
|
return;
|
|
27
24
|
}
|
|
28
25
|
|
|
29
26
|
try {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
27
|
+
const videodb = require("videodb");
|
|
28
|
+
const Constructor = videodb.VideoDb || videodb.Connection || videodb.connect;
|
|
29
|
+
if (typeof Constructor === "function") {
|
|
30
|
+
this.videoDb = new Constructor({ apiKey: this.apiKey });
|
|
31
|
+
console.log("[VideoDB] ✓ Initialized - exploit recordings enabled");
|
|
32
|
+
}
|
|
33
|
+
} catch {
|
|
34
|
+
// VideoDB unavailable, video recording disabled
|
|
34
35
|
}
|
|
35
36
|
}
|
|
36
37
|
|