bugproof 0.1.1
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/CHANGELOG.md +65 -0
- package/README.md +256 -0
- package/assets/icon-16x16.png +0 -0
- package/assets/icon-32x32.png +0 -0
- package/assets/icon-512x512.png +0 -0
- package/dist/capture/engine.d.ts +12 -0
- package/dist/capture/engine.d.ts.map +1 -0
- package/dist/capture/engine.js +129 -0
- package/dist/capture/engine.js.map +1 -0
- package/dist/capture/packager.d.ts +39 -0
- package/dist/capture/packager.d.ts.map +1 -0
- package/dist/capture/packager.js +145 -0
- package/dist/capture/packager.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +538 -0
- package/dist/cli.js.map +1 -0
- package/dist/diff/engine.d.ts +28 -0
- package/dist/diff/engine.d.ts.map +1 -0
- package/dist/diff/engine.js +88 -0
- package/dist/diff/engine.js.map +1 -0
- package/dist/replay/engine.d.ts +41 -0
- package/dist/replay/engine.d.ts.map +1 -0
- package/dist/replay/engine.js +69 -0
- package/dist/replay/engine.js.map +1 -0
- package/dist/replay/sandbox.d.ts +33 -0
- package/dist/replay/sandbox.d.ts.map +1 -0
- package/dist/replay/sandbox.js +167 -0
- package/dist/replay/sandbox.js.map +1 -0
- package/dist/replay/verdict.d.ts +8 -0
- package/dist/replay/verdict.d.ts.map +1 -0
- package/dist/replay/verdict.js +32 -0
- package/dist/replay/verdict.js.map +1 -0
- package/dist/sandbox/bugbox.d.ts +38 -0
- package/dist/sandbox/bugbox.d.ts.map +1 -0
- package/dist/sandbox/bugbox.js +122 -0
- package/dist/sandbox/bugbox.js.map +1 -0
- package/dist/sandbox/capabilities.d.ts +33 -0
- package/dist/sandbox/capabilities.d.ts.map +1 -0
- package/dist/sandbox/capabilities.js +53 -0
- package/dist/sandbox/capabilities.js.map +1 -0
- package/dist/sandbox/filesystem.d.ts +50 -0
- package/dist/sandbox/filesystem.d.ts.map +1 -0
- package/dist/sandbox/filesystem.js +134 -0
- package/dist/sandbox/filesystem.js.map +1 -0
- package/dist/sandbox/network.d.ts +68 -0
- package/dist/sandbox/network.d.ts.map +1 -0
- package/dist/sandbox/network.js +136 -0
- package/dist/sandbox/network.js.map +1 -0
- package/dist/sandbox/process.d.ts +17 -0
- package/dist/sandbox/process.d.ts.map +1 -0
- package/dist/sandbox/process.js +30 -0
- package/dist/sandbox/process.js.map +1 -0
- package/dist/sandbox/resources.d.ts +21 -0
- package/dist/sandbox/resources.d.ts.map +1 -0
- package/dist/sandbox/resources.js +60 -0
- package/dist/sandbox/resources.js.map +1 -0
- package/dist/types/artifact.d.ts +57 -0
- package/dist/types/artifact.d.ts.map +1 -0
- package/dist/types/artifact.js +2 -0
- package/dist/types/artifact.js.map +1 -0
- package/dist/types/failure.d.ts +12 -0
- package/dist/types/failure.d.ts.map +1 -0
- package/dist/types/failure.js +2 -0
- package/dist/types/failure.js.map +1 -0
- package/dist/utils/archive.d.ts +13 -0
- package/dist/utils/archive.d.ts.map +1 -0
- package/dist/utils/archive.js +39 -0
- package/dist/utils/archive.js.map +1 -0
- package/dist/utils/associations.d.ts +10 -0
- package/dist/utils/associations.d.ts.map +1 -0
- package/dist/utils/associations.js +46 -0
- package/dist/utils/associations.js.map +1 -0
- package/dist/utils/exclude.d.ts +12 -0
- package/dist/utils/exclude.d.ts.map +1 -0
- package/dist/utils/exclude.js +42 -0
- package/dist/utils/exclude.js.map +1 -0
- package/dist/utils/fingerprint.d.ts +16 -0
- package/dist/utils/fingerprint.d.ts.map +1 -0
- package/dist/utils/fingerprint.js +72 -0
- package/dist/utils/fingerprint.js.map +1 -0
- package/dist/utils/git.d.ts +13 -0
- package/dist/utils/git.d.ts.map +1 -0
- package/dist/utils/git.js +41 -0
- package/dist/utils/git.js.map +1 -0
- package/dist/utils/json-output.d.ts +36 -0
- package/dist/utils/json-output.d.ts.map +1 -0
- package/dist/utils/json-output.js +49 -0
- package/dist/utils/json-output.js.map +1 -0
- package/dist/utils/paths.d.ts +19 -0
- package/dist/utils/paths.d.ts.map +1 -0
- package/dist/utils/paths.js +43 -0
- package/dist/utils/paths.js.map +1 -0
- package/dist/utils/secrets.d.ts +13 -0
- package/dist/utils/secrets.d.ts.map +1 -0
- package/dist/utils/secrets.js +52 -0
- package/dist/utils/secrets.js.map +1 -0
- package/dist/utils/security.d.ts +27 -0
- package/dist/utils/security.d.ts.map +1 -0
- package/dist/utils/security.js +75 -0
- package/dist/utils/security.js.map +1 -0
- package/dist/utils/ui.d.ts +31 -0
- package/dist/utils/ui.d.ts.map +1 -0
- package/dist/utils/ui.js +54 -0
- package/dist/utils/ui.js.map +1 -0
- package/package.json +80 -0
- package/scripts/bugproof-file-association-linux.sh +80 -0
- package/scripts/bugproof-file-association-macos.sh +48 -0
- package/scripts/bugproof-file-association-windows.reg +44 -0
- package/scripts/postinstall.cjs +215 -0
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Diff engine: compares two .bug artifacts and produces a structured diff report.
|
|
3
|
+
*/
|
|
4
|
+
export function diffArtifacts(left, right) {
|
|
5
|
+
const changes = [];
|
|
6
|
+
// Compare exit code
|
|
7
|
+
if (left.failure.exit_code !== right.failure.exit_code) {
|
|
8
|
+
changes.push({ field: 'exit_code', left: left.failure.exit_code, right: right.failure.exit_code });
|
|
9
|
+
}
|
|
10
|
+
// Compare fingerprint
|
|
11
|
+
if (left.failure.fingerprint !== right.failure.fingerprint) {
|
|
12
|
+
changes.push({ field: 'fingerprint', left: left.failure.fingerprint, right: right.failure.fingerprint });
|
|
13
|
+
}
|
|
14
|
+
// Compare command
|
|
15
|
+
const leftCmd = left.manifest.command.join(' ');
|
|
16
|
+
const rightCmd = right.manifest.command.join(' ');
|
|
17
|
+
if (leftCmd !== rightCmd) {
|
|
18
|
+
changes.push({ field: 'command', left: leftCmd, right: rightCmd });
|
|
19
|
+
}
|
|
20
|
+
// Compare OS
|
|
21
|
+
if (left.manifest.captured_on.os !== right.manifest.captured_on.os) {
|
|
22
|
+
changes.push({ field: 'os', left: left.manifest.captured_on.os, right: right.manifest.captured_on.os });
|
|
23
|
+
}
|
|
24
|
+
// Compare architecture
|
|
25
|
+
if (left.manifest.captured_on.arch !== right.manifest.captured_on.arch) {
|
|
26
|
+
changes.push({ field: 'arch', left: left.manifest.captured_on.arch, right: right.manifest.captured_on.arch });
|
|
27
|
+
}
|
|
28
|
+
// Compare Node version
|
|
29
|
+
if (left.manifest.captured_on.node_version !== right.manifest.captured_on.node_version) {
|
|
30
|
+
changes.push({
|
|
31
|
+
field: 'node_version',
|
|
32
|
+
left: left.manifest.captured_on.node_version,
|
|
33
|
+
right: right.manifest.captured_on.node_version,
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
// Compare error patterns
|
|
37
|
+
const leftPatterns = JSON.stringify(left.failure.error_patterns);
|
|
38
|
+
const rightPatterns = JSON.stringify(right.failure.error_patterns);
|
|
39
|
+
if (leftPatterns !== rightPatterns) {
|
|
40
|
+
changes.push({
|
|
41
|
+
field: 'error_patterns',
|
|
42
|
+
left: left.failure.error_patterns,
|
|
43
|
+
right: right.failure.error_patterns,
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
// Compare duration (only if significantly different, >20%)
|
|
47
|
+
const durationDiff = Math.abs(left.failure.duration_ms - right.failure.duration_ms);
|
|
48
|
+
const avgDuration = (left.failure.duration_ms + right.failure.duration_ms) / 2;
|
|
49
|
+
if (avgDuration > 0 && durationDiff / avgDuration > 0.2) {
|
|
50
|
+
changes.push({ field: 'duration_ms', left: left.failure.duration_ms, right: right.failure.duration_ms });
|
|
51
|
+
}
|
|
52
|
+
// Compare file lists
|
|
53
|
+
const fileChanges = diffFileEntries(left.files, right.files);
|
|
54
|
+
const hasFileChanges = fileChanges.added.length > 0 || fileChanges.removed.length > 0 || fileChanges.modified.length > 0;
|
|
55
|
+
return {
|
|
56
|
+
identical: changes.length === 0 && !hasFileChanges,
|
|
57
|
+
changes,
|
|
58
|
+
fileChanges: hasFileChanges ? fileChanges : { added: [], removed: [], modified: [] },
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
function diffFileEntries(leftFiles, rightFiles) {
|
|
62
|
+
const leftMap = new Map(leftFiles.map(f => [f.path, f]));
|
|
63
|
+
const rightMap = new Map(rightFiles.map(f => [f.path, f]));
|
|
64
|
+
const added = [];
|
|
65
|
+
const removed = [];
|
|
66
|
+
const modified = [];
|
|
67
|
+
// Files in right but not in left => added
|
|
68
|
+
for (const [path] of rightMap) {
|
|
69
|
+
if (!leftMap.has(path)) {
|
|
70
|
+
added.push(path);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
// Files in left but not in right => removed
|
|
74
|
+
for (const [path] of leftMap) {
|
|
75
|
+
if (!rightMap.has(path)) {
|
|
76
|
+
removed.push(path);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
// Files in both but with different hashes => modified
|
|
80
|
+
for (const [path, leftEntry] of leftMap) {
|
|
81
|
+
const rightEntry = rightMap.get(path);
|
|
82
|
+
if (rightEntry && leftEntry.sha256 !== rightEntry.sha256) {
|
|
83
|
+
modified.push(path);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return { added, removed, modified };
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=engine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine.js","sourceRoot":"","sources":["../../src/diff/engine.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { RunConfig } from '../types/artifact.js';
|
|
2
|
+
import { FailureRecord } from '../types/failure.js';
|
|
3
|
+
export interface ReplayOptions {
|
|
4
|
+
artifactPath: string;
|
|
5
|
+
versionMatch: 'strict' | 'current' | 'branch';
|
|
6
|
+
envOverrides: Record<string, string>;
|
|
7
|
+
/** Git commit from the artifact manifest (used for strict mode) */
|
|
8
|
+
gitCommit?: string;
|
|
9
|
+
/** Git branch from the artifact manifest (used for branch mode) */
|
|
10
|
+
gitBranch?: string;
|
|
11
|
+
sandboxLevel?: 'workspace' | 'isolated' | 'full';
|
|
12
|
+
}
|
|
13
|
+
export interface ReplayResult {
|
|
14
|
+
actualFailure: FailureRecord;
|
|
15
|
+
expectedFailure: FailureRecord;
|
|
16
|
+
actualStdout: string;
|
|
17
|
+
actualStderr: string;
|
|
18
|
+
/** The directory where replay actually ran */
|
|
19
|
+
replayDirectory: string;
|
|
20
|
+
/** Whether the sandbox fell back to artifact file snapshots */
|
|
21
|
+
usedFallback?: boolean;
|
|
22
|
+
/** Sandbox architecture layers applied */
|
|
23
|
+
bugBox?: {
|
|
24
|
+
level: string;
|
|
25
|
+
appliedLayers: string[];
|
|
26
|
+
skippedLayers: string[];
|
|
27
|
+
platform: string;
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Replays a captured artifact in an isolated sandbox.
|
|
32
|
+
*
|
|
33
|
+
* Three modes:
|
|
34
|
+
* - current: runs in cwd (no sandbox, fast)
|
|
35
|
+
* - strict: creates temp dir at the exact git commit, falls back to artifact files/
|
|
36
|
+
* - branch: creates temp dir at the branch tip, falls back to current
|
|
37
|
+
*
|
|
38
|
+
* The sandbox is always cleaned up after the command finishes.
|
|
39
|
+
*/
|
|
40
|
+
export declare function replayArtifact(runConfig: RunConfig, expectedFailure: FailureRecord, options: ReplayOptions): Promise<ReplayResult>;
|
|
41
|
+
//# sourceMappingURL=engine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../src/replay/engine.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAKpD,MAAM,WAAW,aAAa;IAC5B,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,QAAQ,GAAG,SAAS,GAAG,QAAQ,CAAC;IAC9C,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrC,mEAAmE;IACnE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,mEAAmE;IACnE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,WAAW,GAAG,UAAU,GAAG,MAAM,CAAC;CAClD;AAED,MAAM,WAAW,YAAY;IAC3B,aAAa,EAAE,aAAa,CAAC;IAC7B,eAAe,EAAE,aAAa,CAAC;IAC/B,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,8CAA8C;IAC9C,eAAe,EAAE,MAAM,CAAC;IACxB,+DAA+D;IAC/D,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,0CAA0C;IAC1C,MAAM,CAAC,EAAE;QACP,KAAK,EAAE,MAAM,CAAC;QACd,aAAa,EAAE,MAAM,EAAE,CAAC;QACxB,aAAa,EAAE,MAAM,EAAE,CAAC;QACxB,QAAQ,EAAE,MAAM,CAAC;KAClB,CAAC;CACH;AAED;;;;;;;;;GASG;AACH,wBAAsB,cAAc,CAClC,SAAS,EAAE,SAAS,EACpB,eAAe,EAAE,aAAa,EAC9B,OAAO,EAAE,aAAa,GACrB,OAAO,CAAC,YAAY,CAAC,CA0DvB"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { executeAndCapture } from '../capture/engine.js';
|
|
2
|
+
import { createBugBox } from '../sandbox/bugbox.js';
|
|
3
|
+
import { sanitizeArtifactEnvironment } from '../utils/security.js';
|
|
4
|
+
/**
|
|
5
|
+
* Replays a captured artifact in an isolated sandbox.
|
|
6
|
+
*
|
|
7
|
+
* Three modes:
|
|
8
|
+
* - current: runs in cwd (no sandbox, fast)
|
|
9
|
+
* - strict: creates temp dir at the exact git commit, falls back to artifact files/
|
|
10
|
+
* - branch: creates temp dir at the branch tip, falls back to current
|
|
11
|
+
*
|
|
12
|
+
* The sandbox is always cleaned up after the command finishes.
|
|
13
|
+
*/
|
|
14
|
+
export async function replayArtifact(runConfig, expectedFailure, options) {
|
|
15
|
+
// 1. Create the sandbox workspace via Bug-Box orchestrator
|
|
16
|
+
const bugbox = await createBugBox({
|
|
17
|
+
level: options.sandboxLevel || 'workspace',
|
|
18
|
+
command: runConfig.command,
|
|
19
|
+
sandboxOptions: {
|
|
20
|
+
mode: options.versionMatch,
|
|
21
|
+
originalWorkingDir: runConfig.working_directory,
|
|
22
|
+
artifactPath: options.artifactPath,
|
|
23
|
+
gitCommit: options.gitCommit,
|
|
24
|
+
gitBranch: options.gitBranch,
|
|
25
|
+
},
|
|
26
|
+
});
|
|
27
|
+
try {
|
|
28
|
+
// 2. Merge environments — sanitize artifact env to block dangerous overrides
|
|
29
|
+
const safeArtifactEnv = sanitizeArtifactEnvironment(runConfig.environment);
|
|
30
|
+
const replayEnv = {
|
|
31
|
+
...process.env,
|
|
32
|
+
...safeArtifactEnv,
|
|
33
|
+
...options.envOverrides,
|
|
34
|
+
};
|
|
35
|
+
const hostPath = process.env.PATH || process.env.Path || process.env.path;
|
|
36
|
+
if (hostPath) {
|
|
37
|
+
replayEnv.PATH = hostPath;
|
|
38
|
+
if (process.platform === 'win32') {
|
|
39
|
+
replayEnv.Path = hostPath;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
// 3. Re-run the command in the sandbox directory
|
|
43
|
+
const replayConfig = {
|
|
44
|
+
...runConfig,
|
|
45
|
+
...bugbox.runConfigOverrides,
|
|
46
|
+
environment: replayEnv,
|
|
47
|
+
};
|
|
48
|
+
const result = await executeAndCapture(replayConfig);
|
|
49
|
+
return {
|
|
50
|
+
actualFailure: result.failure,
|
|
51
|
+
expectedFailure,
|
|
52
|
+
actualStdout: result.stdout,
|
|
53
|
+
actualStderr: result.stderr,
|
|
54
|
+
replayDirectory: bugbox.sandboxResult.workingDirectory,
|
|
55
|
+
usedFallback: bugbox.sandboxResult.usedFallback,
|
|
56
|
+
bugBox: {
|
|
57
|
+
level: options.sandboxLevel || 'workspace',
|
|
58
|
+
appliedLayers: bugbox.appliedLayers,
|
|
59
|
+
skippedLayers: bugbox.skippedLayers,
|
|
60
|
+
platform: bugbox.capabilities.platform,
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
finally {
|
|
65
|
+
// 4. Always clean up the sandbox
|
|
66
|
+
bugbox.cleanupFn();
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=engine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine.js","sourceRoot":"","sources":["../../src/replay/engine.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAE,YAAY,EAAgB,MAAM,sBAAsB,CAAC;AAClE,OAAO,EAAE,2BAA2B,EAAE,MAAM,sBAAsB,CAAC;AA+BnE;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,SAAoB,EACpB,eAA8B,EAC9B,OAAsB;IAEtB,2DAA2D;IAC3D,MAAM,MAAM,GAAiB,MAAM,YAAY,CAAC;QAC9C,KAAK,EAAE,OAAO,CAAC,YAAY,IAAI,WAAW;QAC1C,OAAO,EAAE,SAAS,CAAC,OAAO;QAC1B,cAAc,EAAE;YACd,IAAI,EAAE,OAAO,CAAC,YAAY;YAC1B,kBAAkB,EAAE,SAAS,CAAC,iBAAiB;YAC/C,YAAY,EAAE,OAAO,CAAC,YAAY;YAClC,SAAS,EAAE,OAAO,CAAC,SAAS;YAC5B,SAAS,EAAE,OAAO,CAAC,SAAS;SAC7B;KACF,CAAC,CAAC;IAEH,IAAI,CAAC;QACH,6EAA6E;QAC7E,MAAM,eAAe,GAAG,2BAA2B,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;QAC3E,MAAM,SAAS,GAAG;YAChB,GAAG,OAAO,CAAC,GAAG;YACd,GAAG,eAAe;YAClB,GAAG,OAAO,CAAC,YAAY;SACE,CAAC;QAE5B,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC;QAC1E,IAAI,QAAQ,EAAE,CAAC;YACb,SAAS,CAAC,IAAI,GAAG,QAAQ,CAAC;YAC1B,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;gBACjC,SAAS,CAAC,IAAI,GAAG,QAAQ,CAAC;YAC5B,CAAC;QACH,CAAC;QAED,iDAAiD;QACjD,MAAM,YAAY,GAAc;YAC9B,GAAG,SAAS;YACZ,GAAG,MAAM,CAAC,kBAAkB;YAC5B,WAAW,EAAE,SAAS;SACvB,CAAC;QAEF,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC,YAAY,CAAC,CAAC;QAErD,OAAO;YACL,aAAa,EAAE,MAAM,CAAC,OAAO;YAC7B,eAAe;YACf,YAAY,EAAE,MAAM,CAAC,MAAM;YAC3B,YAAY,EAAE,MAAM,CAAC,MAAM;YAC3B,eAAe,EAAE,MAAM,CAAC,aAAa,CAAC,gBAAgB;YACtD,YAAY,EAAE,MAAM,CAAC,aAAa,CAAC,YAAY;YAC/C,MAAM,EAAE;gBACN,KAAK,EAAE,OAAO,CAAC,YAAY,IAAI,WAAW;gBAC1C,aAAa,EAAE,MAAM,CAAC,aAAa;gBACnC,aAAa,EAAE,MAAM,CAAC,aAAa;gBACnC,QAAQ,EAAE,MAAM,CAAC,YAAY,CAAC,QAAQ;aACvC;SACF,CAAC;IACJ,CAAC;YAAS,CAAC;QACT,iCAAiC;QACjC,MAAM,CAAC,SAAS,EAAE,CAAC;IACrB,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Replay Sandbox: creates an isolated workspace for deterministic replay.
|
|
3
|
+
*
|
|
4
|
+
* Three modes:
|
|
5
|
+
* - current: run in cwd (no isolation, fast)
|
|
6
|
+
* - strict: git worktree at exact commit, falls back to artifact files/
|
|
7
|
+
* - branch: git worktree at branch tip, falls back to current
|
|
8
|
+
*/
|
|
9
|
+
export interface SandboxOptions {
|
|
10
|
+
mode: 'current' | 'strict' | 'branch';
|
|
11
|
+
originalWorkingDir: string;
|
|
12
|
+
artifactPath: string;
|
|
13
|
+
gitCommit?: string;
|
|
14
|
+
gitBranch?: string;
|
|
15
|
+
/** Optional pre-created directory to place the sandbox into */
|
|
16
|
+
targetDir?: string;
|
|
17
|
+
}
|
|
18
|
+
export interface SandboxResult {
|
|
19
|
+
workingDirectory: string;
|
|
20
|
+
tempDir?: string;
|
|
21
|
+
needsCleanup: boolean;
|
|
22
|
+
/** True when git checkout failed and we fell back to the artifact's files/ snapshot */
|
|
23
|
+
usedFallback?: boolean;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Creates a sandbox workspace for replay.
|
|
27
|
+
*/
|
|
28
|
+
export declare function createSandbox(options: SandboxOptions): Promise<SandboxResult>;
|
|
29
|
+
/**
|
|
30
|
+
* Removes the sandbox temp directory.
|
|
31
|
+
*/
|
|
32
|
+
export declare function cleanupSandbox(result: SandboxResult): void;
|
|
33
|
+
//# sourceMappingURL=sandbox.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sandbox.d.ts","sourceRoot":"","sources":["../../src/replay/sandbox.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAQH,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,SAAS,GAAG,QAAQ,GAAG,QAAQ,CAAC;IACtC,kBAAkB,EAAE,MAAM,CAAC;IAC3B,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,+DAA+D;IAC/D,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,aAAa;IAC5B,gBAAgB,EAAE,MAAM,CAAC;IACzB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,OAAO,CAAC;IACtB,uFAAuF;IACvF,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED;;GAEG;AACH,wBAAsB,aAAa,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC,CAsFnF;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,aAAa,GAAG,IAAI,CA0B1D"}
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Replay Sandbox: creates an isolated workspace for deterministic replay.
|
|
3
|
+
*
|
|
4
|
+
* Three modes:
|
|
5
|
+
* - current: run in cwd (no isolation, fast)
|
|
6
|
+
* - strict: git worktree at exact commit, falls back to artifact files/
|
|
7
|
+
* - branch: git worktree at branch tip, falls back to current
|
|
8
|
+
*/
|
|
9
|
+
import * as fs from 'fs';
|
|
10
|
+
import * as path from 'path';
|
|
11
|
+
import * as os from 'os';
|
|
12
|
+
import { spawnSync } from 'child_process';
|
|
13
|
+
import { isValidGitRef } from '../utils/security.js';
|
|
14
|
+
/**
|
|
15
|
+
* Creates a sandbox workspace for replay.
|
|
16
|
+
*/
|
|
17
|
+
export async function createSandbox(options) {
|
|
18
|
+
// ── current mode: no isolation ──
|
|
19
|
+
if (options.mode === 'current') {
|
|
20
|
+
const tempDir = options.targetDir || fs.mkdtempSync(path.join(os.tmpdir(), 'bugproof-replay-'));
|
|
21
|
+
const artifactFilesDir = path.join(options.artifactPath, 'files');
|
|
22
|
+
if (fs.existsSync(artifactFilesDir)) {
|
|
23
|
+
copyDirRecursive(artifactFilesDir, tempDir);
|
|
24
|
+
return {
|
|
25
|
+
workingDirectory: tempDir,
|
|
26
|
+
tempDir,
|
|
27
|
+
needsCleanup: true,
|
|
28
|
+
usedFallback: true,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
return {
|
|
32
|
+
workingDirectory: options.originalWorkingDir,
|
|
33
|
+
needsCleanup: false,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
// ── branch mode without a branch: fall back to current ──
|
|
37
|
+
if (options.mode === 'branch' && !options.gitBranch) {
|
|
38
|
+
return {
|
|
39
|
+
workingDirectory: options.originalWorkingDir,
|
|
40
|
+
needsCleanup: false,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
// ── strict or branch: try git worktree ──
|
|
44
|
+
const tempDir = options.targetDir || fs.mkdtempSync(path.join(os.tmpdir(), 'bugproof-replay-'));
|
|
45
|
+
// Determine the ref to checkout
|
|
46
|
+
const ref = options.mode === 'strict' ? options.gitCommit : options.gitBranch;
|
|
47
|
+
if (ref) {
|
|
48
|
+
// Security: validate ref before passing to git
|
|
49
|
+
if (!isValidGitRef(ref)) {
|
|
50
|
+
// Invalid ref, skip directly to fallback
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
const worktreeResult = tryGitWorktree(options.originalWorkingDir, tempDir, ref);
|
|
54
|
+
if (worktreeResult.success) {
|
|
55
|
+
return {
|
|
56
|
+
workingDirectory: tempDir,
|
|
57
|
+
tempDir,
|
|
58
|
+
needsCleanup: true,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
// Worktree failed. For strict mode, try a detached checkout clone.
|
|
62
|
+
if (options.mode === 'strict') {
|
|
63
|
+
const cloneResult = tryGitCloneAndCheckout(options.originalWorkingDir, tempDir, ref);
|
|
64
|
+
if (cloneResult.success) {
|
|
65
|
+
return {
|
|
66
|
+
workingDirectory: tempDir,
|
|
67
|
+
tempDir,
|
|
68
|
+
needsCleanup: true,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
// ── Fallback: copy artifact's files/ snapshot into the temp dir ──
|
|
75
|
+
const artifactFilesDir = path.join(options.artifactPath, 'files');
|
|
76
|
+
if (fs.existsSync(artifactFilesDir)) {
|
|
77
|
+
copyDirRecursive(artifactFilesDir, tempDir);
|
|
78
|
+
return {
|
|
79
|
+
workingDirectory: tempDir,
|
|
80
|
+
tempDir,
|
|
81
|
+
needsCleanup: true,
|
|
82
|
+
usedFallback: true,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
// Nothing worked, clean up and fall back to cwd
|
|
86
|
+
if (!options.targetDir) {
|
|
87
|
+
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
88
|
+
}
|
|
89
|
+
return {
|
|
90
|
+
workingDirectory: options.originalWorkingDir,
|
|
91
|
+
needsCleanup: false,
|
|
92
|
+
usedFallback: true,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Removes the sandbox temp directory.
|
|
97
|
+
*/
|
|
98
|
+
export function cleanupSandbox(result) {
|
|
99
|
+
if (!result.needsCleanup || !result.tempDir)
|
|
100
|
+
return;
|
|
101
|
+
try {
|
|
102
|
+
// If it was a worktree, remove it properly first
|
|
103
|
+
const gitDir = path.join(result.tempDir, '.git');
|
|
104
|
+
if (fs.existsSync(gitDir)) {
|
|
105
|
+
const gitContent = fs.readFileSync(gitDir, 'utf-8').trim();
|
|
106
|
+
if (gitContent.startsWith('gitdir:')) {
|
|
107
|
+
// This is a worktree, find the parent repo and remove the worktree
|
|
108
|
+
spawnSync('git', ['worktree', 'remove', '--force', result.tempDir], {
|
|
109
|
+
encoding: 'utf-8',
|
|
110
|
+
timeout: 10000,
|
|
111
|
+
});
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
catch {
|
|
117
|
+
// Fall through to force delete
|
|
118
|
+
}
|
|
119
|
+
try {
|
|
120
|
+
fs.rmSync(result.tempDir, { recursive: true, force: true });
|
|
121
|
+
}
|
|
122
|
+
catch {
|
|
123
|
+
// Best effort cleanup
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
// ── Internal helpers ──
|
|
127
|
+
function tryGitWorktree(repoDir, targetDir, ref) {
|
|
128
|
+
// First verify the ref exists in this repo
|
|
129
|
+
const verify = spawnSync('git', ['rev-parse', '--verify', ref], {
|
|
130
|
+
cwd: repoDir,
|
|
131
|
+
encoding: 'utf-8',
|
|
132
|
+
timeout: 5000,
|
|
133
|
+
});
|
|
134
|
+
if (verify.status !== 0) {
|
|
135
|
+
return { success: false };
|
|
136
|
+
}
|
|
137
|
+
// Create a detached worktree
|
|
138
|
+
const result = spawnSync('git', ['worktree', 'add', '--detach', targetDir, '--', ref], { cwd: repoDir, encoding: 'utf-8', timeout: 30000 });
|
|
139
|
+
return { success: result.status === 0 };
|
|
140
|
+
}
|
|
141
|
+
function tryGitCloneAndCheckout(repoDir, targetDir, commitSha) {
|
|
142
|
+
// Local clone (no network, shares objects via hardlinks)
|
|
143
|
+
const clone = spawnSync('git', ['clone', '--no-checkout', '--shared', repoDir, targetDir], { encoding: 'utf-8', timeout: 30000 });
|
|
144
|
+
if (clone.status !== 0) {
|
|
145
|
+
return { success: false };
|
|
146
|
+
}
|
|
147
|
+
const checkout = spawnSync('git', ['checkout', commitSha], { cwd: targetDir, encoding: 'utf-8', timeout: 10000 });
|
|
148
|
+
return { success: checkout.status === 0 };
|
|
149
|
+
}
|
|
150
|
+
function copyDirRecursive(src, dest) {
|
|
151
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
152
|
+
const entries = fs.readdirSync(src, { withFileTypes: true });
|
|
153
|
+
for (const entry of entries) {
|
|
154
|
+
// Security: skip symlinks to prevent escape attacks
|
|
155
|
+
if (entry.isSymbolicLink())
|
|
156
|
+
continue;
|
|
157
|
+
const srcPath = path.join(src, entry.name);
|
|
158
|
+
const destPath = path.join(dest, entry.name);
|
|
159
|
+
if (entry.isDirectory()) {
|
|
160
|
+
copyDirRecursive(srcPath, destPath);
|
|
161
|
+
}
|
|
162
|
+
else if (entry.isFile()) {
|
|
163
|
+
fs.copyFileSync(srcPath, destPath);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
//# sourceMappingURL=sandbox.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sandbox.js","sourceRoot":"","sources":["../../src/replay/sandbox.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { ReplayResult } from './engine.js';
|
|
2
|
+
export type VerdictStatus = 'confirmed' | 'not_confirmed' | 'blocked_by_env';
|
|
3
|
+
export interface Verdict {
|
|
4
|
+
status: VerdictStatus;
|
|
5
|
+
message: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function generateVerdict(result: ReplayResult): Verdict;
|
|
8
|
+
//# sourceMappingURL=verdict.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verdict.d.ts","sourceRoot":"","sources":["../../src/replay/verdict.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,MAAM,MAAM,aAAa,GAAG,WAAW,GAAG,eAAe,GAAG,gBAAgB,CAAC;AAE7E,MAAM,WAAW,OAAO;IACtB,MAAM,EAAE,aAAa,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAqC7D"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export function generateVerdict(result) {
|
|
2
|
+
const { expectedFailure, actualFailure } = result;
|
|
3
|
+
// 1. Exact Fingerprint Match
|
|
4
|
+
if (expectedFailure.fingerprint === actualFailure.fingerprint) {
|
|
5
|
+
return {
|
|
6
|
+
status: 'confirmed',
|
|
7
|
+
message: 'Reproduction confirmed (exact fingerprint match)'
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
// 2. Fuzzy Pattern Match
|
|
11
|
+
// Check if actual failure shares any of the same error patterns
|
|
12
|
+
const sharedPatterns = actualFailure.error_patterns.filter(p => expectedFailure.error_patterns.includes(p));
|
|
13
|
+
if (sharedPatterns.length > 0) {
|
|
14
|
+
return {
|
|
15
|
+
status: 'confirmed',
|
|
16
|
+
message: `Reproduction confirmed (fuzzy match on patterns: ${sharedPatterns.join(', ')})`
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
// 3. Different exit code, but failed
|
|
20
|
+
if (actualFailure.exit_code !== 0) {
|
|
21
|
+
return {
|
|
22
|
+
status: 'not_confirmed',
|
|
23
|
+
message: `Failed, but with a different error. Expected pattern: ${expectedFailure.error_patterns[0] || 'Unknown'} / Actual pattern: ${actualFailure.error_patterns[0] || 'Unknown'}`
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
// 4. Succeeded
|
|
27
|
+
return {
|
|
28
|
+
status: 'not_confirmed',
|
|
29
|
+
message: 'Command succeeded on replay. The bug did not reproduce.'
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=verdict.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verdict.js","sourceRoot":"","sources":["../../src/replay/verdict.ts"],"names":[],"mappings":"AASA,MAAM,UAAU,eAAe,CAAC,MAAoB;IAClD,MAAM,EAAE,eAAe,EAAE,aAAa,EAAE,GAAG,MAAM,CAAC;IAElD,6BAA6B;IAC7B,IAAI,eAAe,CAAC,WAAW,KAAK,aAAa,CAAC,WAAW,EAAE,CAAC;QAC9D,OAAO;YACL,MAAM,EAAE,WAAW;YACnB,OAAO,EAAE,kDAAkD;SAC5D,CAAC;IACJ,CAAC;IAED,yBAAyB;IACzB,gEAAgE;IAChE,MAAM,cAAc,GAAG,aAAa,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAC7D,eAAe,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC,CAAC,CAC3C,CAAC;IAEF,IAAI,cAAc,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC9B,OAAO;YACL,MAAM,EAAE,WAAW;YACnB,OAAO,EAAE,oDAAoD,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG;SAC1F,CAAC;IACJ,CAAC;IAED,qCAAqC;IACrC,IAAI,aAAa,CAAC,SAAS,KAAK,CAAC,EAAE,CAAC;QAClC,OAAO;YACL,MAAM,EAAE,eAAe;YACvB,OAAO,EAAE,yDAAyD,eAAe,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI,SAAS,sBAAsB,aAAa,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI,SAAS,EAAE;SACrL,CAAC;IACJ,CAAC;IAED,eAAe;IACf,OAAO;QACL,MAAM,EAAE,eAAe;QACvB,OAAO,EAAE,yDAAyD;KACnE,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bug-Box Orchestrator
|
|
3
|
+
*
|
|
4
|
+
* Ties together capabilities, filesystem permissions, network isolation,
|
|
5
|
+
* and the existing replay sandbox into a single easy-to-use interface.
|
|
6
|
+
*/
|
|
7
|
+
import { SandboxResult, SandboxOptions } from '../replay/sandbox.js';
|
|
8
|
+
import { PlatformCapabilities } from './capabilities.js';
|
|
9
|
+
import { IsolatedDirResult } from './filesystem.js';
|
|
10
|
+
import { NetworkStrategy } from './network.js';
|
|
11
|
+
import { ProcessStrategy } from './process.js';
|
|
12
|
+
import { ResourceStrategy, ResourceLimits } from './resources.js';
|
|
13
|
+
import { RunConfig } from '../types/artifact.js';
|
|
14
|
+
export interface BugBoxOptions {
|
|
15
|
+
level: 'workspace' | 'isolated' | 'full';
|
|
16
|
+
sandboxOptions: SandboxOptions;
|
|
17
|
+
command: string[];
|
|
18
|
+
resourceLimits?: ResourceLimits;
|
|
19
|
+
}
|
|
20
|
+
export interface BugBoxResult {
|
|
21
|
+
sandboxResult: SandboxResult;
|
|
22
|
+
capabilities: PlatformCapabilities;
|
|
23
|
+
appliedLayers: string[];
|
|
24
|
+
skippedLayers: string[];
|
|
25
|
+
networkStrategy: NetworkStrategy;
|
|
26
|
+
processStrategy: ProcessStrategy;
|
|
27
|
+
resourceStrategy: ResourceStrategy;
|
|
28
|
+
isolatedDir?: IsolatedDirResult;
|
|
29
|
+
runConfigOverrides: Partial<RunConfig>;
|
|
30
|
+
cleanupFn: () => void;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Creates a Bug-Box environment for replaying an artifact.
|
|
34
|
+
*
|
|
35
|
+
* @param options Level of isolation and underlying sandbox options
|
|
36
|
+
*/
|
|
37
|
+
export declare function createBugBox(options: BugBoxOptions): Promise<BugBoxResult>;
|
|
38
|
+
//# sourceMappingURL=bugbox.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bugbox.d.ts","sourceRoot":"","sources":["../../src/sandbox/bugbox.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,aAAa,EAAE,cAAc,EAAiC,MAAM,sBAAsB,CAAC;AACpG,OAAO,EAAsB,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAC7E,OAAO,EAIL,iBAAiB,EAClB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAKL,eAAe,EAChB,MAAM,cAAc,CAAC;AACtB,OAAO,EAGL,eAAe,EAChB,MAAM,cAAc,CAAC;AACtB,OAAO,EAGL,gBAAgB,EAChB,cAAc,EACf,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAEjD,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,WAAW,GAAG,UAAU,GAAG,MAAM,CAAC;IACzC,cAAc,EAAE,cAAc,CAAC;IAC/B,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,cAAc,CAAC,EAAE,cAAc,CAAC;CACjC;AAED,MAAM,WAAW,YAAY;IAC3B,aAAa,EAAE,aAAa,CAAC;IAC7B,YAAY,EAAE,oBAAoB,CAAC;IACnC,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,eAAe,EAAE,eAAe,CAAC;IACjC,eAAe,EAAE,eAAe,CAAC;IACjC,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,WAAW,CAAC,EAAE,iBAAiB,CAAC;IAChC,kBAAkB,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC;IACvC,SAAS,EAAE,MAAM,IAAI,CAAC;CACvB;AAED;;;;GAIG;AACH,wBAAsB,YAAY,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC,CA2HhF"}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bug-Box Orchestrator
|
|
3
|
+
*
|
|
4
|
+
* Ties together capabilities, filesystem permissions, network isolation,
|
|
5
|
+
* and the existing replay sandbox into a single easy-to-use interface.
|
|
6
|
+
*/
|
|
7
|
+
import { createSandbox, cleanupSandbox } from '../replay/sandbox.js';
|
|
8
|
+
import { detectCapabilities } from './capabilities.js';
|
|
9
|
+
import { createIsolatedDir, lockDirReadOnly, cleanupIsolatedDir, } from './filesystem.js';
|
|
10
|
+
import { selectNetworkStrategy, buildNetworkIsolationArgs, createNetworkCleanup, addFirewallBlockRule, } from './network.js';
|
|
11
|
+
import { selectProcessStrategy, buildProcessIsolationArgs, } from './process.js';
|
|
12
|
+
import { selectResourceStrategy, buildResourceIsolationArgs, } from './resources.js';
|
|
13
|
+
/**
|
|
14
|
+
* Creates a Bug-Box environment for replaying an artifact.
|
|
15
|
+
*
|
|
16
|
+
* @param options Level of isolation and underlying sandbox options
|
|
17
|
+
*/
|
|
18
|
+
export async function createBugBox(options) {
|
|
19
|
+
const caps = detectCapabilities();
|
|
20
|
+
const appliedLayers = [];
|
|
21
|
+
const skippedLayers = [];
|
|
22
|
+
// 1. Fast path: 'workspace' mode (no OS-level isolation, just git worktree)
|
|
23
|
+
if (options.level === 'workspace') {
|
|
24
|
+
const sandboxResult = await createSandbox(options.sandboxOptions);
|
|
25
|
+
return {
|
|
26
|
+
sandboxResult,
|
|
27
|
+
capabilities: caps,
|
|
28
|
+
appliedLayers,
|
|
29
|
+
skippedLayers,
|
|
30
|
+
networkStrategy: 'none',
|
|
31
|
+
processStrategy: 'none',
|
|
32
|
+
resourceStrategy: 'none',
|
|
33
|
+
runConfigOverrides: {
|
|
34
|
+
working_directory: sandboxResult.workingDirectory,
|
|
35
|
+
},
|
|
36
|
+
cleanupFn: () => cleanupSandbox(sandboxResult),
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
// 2. 'isolated' or 'full' mode: start by creating the restricted filesystem structure
|
|
40
|
+
const isolatedDir = createIsolatedDir();
|
|
41
|
+
appliedLayers.push('filesystem');
|
|
42
|
+
// 3. Populate the workspace with source files (via git worktree or fallback)
|
|
43
|
+
const sandboxResult = await createSandbox({
|
|
44
|
+
...options.sandboxOptions,
|
|
45
|
+
targetDir: isolatedDir.workspaceDir, // Force sandbox to use our restricted dir
|
|
46
|
+
});
|
|
47
|
+
// If the sandbox fell back to copying the artifact's files/ snapshot,
|
|
48
|
+
// lock the filesDir read-only to prevent the replayed process from
|
|
49
|
+
// modifying the captured source snapshot.
|
|
50
|
+
if (sandboxResult.usedFallback) {
|
|
51
|
+
lockDirReadOnly(isolatedDir.filesDir);
|
|
52
|
+
}
|
|
53
|
+
const runConfigOverrides = {
|
|
54
|
+
working_directory: sandboxResult.workingDirectory,
|
|
55
|
+
};
|
|
56
|
+
// 4. Network Isolation
|
|
57
|
+
let netStrategy = 'none';
|
|
58
|
+
let netCleanup = () => { };
|
|
59
|
+
const ruleName = `bugbox-net-${Date.now()}`;
|
|
60
|
+
if (options.level === 'isolated' || options.level === 'full') {
|
|
61
|
+
netStrategy = selectNetworkStrategy(caps);
|
|
62
|
+
if (netStrategy === 'none') {
|
|
63
|
+
skippedLayers.push('network: primitive not available on this OS');
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
appliedLayers.push('network');
|
|
67
|
+
const netResult = buildNetworkIsolationArgs(netStrategy, options.command);
|
|
68
|
+
runConfigOverrides.command = netResult.command;
|
|
69
|
+
if (netResult.needsPreExec) {
|
|
70
|
+
const exePath = netResult.command[0];
|
|
71
|
+
// If this fails, we just continue (best effort isolation)
|
|
72
|
+
addFirewallBlockRule(ruleName, exePath);
|
|
73
|
+
}
|
|
74
|
+
netCleanup = createNetworkCleanup(netStrategy, ruleName);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
// 5. Process & Resource Isolation (Only in 'full' mode)
|
|
78
|
+
let procStrategy = 'none';
|
|
79
|
+
let resStrategy = 'none';
|
|
80
|
+
if (options.level === 'full') {
|
|
81
|
+
// Process Isolation
|
|
82
|
+
procStrategy = selectProcessStrategy(caps);
|
|
83
|
+
if (procStrategy === 'none') {
|
|
84
|
+
skippedLayers.push('process: primitive not available on this OS');
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
appliedLayers.push('process');
|
|
88
|
+
runConfigOverrides.command = buildProcessIsolationArgs(procStrategy, runConfigOverrides.command || options.command);
|
|
89
|
+
}
|
|
90
|
+
// Resource Limits
|
|
91
|
+
resStrategy = selectResourceStrategy(caps);
|
|
92
|
+
if (resStrategy === 'none') {
|
|
93
|
+
skippedLayers.push('resources: primitive not available on this OS');
|
|
94
|
+
}
|
|
95
|
+
else if (options.resourceLimits && (options.resourceLimits.maxMemoryMB || options.resourceLimits.maxCpuPercent)) {
|
|
96
|
+
appliedLayers.push('resources');
|
|
97
|
+
runConfigOverrides.command = buildResourceIsolationArgs(resStrategy, runConfigOverrides.command || options.command, options.resourceLimits);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
// 6. Build combined cleanup
|
|
101
|
+
const cleanupFn = () => {
|
|
102
|
+
// 1. Tear down network rules
|
|
103
|
+
netCleanup();
|
|
104
|
+
// 2. Remove git worktree
|
|
105
|
+
cleanupSandbox(sandboxResult);
|
|
106
|
+
// 3. Remove restricted temp directory
|
|
107
|
+
cleanupIsolatedDir(isolatedDir);
|
|
108
|
+
};
|
|
109
|
+
return {
|
|
110
|
+
sandboxResult,
|
|
111
|
+
capabilities: caps,
|
|
112
|
+
appliedLayers,
|
|
113
|
+
skippedLayers,
|
|
114
|
+
networkStrategy: netStrategy,
|
|
115
|
+
processStrategy: procStrategy,
|
|
116
|
+
resourceStrategy: resStrategy,
|
|
117
|
+
isolatedDir,
|
|
118
|
+
runConfigOverrides,
|
|
119
|
+
cleanupFn,
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
//# sourceMappingURL=bugbox.js.map
|