bugproof 0.1.2 → 0.2.2
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 +61 -5
- package/README.md +175 -4
- package/dist/capture/env-snapshot.d.ts +53 -0
- package/dist/capture/env-snapshot.d.ts.map +1 -0
- package/dist/capture/env-snapshot.js +122 -0
- package/dist/capture/env-snapshot.js.map +1 -0
- package/dist/capture/language-support.d.ts +55 -0
- package/dist/capture/language-support.d.ts.map +1 -0
- package/dist/capture/language-support.js +505 -0
- package/dist/capture/language-support.js.map +1 -0
- package/dist/capture/packager.d.ts +9 -0
- package/dist/capture/packager.d.ts.map +1 -1
- package/dist/capture/packager.js +23 -2
- package/dist/capture/packager.js.map +1 -1
- package/dist/capture/source-strategy.d.ts +52 -0
- package/dist/capture/source-strategy.d.ts.map +1 -0
- package/dist/capture/source-strategy.js +227 -0
- package/dist/capture/source-strategy.js.map +1 -0
- package/dist/cli.js +373 -12
- package/dist/cli.js.map +1 -1
- package/dist/config/loader.d.ts +44 -0
- package/dist/config/loader.d.ts.map +1 -0
- package/dist/config/loader.js +87 -0
- package/dist/config/loader.js.map +1 -0
- package/dist/replay/engine.d.ts +9 -0
- package/dist/replay/engine.d.ts.map +1 -1
- package/dist/replay/engine.js +29 -3
- package/dist/replay/engine.js.map +1 -1
- package/dist/replay/hints.d.ts +18 -0
- package/dist/replay/hints.d.ts.map +1 -0
- package/dist/replay/hints.js +138 -0
- package/dist/replay/hints.js.map +1 -0
- package/dist/replay/sandbox.js +41 -14
- package/dist/replay/sandbox.js.map +1 -1
- package/dist/replay/verdict.d.ts.map +1 -1
- package/dist/replay/verdict.js +41 -5
- package/dist/replay/verdict.js.map +1 -1
- package/dist/sandbox/bugbox.d.ts.map +1 -1
- package/dist/sandbox/bugbox.js +40 -6
- package/dist/sandbox/bugbox.js.map +1 -1
- package/dist/sandbox/container.d.ts +81 -0
- package/dist/sandbox/container.d.ts.map +1 -0
- package/dist/sandbox/container.js +343 -0
- package/dist/sandbox/container.js.map +1 -0
- package/dist/sandbox/cross-platform.d.ts +59 -0
- package/dist/sandbox/cross-platform.d.ts.map +1 -0
- package/dist/sandbox/cross-platform.js +330 -0
- package/dist/sandbox/cross-platform.js.map +1 -0
- package/dist/sandbox/network.d.ts.map +1 -1
- package/dist/sandbox/network.js +31 -2
- package/dist/sandbox/network.js.map +1 -1
- package/dist/share/gist.d.ts +21 -0
- package/dist/share/gist.d.ts.map +1 -0
- package/dist/share/gist.js +158 -0
- package/dist/share/gist.js.map +1 -0
- package/dist/utils/archive.d.ts +1 -0
- package/dist/utils/archive.d.ts.map +1 -1
- package/dist/utils/archive.js +42 -1
- package/dist/utils/archive.js.map +1 -1
- package/dist/utils/artifact-validation.d.ts +7 -0
- package/dist/utils/artifact-validation.d.ts.map +1 -0
- package/dist/utils/artifact-validation.js +212 -0
- package/dist/utils/artifact-validation.js.map +1 -0
- package/dist/utils/dependencies.d.ts +18 -0
- package/dist/utils/dependencies.d.ts.map +1 -0
- package/dist/utils/dependencies.js +218 -0
- package/dist/utils/dependencies.js.map +1 -0
- package/package.json +3 -2
- package/scripts/postinstall.cjs +38 -5
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Project-level configuration loader.
|
|
3
|
+
* Reads .bugproofrc (JSON) from the project root or any parent directory.
|
|
4
|
+
*/
|
|
5
|
+
export interface BugProofConfig {
|
|
6
|
+
/** Glob patterns to exclude from artifact file capture */
|
|
7
|
+
exclude: string[];
|
|
8
|
+
/** Default artifact output directory (relative to cwd) */
|
|
9
|
+
outputDir: string;
|
|
10
|
+
/** Default timeout in ms */
|
|
11
|
+
timeout: number;
|
|
12
|
+
/** Whether to skip secret scanning */
|
|
13
|
+
skipSecrets: boolean;
|
|
14
|
+
/** Whether to include untracked files */
|
|
15
|
+
includeUntracked: boolean;
|
|
16
|
+
/** Watch mode: auto-capture only on failure (vs always capture) */
|
|
17
|
+
watchOnlyOnFailure: boolean;
|
|
18
|
+
/** Maximum artifact size in MB */
|
|
19
|
+
maxArtifactSizeMB: number;
|
|
20
|
+
/** Custom name template for artifacts (supports {timestamp}, {command}, {exit_code}) */
|
|
21
|
+
nameTemplate: string;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Searches for .bugproofrc from the given directory upwards.
|
|
25
|
+
* Returns the merged config (file values override defaults).
|
|
26
|
+
*/
|
|
27
|
+
export declare function loadConfig(startDir?: string): BugProofConfig;
|
|
28
|
+
/**
|
|
29
|
+
* Finds the nearest .bugproofrc file by walking up from startDir.
|
|
30
|
+
*/
|
|
31
|
+
export declare function findConfigFile(startDir: string): string | null;
|
|
32
|
+
/**
|
|
33
|
+
* Generates a default .bugproofrc content for `bugproof init`.
|
|
34
|
+
*/
|
|
35
|
+
export declare function generateDefaultConfig(): string;
|
|
36
|
+
/**
|
|
37
|
+
* Applies a name template to generate an artifact filename.
|
|
38
|
+
*/
|
|
39
|
+
export declare function applyNameTemplate(template: string, vars: {
|
|
40
|
+
timestamp: number;
|
|
41
|
+
command: string;
|
|
42
|
+
exit_code: number;
|
|
43
|
+
}): string;
|
|
44
|
+
//# sourceMappingURL=loader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../src/config/loader.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,MAAM,WAAW,cAAc;IAC7B,0DAA0D;IAC1D,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,0DAA0D;IAC1D,SAAS,EAAE,MAAM,CAAC;IAClB,4BAA4B;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,sCAAsC;IACtC,WAAW,EAAE,OAAO,CAAC;IACrB,yCAAyC;IACzC,gBAAgB,EAAE,OAAO,CAAC;IAC1B,mEAAmE;IACnE,kBAAkB,EAAE,OAAO,CAAC;IAC5B,kCAAkC;IAClC,iBAAiB,EAAE,MAAM,CAAC;IAC1B,wFAAwF;IACxF,YAAY,EAAE,MAAM,CAAC;CACtB;AAeD;;;GAGG;AACH,wBAAgB,UAAU,CAAC,QAAQ,GAAE,MAAsB,GAAG,cAAc,CAoB3E;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAgB9D;AAED;;GAEG;AACH,wBAAgB,qBAAqB,IAAI,MAAM,CAY9C;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GAC9D,MAAM,CAKR"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Project-level configuration loader.
|
|
3
|
+
* Reads .bugproofrc (JSON) from the project root or any parent directory.
|
|
4
|
+
*/
|
|
5
|
+
import * as fs from 'fs';
|
|
6
|
+
import * as path from 'path';
|
|
7
|
+
const DEFAULTS = {
|
|
8
|
+
exclude: ['node_modules/**', '.git/**', 'dist/**', 'build/**', 'coverage/**', '*.bug'],
|
|
9
|
+
outputDir: '.',
|
|
10
|
+
timeout: 300000,
|
|
11
|
+
skipSecrets: false,
|
|
12
|
+
includeUntracked: false,
|
|
13
|
+
watchOnlyOnFailure: true,
|
|
14
|
+
maxArtifactSizeMB: 50,
|
|
15
|
+
nameTemplate: 'bug_{timestamp}',
|
|
16
|
+
};
|
|
17
|
+
const CONFIG_FILENAME = '.bugproofrc';
|
|
18
|
+
/**
|
|
19
|
+
* Searches for .bugproofrc from the given directory upwards.
|
|
20
|
+
* Returns the merged config (file values override defaults).
|
|
21
|
+
*/
|
|
22
|
+
export function loadConfig(startDir = process.cwd()) {
|
|
23
|
+
const configPath = findConfigFile(startDir);
|
|
24
|
+
if (!configPath) {
|
|
25
|
+
return { ...DEFAULTS };
|
|
26
|
+
}
|
|
27
|
+
try {
|
|
28
|
+
const raw = fs.readFileSync(configPath, 'utf-8');
|
|
29
|
+
const parsed = JSON.parse(raw);
|
|
30
|
+
return {
|
|
31
|
+
...DEFAULTS,
|
|
32
|
+
...parsed,
|
|
33
|
+
// Merge arrays (user's exclude adds to defaults, not replaces)
|
|
34
|
+
exclude: parsed.exclude
|
|
35
|
+
? [...new Set([...DEFAULTS.exclude, ...parsed.exclude])]
|
|
36
|
+
: DEFAULTS.exclude,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
return { ...DEFAULTS };
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Finds the nearest .bugproofrc file by walking up from startDir.
|
|
45
|
+
*/
|
|
46
|
+
export function findConfigFile(startDir) {
|
|
47
|
+
let dir = path.resolve(startDir);
|
|
48
|
+
const root = path.parse(dir).root;
|
|
49
|
+
// eslint-disable-next-line no-constant-condition
|
|
50
|
+
while (true) {
|
|
51
|
+
const candidate = path.join(dir, CONFIG_FILENAME);
|
|
52
|
+
if (fs.existsSync(candidate)) {
|
|
53
|
+
return candidate;
|
|
54
|
+
}
|
|
55
|
+
const parent = path.dirname(dir);
|
|
56
|
+
if (parent === dir || dir === root) {
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
dir = parent;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Generates a default .bugproofrc content for `bugproof init`.
|
|
64
|
+
*/
|
|
65
|
+
export function generateDefaultConfig() {
|
|
66
|
+
const config = {
|
|
67
|
+
exclude: ['node_modules/**', '.git/**', 'dist/**', 'build/**', 'coverage/**', '*.bug'],
|
|
68
|
+
outputDir: '.',
|
|
69
|
+
timeout: 300000,
|
|
70
|
+
skipSecrets: false,
|
|
71
|
+
includeUntracked: false,
|
|
72
|
+
watchOnlyOnFailure: true,
|
|
73
|
+
maxArtifactSizeMB: 50,
|
|
74
|
+
nameTemplate: 'bug_{timestamp}',
|
|
75
|
+
};
|
|
76
|
+
return JSON.stringify(config, null, 2) + '\n';
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Applies a name template to generate an artifact filename.
|
|
80
|
+
*/
|
|
81
|
+
export function applyNameTemplate(template, vars) {
|
|
82
|
+
return template
|
|
83
|
+
.replace('{timestamp}', String(vars.timestamp))
|
|
84
|
+
.replace('{command}', vars.command.replace(/[^a-zA-Z0-9_-]/g, '_').slice(0, 30))
|
|
85
|
+
.replace('{exit_code}', String(vars.exit_code));
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../../src/config/loader.ts"],"names":[],"mappings":"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"}
|
package/dist/replay/engine.d.ts
CHANGED
|
@@ -9,6 +9,8 @@ export interface ReplayOptions {
|
|
|
9
9
|
/** Git branch from the artifact manifest (used for branch mode) */
|
|
10
10
|
gitBranch?: string;
|
|
11
11
|
sandboxLevel?: 'workspace' | 'isolated' | 'full';
|
|
12
|
+
/** Platform the artifact was captured on (for cross-platform translation) */
|
|
13
|
+
capturedPlatform?: string;
|
|
12
14
|
}
|
|
13
15
|
export interface ReplayResult {
|
|
14
16
|
actualFailure: FailureRecord;
|
|
@@ -26,6 +28,13 @@ export interface ReplayResult {
|
|
|
26
28
|
skippedLayers: string[];
|
|
27
29
|
platform: string;
|
|
28
30
|
};
|
|
31
|
+
/** Cross-platform translation info */
|
|
32
|
+
crossPlatform?: {
|
|
33
|
+
needsTranslation: boolean;
|
|
34
|
+
translations: string[];
|
|
35
|
+
warnings: string[];
|
|
36
|
+
blockers: string[];
|
|
37
|
+
};
|
|
29
38
|
}
|
|
30
39
|
/**
|
|
31
40
|
* Replays a captured artifact in an isolated sandbox.
|
|
@@ -1 +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;
|
|
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;AAMpD,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;IACjD,6EAA6E;IAC7E,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;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;IACF,sCAAsC;IACtC,aAAa,CAAC,EAAE;QACd,gBAAgB,EAAE,OAAO,CAAC;QAC1B,YAAY,EAAE,MAAM,EAAE,CAAC;QACvB,QAAQ,EAAE,MAAM,EAAE,CAAC;QACnB,QAAQ,EAAE,MAAM,EAAE,CAAC;KACpB,CAAC;CACH;AAED;;;;;;;;;GASG;AACH,wBAAsB,cAAc,CAClC,SAAS,EAAE,SAAS,EACpB,eAAe,EAAE,aAAa,EAC9B,OAAO,EAAE,aAAa,GACrB,OAAO,CAAC,YAAY,CAAC,CAuFvB"}
|
package/dist/replay/engine.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { executeAndCapture } from '../capture/engine.js';
|
|
2
2
|
import { createBugBox } from '../sandbox/bugbox.js';
|
|
3
3
|
import { sanitizeArtifactEnvironment } from '../utils/security.js';
|
|
4
|
+
import { detectCrossPlatform, translateCommand, translateEnvironment } from '../sandbox/cross-platform.js';
|
|
4
5
|
/**
|
|
5
6
|
* Replays a captured artifact in an isolated sandbox.
|
|
6
7
|
*
|
|
@@ -25,13 +26,31 @@ export async function replayArtifact(runConfig, expectedFailure, options) {
|
|
|
25
26
|
},
|
|
26
27
|
});
|
|
27
28
|
try {
|
|
28
|
-
// 2.
|
|
29
|
+
// 2. Cross-platform detection and translation
|
|
30
|
+
const capturedPlatform = options.capturedPlatform || process.platform;
|
|
31
|
+
const crossPlatform = detectCrossPlatform(capturedPlatform);
|
|
32
|
+
let replayCommand = runConfig.command;
|
|
33
|
+
const allTranslations = [];
|
|
34
|
+
const allBlockers = [];
|
|
35
|
+
if (crossPlatform.needsTranslation) {
|
|
36
|
+
const cmdTranslation = translateCommand(replayCommand, capturedPlatform);
|
|
37
|
+
replayCommand = cmdTranslation.command;
|
|
38
|
+
allTranslations.push(...cmdTranslation.translations);
|
|
39
|
+
allBlockers.push(...cmdTranslation.blockers);
|
|
40
|
+
}
|
|
41
|
+
// 3. Merge environments — sanitize artifact env to block dangerous overrides
|
|
29
42
|
const safeArtifactEnv = sanitizeArtifactEnvironment(runConfig.environment);
|
|
30
|
-
|
|
43
|
+
let replayEnv = {
|
|
31
44
|
...process.env,
|
|
32
45
|
...safeArtifactEnv,
|
|
33
46
|
...options.envOverrides,
|
|
34
47
|
};
|
|
48
|
+
// Apply cross-platform environment translation
|
|
49
|
+
if (crossPlatform.needsTranslation) {
|
|
50
|
+
const envTranslation = translateEnvironment(replayEnv, capturedPlatform);
|
|
51
|
+
replayEnv = envTranslation.environment;
|
|
52
|
+
allTranslations.push(...envTranslation.translations);
|
|
53
|
+
}
|
|
35
54
|
const hostPath = process.env.PATH || process.env.Path || process.env.path;
|
|
36
55
|
if (hostPath) {
|
|
37
56
|
replayEnv.PATH = hostPath;
|
|
@@ -39,10 +58,11 @@ export async function replayArtifact(runConfig, expectedFailure, options) {
|
|
|
39
58
|
replayEnv.Path = hostPath;
|
|
40
59
|
}
|
|
41
60
|
}
|
|
42
|
-
//
|
|
61
|
+
// 4. Re-run the command in the sandbox directory
|
|
43
62
|
const replayConfig = {
|
|
44
63
|
...runConfig,
|
|
45
64
|
...bugbox.runConfigOverrides,
|
|
65
|
+
command: replayCommand,
|
|
46
66
|
environment: replayEnv,
|
|
47
67
|
};
|
|
48
68
|
const result = await executeAndCapture(replayConfig);
|
|
@@ -59,6 +79,12 @@ export async function replayArtifact(runConfig, expectedFailure, options) {
|
|
|
59
79
|
skippedLayers: bugbox.skippedLayers,
|
|
60
80
|
platform: bugbox.capabilities.platform,
|
|
61
81
|
},
|
|
82
|
+
crossPlatform: crossPlatform.needsTranslation ? {
|
|
83
|
+
needsTranslation: true,
|
|
84
|
+
translations: allTranslations,
|
|
85
|
+
warnings: crossPlatform.warnings,
|
|
86
|
+
blockers: allBlockers,
|
|
87
|
+
} : undefined,
|
|
62
88
|
};
|
|
63
89
|
}
|
|
64
90
|
finally {
|
|
@@ -1 +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;
|
|
1
|
+
{"version":3,"file":"engine.js","sourceRoot":"","sources":["../../src/replay/engine.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Smart Hints Engine
|
|
3
|
+
*
|
|
4
|
+
* When a replay produces a DIFFERENT failure than expected, this module
|
|
5
|
+
* analyzes the mismatch and provides actionable suggestions to the developer.
|
|
6
|
+
*/
|
|
7
|
+
import { FailureRecord } from '../types/failure.js';
|
|
8
|
+
export interface Hint {
|
|
9
|
+
category: 'missing_dependency' | 'env_missing' | 'permission' | 'version_mismatch' | 'network' | 'file_not_found' | 'general';
|
|
10
|
+
title: string;
|
|
11
|
+
suggestion: string;
|
|
12
|
+
confidence: 'high' | 'medium' | 'low';
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Analyzes the mismatch between expected and actual failures and generates hints.
|
|
16
|
+
*/
|
|
17
|
+
export declare function generateHints(expected: FailureRecord, actual: FailureRecord, actualStderr: string): Hint[];
|
|
18
|
+
//# sourceMappingURL=hints.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hints.d.ts","sourceRoot":"","sources":["../../src/replay/hints.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEpD,MAAM,WAAW,IAAI;IACnB,QAAQ,EAAE,oBAAoB,GAAG,aAAa,GAAG,YAAY,GAAG,kBAAkB,GAAG,SAAS,GAAG,gBAAgB,GAAG,SAAS,CAAC;IAC9H,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAC;CACvC;AAwGD;;GAEG;AACH,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,aAAa,EACvB,MAAM,EAAE,aAAa,EACrB,YAAY,EAAE,MAAM,GACnB,IAAI,EAAE,CAsCR"}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Smart Hints Engine
|
|
3
|
+
*
|
|
4
|
+
* When a replay produces a DIFFERENT failure than expected, this module
|
|
5
|
+
* analyzes the mismatch and provides actionable suggestions to the developer.
|
|
6
|
+
*/
|
|
7
|
+
const HINT_RULES = [
|
|
8
|
+
// Node.js missing module
|
|
9
|
+
{
|
|
10
|
+
pattern: /Cannot find module ['"]([^'"]+)['"]/,
|
|
11
|
+
category: 'missing_dependency',
|
|
12
|
+
title: 'Missing Node.js module',
|
|
13
|
+
suggestion: (m) => `Install the missing package: npm install ${m[1]}`,
|
|
14
|
+
confidence: 'high',
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
pattern: /Error: Cannot find module '([^']+)'/,
|
|
18
|
+
category: 'missing_dependency',
|
|
19
|
+
title: 'Missing Node.js module',
|
|
20
|
+
suggestion: (m) => `Install the missing package: npm install ${m[1].split('/')[0]}`,
|
|
21
|
+
confidence: 'high',
|
|
22
|
+
},
|
|
23
|
+
// Python missing module
|
|
24
|
+
{
|
|
25
|
+
pattern: /ModuleNotFoundError: No module named '([^']+)'/,
|
|
26
|
+
category: 'missing_dependency',
|
|
27
|
+
title: 'Missing Python module',
|
|
28
|
+
suggestion: (m) => `Install the missing package: pip install ${m[1].replace('.', '-')}`,
|
|
29
|
+
confidence: 'high',
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
pattern: /ImportError: cannot import name '([^']+)' from '([^']+)'/,
|
|
33
|
+
category: 'missing_dependency',
|
|
34
|
+
title: 'Missing Python import',
|
|
35
|
+
suggestion: (m) => `Module '${m[2]}' may need updating: pip install --upgrade ${m[2].split('.')[0]}`,
|
|
36
|
+
confidence: 'medium',
|
|
37
|
+
},
|
|
38
|
+
// Ruby missing gem
|
|
39
|
+
{
|
|
40
|
+
pattern: /cannot load such file -- ([^\s(]+)/,
|
|
41
|
+
category: 'missing_dependency',
|
|
42
|
+
title: 'Missing Ruby gem',
|
|
43
|
+
suggestion: (m) => `Install the missing gem: gem install ${m[1]}`,
|
|
44
|
+
confidence: 'medium',
|
|
45
|
+
},
|
|
46
|
+
// Environment variables
|
|
47
|
+
{
|
|
48
|
+
pattern: /(?:env|environment|variable)\s+['"]?([A-Z_][A-Z0-9_]+)['"]?\s+(?:is not set|not found|undefined|missing)/i,
|
|
49
|
+
category: 'env_missing',
|
|
50
|
+
title: 'Missing environment variable',
|
|
51
|
+
suggestion: (m) => `Set the required environment variable: export ${m[1]}=<value>`,
|
|
52
|
+
confidence: 'high',
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
pattern: /(?:EACCES|EPERM|permission denied)/i,
|
|
56
|
+
category: 'permission',
|
|
57
|
+
title: 'Permission denied',
|
|
58
|
+
suggestion: () => `Check file/directory permissions. You may need elevated privileges or the file may be read-only.`,
|
|
59
|
+
confidence: 'high',
|
|
60
|
+
},
|
|
61
|
+
// Network errors
|
|
62
|
+
{
|
|
63
|
+
pattern: /(?:ECONNREFUSED|ENOTFOUND|ETIMEDOUT|ECONNRESET|EAI_AGAIN)/,
|
|
64
|
+
category: 'network',
|
|
65
|
+
title: 'Network connectivity issue',
|
|
66
|
+
suggestion: () => `A network connection failed. Check that the required service/host is running and accessible.`,
|
|
67
|
+
confidence: 'high',
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
pattern: /(?:401|403)\s*(?:Unauthorized|Forbidden)/i,
|
|
71
|
+
category: 'env_missing',
|
|
72
|
+
title: 'Authentication failure',
|
|
73
|
+
suggestion: () => `Authentication failed. Check that API keys and tokens are correctly set in your environment.`,
|
|
74
|
+
confidence: 'high',
|
|
75
|
+
},
|
|
76
|
+
// File not found
|
|
77
|
+
{
|
|
78
|
+
pattern: /ENOENT[^']*'([^']+)'/i,
|
|
79
|
+
category: 'file_not_found',
|
|
80
|
+
title: 'File or directory not found',
|
|
81
|
+
suggestion: (m) => `File not found: ${m[1]}. Ensure the file exists and the path is correct.`,
|
|
82
|
+
confidence: 'high',
|
|
83
|
+
},
|
|
84
|
+
// Version mismatch
|
|
85
|
+
{
|
|
86
|
+
pattern: /(?:requires|expected|needs)\s+(?:node|python|ruby|java)\s*(?:version\s*)?([><=!~^]+\s*[\d.]+)/i,
|
|
87
|
+
category: 'version_mismatch',
|
|
88
|
+
title: 'Runtime version mismatch',
|
|
89
|
+
suggestion: (m) => `The required version (${m[1]}) doesn't match your installed version. Use a version manager (nvm, pyenv) to switch.`,
|
|
90
|
+
confidence: 'medium',
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
pattern: /(?:SyntaxError|unexpected token).*?\n/i,
|
|
94
|
+
category: 'version_mismatch',
|
|
95
|
+
title: 'Possible syntax/version incompatibility',
|
|
96
|
+
suggestion: () => `A syntax error occurred. This may indicate a Node.js/runtime version mismatch between capture and replay environments.`,
|
|
97
|
+
confidence: 'low',
|
|
98
|
+
},
|
|
99
|
+
];
|
|
100
|
+
/**
|
|
101
|
+
* Analyzes the mismatch between expected and actual failures and generates hints.
|
|
102
|
+
*/
|
|
103
|
+
export function generateHints(expected, actual, actualStderr) {
|
|
104
|
+
const hints = [];
|
|
105
|
+
// If the command succeeded but was expected to fail
|
|
106
|
+
if (actual.exit_code === 0 && expected.exit_code !== 0) {
|
|
107
|
+
hints.push({
|
|
108
|
+
category: 'general',
|
|
109
|
+
title: 'Bug appears to be fixed',
|
|
110
|
+
suggestion: 'The command succeeded on replay. The original bug may have been fixed in the current codebase.',
|
|
111
|
+
confidence: 'high',
|
|
112
|
+
});
|
|
113
|
+
return hints;
|
|
114
|
+
}
|
|
115
|
+
// Analyze actual stderr for actionable patterns
|
|
116
|
+
for (const rule of HINT_RULES) {
|
|
117
|
+
const match = actualStderr.match(rule.pattern);
|
|
118
|
+
if (match) {
|
|
119
|
+
hints.push({
|
|
120
|
+
category: rule.category,
|
|
121
|
+
title: rule.title,
|
|
122
|
+
suggestion: rule.suggestion(match),
|
|
123
|
+
confidence: rule.confidence,
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
// If we have different exit codes but no specific hints, give a general one
|
|
128
|
+
if (hints.length === 0 && actual.exit_code !== expected.exit_code) {
|
|
129
|
+
hints.push({
|
|
130
|
+
category: 'general',
|
|
131
|
+
title: 'Different failure mode',
|
|
132
|
+
suggestion: `Expected exit code ${expected.exit_code} but got ${actual.exit_code}. The bug may have mutated or the environment differs.`,
|
|
133
|
+
confidence: 'low',
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
return hints;
|
|
137
|
+
}
|
|
138
|
+
//# sourceMappingURL=hints.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hints.js","sourceRoot":"","sources":["../../src/replay/hints.ts"],"names":[],"mappings":"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"}
|
package/dist/replay/sandbox.js
CHANGED
|
@@ -17,7 +17,7 @@ import { isValidGitRef } from '../utils/security.js';
|
|
|
17
17
|
export async function createSandbox(options) {
|
|
18
18
|
// ── current mode: no isolation ──
|
|
19
19
|
if (options.mode === 'current') {
|
|
20
|
-
const tempDir = options.targetDir ||
|
|
20
|
+
const tempDir = options.targetDir || createUniqueTempDir();
|
|
21
21
|
const artifactFilesDir = path.join(options.artifactPath, 'files');
|
|
22
22
|
if (fs.existsSync(artifactFilesDir)) {
|
|
23
23
|
copyDirRecursive(artifactFilesDir, tempDir);
|
|
@@ -41,7 +41,7 @@ export async function createSandbox(options) {
|
|
|
41
41
|
};
|
|
42
42
|
}
|
|
43
43
|
// ── strict or branch: try git worktree ──
|
|
44
|
-
const tempDir = options.targetDir ||
|
|
44
|
+
const tempDir = options.targetDir || createUniqueTempDir();
|
|
45
45
|
// Determine the ref to checkout
|
|
46
46
|
const ref = options.mode === 'strict' ? options.gitCommit : options.gitBranch;
|
|
47
47
|
if (ref) {
|
|
@@ -104,24 +104,23 @@ export function cleanupSandbox(result) {
|
|
|
104
104
|
if (fs.existsSync(gitDir)) {
|
|
105
105
|
const gitContent = fs.readFileSync(gitDir, 'utf-8').trim();
|
|
106
106
|
if (gitContent.startsWith('gitdir:')) {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
107
|
+
const repoRoot = resolveWorktreeRepoRoot(gitContent, result.tempDir);
|
|
108
|
+
if (repoRoot) {
|
|
109
|
+
const removeResult = spawnSync('git', ['-C', repoRoot, 'worktree', 'remove', '--force', result.tempDir], {
|
|
110
|
+
encoding: 'utf-8',
|
|
111
|
+
timeout: 10000,
|
|
112
|
+
});
|
|
113
|
+
if (removeResult.status === 0) {
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
113
117
|
}
|
|
114
118
|
}
|
|
115
119
|
}
|
|
116
120
|
catch {
|
|
117
121
|
// Fall through to force delete
|
|
118
122
|
}
|
|
119
|
-
|
|
120
|
-
fs.rmSync(result.tempDir, { recursive: true, force: true });
|
|
121
|
-
}
|
|
122
|
-
catch {
|
|
123
|
-
// Best effort cleanup
|
|
124
|
-
}
|
|
123
|
+
removeDirWithRetry(result.tempDir);
|
|
125
124
|
}
|
|
126
125
|
// ── Internal helpers ──
|
|
127
126
|
function tryGitWorktree(repoDir, targetDir, ref) {
|
|
@@ -147,6 +146,34 @@ function tryGitCloneAndCheckout(repoDir, targetDir, commitSha) {
|
|
|
147
146
|
const checkout = spawnSync('git', ['checkout', commitSha], { cwd: targetDir, encoding: 'utf-8', timeout: 10000 });
|
|
148
147
|
return { success: checkout.status === 0 };
|
|
149
148
|
}
|
|
149
|
+
function createUniqueTempDir() {
|
|
150
|
+
const prefix = `bugproof-replay-${process.pid}-`;
|
|
151
|
+
return fs.mkdtempSync(path.join(os.tmpdir(), prefix));
|
|
152
|
+
}
|
|
153
|
+
function resolveWorktreeRepoRoot(gitFileContent, tempDir) {
|
|
154
|
+
const gitdirPath = gitFileContent.slice('gitdir:'.length).trim();
|
|
155
|
+
if (!gitdirPath) {
|
|
156
|
+
return null;
|
|
157
|
+
}
|
|
158
|
+
const resolvedGitDir = path.resolve(tempDir, gitdirPath);
|
|
159
|
+
const marker = `${path.sep}.git${path.sep}worktrees${path.sep}`;
|
|
160
|
+
const markerIndex = resolvedGitDir.lastIndexOf(marker);
|
|
161
|
+
if (markerIndex < 0) {
|
|
162
|
+
return null;
|
|
163
|
+
}
|
|
164
|
+
return resolvedGitDir.slice(0, markerIndex);
|
|
165
|
+
}
|
|
166
|
+
function removeDirWithRetry(targetDir) {
|
|
167
|
+
for (let i = 0; i < 3; i += 1) {
|
|
168
|
+
try {
|
|
169
|
+
fs.rmSync(targetDir, { recursive: true, force: true });
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
catch {
|
|
173
|
+
// Best-effort retries in case of transient locks.
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
150
177
|
function copyDirRecursive(src, dest) {
|
|
151
178
|
fs.mkdirSync(dest, { recursive: true });
|
|
152
179
|
const entries = fs.readdirSync(src, { withFileTypes: true });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sandbox.js","sourceRoot":"","sources":["../../src/replay/sandbox.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAoBrD;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,OAAuB;IACzD,mCAAmC;IACnC,IAAI,OAAO,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QAC/B,MAAM,OAAO,GAAG,OAAO,CAAC,SAAS,IAAI,
|
|
1
|
+
{"version":3,"file":"sandbox.js","sourceRoot":"","sources":["../../src/replay/sandbox.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +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;
|
|
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;AAgDD,wBAAgB,eAAe,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAmC7D"}
|
package/dist/replay/verdict.js
CHANGED
|
@@ -1,3 +1,39 @@
|
|
|
1
|
+
function normalizePatterns(patterns) {
|
|
2
|
+
return [...new Set(patterns.map((pattern) => pattern.trim()).filter((pattern) => pattern.length > 0))].sort();
|
|
3
|
+
}
|
|
4
|
+
// Recognize core failure tokens: exception names and structured error codes.
|
|
5
|
+
function isCorePattern(pattern) {
|
|
6
|
+
return /^(?:[A-Z][a-zA-Z0-9]+(?:Error|Exception)|ERR_[A-Z0-9_]+|E[A-Z0-9_]{3,})$/.test(pattern);
|
|
7
|
+
}
|
|
8
|
+
function isCodeLikePattern(pattern) {
|
|
9
|
+
return /^(?:ERR_[A-Z0-9_]+|E[A-Z0-9_]{3,})$/.test(pattern);
|
|
10
|
+
}
|
|
11
|
+
function normalizeMessagePattern(pattern) {
|
|
12
|
+
return pattern.trim().replace(/\s+/g, ' ').toLowerCase();
|
|
13
|
+
}
|
|
14
|
+
// Matching strategy:
|
|
15
|
+
// - Core tokens (exception names and real error codes) must line up.
|
|
16
|
+
// - Extra code-like tokens can be tolerated when the same bug still reproduces.
|
|
17
|
+
// - Freeform message fragments only confirm when there are no core tokens at all.
|
|
18
|
+
function hasMatchingSignificantPatterns(expectedPatterns, actualPatterns) {
|
|
19
|
+
const expectedNormalized = normalizePatterns(expectedPatterns);
|
|
20
|
+
const actualNormalized = normalizePatterns(actualPatterns);
|
|
21
|
+
const expectedCore = expectedNormalized.filter(isCorePattern);
|
|
22
|
+
const actualCore = actualNormalized.filter(isCorePattern);
|
|
23
|
+
if (expectedCore.length > 0) {
|
|
24
|
+
if (!expectedCore.every((pattern) => actualCore.includes(pattern))) {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
const extraCorePatterns = actualCore.filter((pattern) => !expectedCore.includes(pattern));
|
|
28
|
+
return extraCorePatterns.every(isCodeLikePattern);
|
|
29
|
+
}
|
|
30
|
+
if (actualCore.length > 0) {
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
const expectedMessages = expectedNormalized.map(normalizeMessagePattern);
|
|
34
|
+
const actualMessages = actualNormalized.map(normalizeMessagePattern);
|
|
35
|
+
return expectedMessages.some((pattern) => actualMessages.includes(pattern));
|
|
36
|
+
}
|
|
1
37
|
export function generateVerdict(result) {
|
|
2
38
|
const { expectedFailure, actualFailure } = result;
|
|
3
39
|
// 1. Exact Fingerprint Match
|
|
@@ -7,13 +43,13 @@ export function generateVerdict(result) {
|
|
|
7
43
|
message: 'Reproduction confirmed (exact fingerprint match)'
|
|
8
44
|
};
|
|
9
45
|
}
|
|
10
|
-
// 2.
|
|
11
|
-
|
|
12
|
-
const
|
|
13
|
-
if (
|
|
46
|
+
// 2. Normalized Pattern Match
|
|
47
|
+
const expectedPatterns = normalizePatterns(expectedFailure.error_patterns);
|
|
48
|
+
const actualPatterns = normalizePatterns(actualFailure.error_patterns);
|
|
49
|
+
if (hasMatchingSignificantPatterns(expectedPatterns, actualPatterns)) {
|
|
14
50
|
return {
|
|
15
51
|
status: 'confirmed',
|
|
16
|
-
message: `Reproduction confirmed (
|
|
52
|
+
message: `Reproduction confirmed (normalized pattern match: ${expectedPatterns.filter(isCorePattern).join(', ') || expectedPatterns.join(', ')})`
|
|
17
53
|
};
|
|
18
54
|
}
|
|
19
55
|
// 3. Different exit code, but failed
|
|
@@ -1 +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,
|
|
1
|
+
{"version":3,"file":"verdict.js","sourceRoot":"","sources":["../../src/replay/verdict.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bugbox.d.ts","sourceRoot":"","sources":["../../src/sandbox/bugbox.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;
|
|
1
|
+
{"version":3,"file":"bugbox.d.ts","sourceRoot":"","sources":["../../src/sandbox/bugbox.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,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,CAgIhF"}
|