@brainbase-labs/cli 0.25.0-eng1209.6 → 0.25.0-eng1209.8
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/dist/index.js +199 -38
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -36008,7 +36008,7 @@ function padStart(s, n) {
|
|
|
36008
36008
|
// package.json
|
|
36009
36009
|
var package_default = {
|
|
36010
36010
|
name: "@brainbase-labs/cli",
|
|
36011
|
-
version: "0.25.0-eng1209.
|
|
36011
|
+
version: "0.25.0-eng1209.8",
|
|
36012
36012
|
description: "Pack, share, and install agent templates across harnesses (Claude Code, Codex, ...).",
|
|
36013
36013
|
type: "module",
|
|
36014
36014
|
bin: {
|
|
@@ -78492,6 +78492,9 @@ var MAX_CRITERION_EXPLANATION_LENGTH = 16384;
|
|
|
78492
78492
|
var MAX_CRITERION_EVIDENCE_IDS = 100;
|
|
78493
78493
|
var MAX_CRITERION_EVIDENCE_ID_LENGTH = 256;
|
|
78494
78494
|
var MAX_ALLOWED_EVIDENCE_IDS = 1e4;
|
|
78495
|
+
var COMMAND_PROCESS_MARKER_ENV = "BRAINBASE_BENCHMARK_COMMAND_MARKER";
|
|
78496
|
+
var COMMAND_PROCESS_POLL_MS = 10;
|
|
78497
|
+
var COMMAND_PROCESS_CLEANUP_MS = 500;
|
|
78495
78498
|
var RESERVED_WORKSPACE_PATHS = new Set([
|
|
78496
78499
|
".brainbase",
|
|
78497
78500
|
".git",
|
|
@@ -78712,6 +78715,20 @@ var BenchmarkSpecSchema = exports_external.discriminatedUnion("phase", [
|
|
|
78712
78715
|
HydrateSpecSchema,
|
|
78713
78716
|
EvaluateSpecSchema
|
|
78714
78717
|
]).superRefine((value, context) => {
|
|
78718
|
+
if (Object.hasOwn(value.environment, COMMAND_PROCESS_MARKER_ENV)) {
|
|
78719
|
+
context.addIssue({
|
|
78720
|
+
code: exports_external.ZodIssueCode.custom,
|
|
78721
|
+
path: ["environment", COMMAND_PROCESS_MARKER_ENV],
|
|
78722
|
+
message: `${COMMAND_PROCESS_MARKER_ENV} is reserved for command supervision`
|
|
78723
|
+
});
|
|
78724
|
+
}
|
|
78725
|
+
if (value.secret_env.includes(COMMAND_PROCESS_MARKER_ENV)) {
|
|
78726
|
+
context.addIssue({
|
|
78727
|
+
code: exports_external.ZodIssueCode.custom,
|
|
78728
|
+
path: ["secret_env"],
|
|
78729
|
+
message: `${COMMAND_PROCESS_MARKER_ENV} is reserved for command supervision`
|
|
78730
|
+
});
|
|
78731
|
+
}
|
|
78715
78732
|
for (const name of Object.keys(value.environment)) {
|
|
78716
78733
|
if (SENSITIVE_ENV_NAME_RE.test(name)) {
|
|
78717
78734
|
context.addIssue({
|
|
@@ -79920,7 +79937,7 @@ function buildEnvironment(spec, secretNames, additions = {}) {
|
|
|
79920
79937
|
Object.assign(env3, additions);
|
|
79921
79938
|
return env3;
|
|
79922
79939
|
}
|
|
79923
|
-
function redactCommandOutput(data, spec) {
|
|
79940
|
+
function redactCommandOutput(data, spec, additionalSecrets = []) {
|
|
79924
79941
|
let value = data.toString("utf8");
|
|
79925
79942
|
const sensitiveNames = new Set([
|
|
79926
79943
|
...spec.secret_env,
|
|
@@ -79931,6 +79948,10 @@ function redactCommandOutput(data, spec) {
|
|
|
79931
79948
|
if (secret)
|
|
79932
79949
|
value = value.split(secret).join("[REDACTED]");
|
|
79933
79950
|
}
|
|
79951
|
+
for (const secret of additionalSecrets) {
|
|
79952
|
+
if (secret)
|
|
79953
|
+
value = value.split(secret).join("[REDACTED]");
|
|
79954
|
+
}
|
|
79934
79955
|
return Buffer.from(value);
|
|
79935
79956
|
}
|
|
79936
79957
|
function descendantPids(parentPid) {
|
|
@@ -79982,6 +80003,86 @@ function terminate(child) {
|
|
|
79982
80003
|
child.kill("SIGKILL");
|
|
79983
80004
|
}
|
|
79984
80005
|
}
|
|
80006
|
+
function markedProcessPids(marker) {
|
|
80007
|
+
const assignment = `${COMMAND_PROCESS_MARKER_ENV}=${marker}`;
|
|
80008
|
+
if (process.platform === "linux") {
|
|
80009
|
+
const matches2 = [];
|
|
80010
|
+
let entries;
|
|
80011
|
+
try {
|
|
80012
|
+
entries = fs81.readdirSync("/proc");
|
|
80013
|
+
} catch {
|
|
80014
|
+
return matches2;
|
|
80015
|
+
}
|
|
80016
|
+
for (const entry of entries) {
|
|
80017
|
+
if (!/^\d+$/.test(entry))
|
|
80018
|
+
continue;
|
|
80019
|
+
const pid = Number(entry);
|
|
80020
|
+
if (pid === process.pid)
|
|
80021
|
+
continue;
|
|
80022
|
+
try {
|
|
80023
|
+
const environment = fs81.readFileSync(path88.join("/proc", entry, "environ"), "utf8");
|
|
80024
|
+
if (environment.split("\x00").includes(assignment))
|
|
80025
|
+
matches2.push(pid);
|
|
80026
|
+
} catch {}
|
|
80027
|
+
}
|
|
80028
|
+
return matches2;
|
|
80029
|
+
}
|
|
80030
|
+
if (process.platform === "darwin") {
|
|
80031
|
+
try {
|
|
80032
|
+
const output = execFileSync2("ps", ["eww", "-axo", "pid=,command="], {
|
|
80033
|
+
encoding: "utf8",
|
|
80034
|
+
maxBuffer: 16 * 1024 * 1024,
|
|
80035
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
80036
|
+
});
|
|
80037
|
+
const matches2 = [];
|
|
80038
|
+
for (const line of output.split(`
|
|
80039
|
+
`)) {
|
|
80040
|
+
const match = line.match(/^\s*(\d+)\s+(.*)$/);
|
|
80041
|
+
if (!match || !match[2].includes(assignment))
|
|
80042
|
+
continue;
|
|
80043
|
+
const pid = Number(match[1]);
|
|
80044
|
+
if (Number.isInteger(pid) && pid !== process.pid)
|
|
80045
|
+
matches2.push(pid);
|
|
80046
|
+
}
|
|
80047
|
+
return matches2;
|
|
80048
|
+
} catch {
|
|
80049
|
+
return [];
|
|
80050
|
+
}
|
|
80051
|
+
}
|
|
80052
|
+
return [];
|
|
80053
|
+
}
|
|
80054
|
+
function processExists(pid) {
|
|
80055
|
+
try {
|
|
80056
|
+
process.kill(pid, 0);
|
|
80057
|
+
return true;
|
|
80058
|
+
} catch (error2) {
|
|
80059
|
+
return error2.code !== "ESRCH";
|
|
80060
|
+
}
|
|
80061
|
+
}
|
|
80062
|
+
async function terminateCommandProcesses(child, marker, observedDescendants) {
|
|
80063
|
+
if (child.pid !== undefined) {
|
|
80064
|
+
for (const pid of descendantPids(child.pid))
|
|
80065
|
+
observedDescendants.add(pid);
|
|
80066
|
+
}
|
|
80067
|
+
terminate(child);
|
|
80068
|
+
const deadline = Date.now() + COMMAND_PROCESS_CLEANUP_MS;
|
|
80069
|
+
while (true) {
|
|
80070
|
+
for (const pid of markedProcessPids(marker))
|
|
80071
|
+
observedDescendants.add(pid);
|
|
80072
|
+
const active = [...observedDescendants].filter(processExists);
|
|
80073
|
+
for (const pid of active) {
|
|
80074
|
+
try {
|
|
80075
|
+
process.kill(pid, "SIGKILL");
|
|
80076
|
+
} catch {}
|
|
80077
|
+
}
|
|
80078
|
+
if (active.length === 0)
|
|
80079
|
+
return;
|
|
80080
|
+
if (Date.now() >= deadline) {
|
|
80081
|
+
throw new BenchmarkPhaseError("command_cleanup_failed", "command descendants remained after bounded cleanup");
|
|
80082
|
+
}
|
|
80083
|
+
await new Promise((resolve) => setTimeout(resolve, COMMAND_PROCESS_POLL_MS));
|
|
80084
|
+
}
|
|
80085
|
+
}
|
|
79985
80086
|
async function runCommand(command, root, spec, context, additions = {}) {
|
|
79986
80087
|
const cwdRel = normalizedRootRelative(command.cwd);
|
|
79987
80088
|
assertNoSymlinkTraversal(root, cwdRel);
|
|
@@ -80001,27 +80102,56 @@ async function runCommand(command, root, spec, context, additions = {}) {
|
|
|
80001
80102
|
const reachesPhaseDeadline = command.timeout_ms === undefined || command.timeout_ms >= remainingMs;
|
|
80002
80103
|
const timeoutMs2 = reachesPhaseDeadline ? remainingMs : command.timeout_ms;
|
|
80003
80104
|
const started = Date.now();
|
|
80105
|
+
const commandMarker = crypto6.randomBytes(32).toString("hex");
|
|
80004
80106
|
return await new Promise((resolve, reject2) => {
|
|
80005
80107
|
const child = spawn4(command.argv[0], command.argv.slice(1), {
|
|
80006
80108
|
cwd: cwd2,
|
|
80007
|
-
env: buildEnvironment(spec, command.secret_env,
|
|
80109
|
+
env: buildEnvironment(spec, command.secret_env, {
|
|
80110
|
+
...additions,
|
|
80111
|
+
[COMMAND_PROCESS_MARKER_ENV]: commandMarker
|
|
80112
|
+
}),
|
|
80008
80113
|
stdio: ["ignore", "pipe", "pipe"],
|
|
80009
80114
|
detached: process.platform !== "win32"
|
|
80010
80115
|
});
|
|
80011
80116
|
const stdout = [];
|
|
80012
80117
|
const stderr = [];
|
|
80118
|
+
const observedDescendants = new Set;
|
|
80013
80119
|
let captured = 0;
|
|
80014
80120
|
let settled = false;
|
|
80015
80121
|
let timer;
|
|
80122
|
+
let observer;
|
|
80123
|
+
let cleanup;
|
|
80124
|
+
const observeDescendants = () => {
|
|
80125
|
+
if (child.pid === undefined)
|
|
80126
|
+
return;
|
|
80127
|
+
for (const pid of descendantPids(child.pid))
|
|
80128
|
+
observedDescendants.add(pid);
|
|
80129
|
+
};
|
|
80130
|
+
const cleanupProcesses = () => {
|
|
80131
|
+
if (observer)
|
|
80132
|
+
clearInterval(observer);
|
|
80133
|
+
cleanup ??= terminateCommandProcesses(child, commandMarker, observedDescendants);
|
|
80134
|
+
return cleanup;
|
|
80135
|
+
};
|
|
80136
|
+
const sanitizedOutput = (chunks) => redactCommandOutput(Buffer.concat(chunks), spec, [commandMarker]);
|
|
80137
|
+
const sanitizedError = (error2) => {
|
|
80138
|
+
if (!(error2 instanceof BenchmarkCommandExecutionError))
|
|
80139
|
+
return error2;
|
|
80140
|
+
return new BenchmarkCommandExecutionError(error2.code, error2.message, sanitizedOutput(stdout), sanitizedOutput(stderr), error2.durationMs);
|
|
80141
|
+
};
|
|
80016
80142
|
const fail = (error2) => {
|
|
80017
80143
|
if (settled)
|
|
80018
80144
|
return;
|
|
80019
80145
|
settled = true;
|
|
80020
80146
|
if (timer)
|
|
80021
80147
|
clearTimeout(timer);
|
|
80022
|
-
|
|
80023
|
-
reject2(error2);
|
|
80148
|
+
cleanupProcesses().then(() => reject2(sanitizedError(error2)), reject2);
|
|
80024
80149
|
};
|
|
80150
|
+
if (process.platform !== "linux") {
|
|
80151
|
+
observeDescendants();
|
|
80152
|
+
observer = setInterval(observeDescendants, COMMAND_PROCESS_POLL_MS);
|
|
80153
|
+
observer.unref();
|
|
80154
|
+
}
|
|
80025
80155
|
const capture = (target, chunk2) => {
|
|
80026
80156
|
if (settled)
|
|
80027
80157
|
return;
|
|
@@ -80035,6 +80165,11 @@ async function runCommand(command, root, spec, context, additions = {}) {
|
|
|
80035
80165
|
};
|
|
80036
80166
|
child.stdout?.on("data", (chunk2) => capture(stdout, chunk2));
|
|
80037
80167
|
child.stderr?.on("data", (chunk2) => capture(stderr, chunk2));
|
|
80168
|
+
child.once("exit", () => {
|
|
80169
|
+
if (timer)
|
|
80170
|
+
clearTimeout(timer);
|
|
80171
|
+
cleanupProcesses();
|
|
80172
|
+
});
|
|
80038
80173
|
child.on("error", (error2) => {
|
|
80039
80174
|
fail(new BenchmarkCommandExecutionError("command_start_failed", `failed to start ${command.id}: ${error2.message}`, Buffer.concat(stdout), Buffer.concat(stderr), Date.now() - started));
|
|
80040
80175
|
});
|
|
@@ -80050,16 +80185,19 @@ async function runCommand(command, root, spec, context, additions = {}) {
|
|
|
80050
80185
|
return;
|
|
80051
80186
|
settled = true;
|
|
80052
80187
|
clearTimeout(timer);
|
|
80053
|
-
|
|
80054
|
-
|
|
80055
|
-
|
|
80056
|
-
|
|
80057
|
-
|
|
80058
|
-
|
|
80059
|
-
|
|
80060
|
-
|
|
80061
|
-
|
|
80062
|
-
|
|
80188
|
+
cleanupProcesses().then(() => {
|
|
80189
|
+
if (code === null) {
|
|
80190
|
+
reject2(new BenchmarkCommandExecutionError("command_terminated", `command was terminated by ${signal ?? "an unknown signal"}: ${command.id}`, sanitizedOutput(stdout), sanitizedOutput(stderr), Date.now() - started));
|
|
80191
|
+
return;
|
|
80192
|
+
}
|
|
80193
|
+
resolve({
|
|
80194
|
+
exitCode: code,
|
|
80195
|
+
stdout: sanitizedOutput(stdout),
|
|
80196
|
+
stderr: sanitizedOutput(stderr),
|
|
80197
|
+
durationMs: Date.now() - started,
|
|
80198
|
+
redactions: [commandMarker]
|
|
80199
|
+
});
|
|
80200
|
+
}, reject2);
|
|
80063
80201
|
});
|
|
80064
80202
|
});
|
|
80065
80203
|
}
|
|
@@ -80252,6 +80390,13 @@ async function workspaceManifest(spec, context) {
|
|
|
80252
80390
|
}
|
|
80253
80391
|
return records.sort((a3, b4) => a3.path.localeCompare(b4.path));
|
|
80254
80392
|
}
|
|
80393
|
+
async function verifyWorkspaceManifestUnchanged(expected, spec, context) {
|
|
80394
|
+
await verifyRecordsUnchanged(expected, spec);
|
|
80395
|
+
const actual = await workspaceManifest(spec, context);
|
|
80396
|
+
if (JSON.stringify(actual) !== JSON.stringify(expected)) {
|
|
80397
|
+
throw new BenchmarkPhaseError("evidence_tampered", "candidate workspace changed during read-only evaluation");
|
|
80398
|
+
}
|
|
80399
|
+
}
|
|
80255
80400
|
function treeBytes(root, context) {
|
|
80256
80401
|
let totalBytes = 0;
|
|
80257
80402
|
const stack = [path88.resolve(root)];
|
|
@@ -80413,13 +80558,13 @@ async function copyCandidateOutput(output, manifest, spec, context) {
|
|
|
80413
80558
|
}
|
|
80414
80559
|
return copied;
|
|
80415
80560
|
}
|
|
80416
|
-
async function copyFrozenWorkspace(manifest, spec, context) {
|
|
80561
|
+
async function copyFrozenWorkspace(manifest, spec, context, sourceRoot = spec.workspace_root, preserveUnsafeSymlinks = false) {
|
|
80417
80562
|
const destinationRoot = fs81.mkdtempSync(path88.join(os16.tmpdir(), "brainbase-benchmark-workspace-"));
|
|
80418
80563
|
fs81.chmodSync(destinationRoot, 448);
|
|
80419
80564
|
context.temporaryRoots.add(destinationRoot);
|
|
80420
80565
|
for (const frozenFile of manifest) {
|
|
80421
80566
|
assertBudget(context);
|
|
80422
|
-
const source = path88.resolve(
|
|
80567
|
+
const source = path88.resolve(sourceRoot, safeRelPath(frozenFile.path));
|
|
80423
80568
|
const destination = path88.resolve(destinationRoot, safeRelPath(frozenFile.path));
|
|
80424
80569
|
if (frozenFile.kind === "symlink") {
|
|
80425
80570
|
const stat = fs81.lstatSync(source);
|
|
@@ -80427,18 +80572,18 @@ async function copyFrozenWorkspace(manifest, spec, context) {
|
|
|
80427
80572
|
if (target === null || Buffer.byteLength(target) !== frozenFile.size || sha256(target) !== frozenFile.sha256) {
|
|
80428
80573
|
throw new BenchmarkPhaseError("evidence_tampered", `workspace changed after it was frozen: ${frozenFile.path}`);
|
|
80429
80574
|
}
|
|
80430
|
-
if (path88.isAbsolute(target)) {
|
|
80575
|
+
if (!preserveUnsafeSymlinks && path88.isAbsolute(target)) {
|
|
80431
80576
|
throw new BenchmarkPhaseError("unsafe_workspace_symlink", `sandbox evaluator workspace cannot reproduce an absolute symlink: ${frozenFile.path}`);
|
|
80432
80577
|
}
|
|
80433
80578
|
const resolvedTarget = path88.resolve(path88.dirname(source), target);
|
|
80434
|
-
if (!isWithin(
|
|
80579
|
+
if (!preserveUnsafeSymlinks && !isWithin(sourceRoot, resolvedTarget)) {
|
|
80435
80580
|
throw new BenchmarkPhaseError("unsafe_workspace_symlink", `sandbox evaluator workspace symlink escapes the workspace: ${frozenFile.path}`);
|
|
80436
80581
|
}
|
|
80437
80582
|
fs81.mkdirSync(path88.dirname(destination), { recursive: true, mode: 448 });
|
|
80438
80583
|
fs81.symlinkSync(target, destination);
|
|
80439
80584
|
continue;
|
|
80440
80585
|
}
|
|
80441
|
-
await atomicCopy(source, destination, frozenFile.mode,
|
|
80586
|
+
await atomicCopy(source, destination, frozenFile.mode, sourceRoot);
|
|
80442
80587
|
const copied = await recordFile(destinationRoot, destination, "workspace");
|
|
80443
80588
|
if (copied.sha256 !== frozenFile.sha256 || copied.size !== frozenFile.size || copied.mode !== frozenFile.mode) {
|
|
80444
80589
|
throw new BenchmarkPhaseError("evidence_tampered", `workspace changed after it was frozen: ${frozenFile.path}`);
|
|
@@ -80513,7 +80658,7 @@ var CriterionResultSchema = exports_external.object({
|
|
|
80513
80658
|
var CriteriaResultFileSchema = exports_external.object({
|
|
80514
80659
|
criteria: exports_external.array(CriterionResultSchema).max(MAX_CRITERIA_PER_EVALUATOR)
|
|
80515
80660
|
}).strict();
|
|
80516
|
-
function readCriterionResults(resultPath, criterionKeys, allowedEvidenceIds) {
|
|
80661
|
+
function readCriterionResults(resultPath, criterionKeys, allowedEvidenceIds, spec, additionalSecrets = []) {
|
|
80517
80662
|
let opened;
|
|
80518
80663
|
try {
|
|
80519
80664
|
opened = openRegularFileNoFollow(resultPath, "criterion result", path88.dirname(resultPath));
|
|
@@ -80557,7 +80702,13 @@ function readCriterionResults(resultPath, criterionKeys, allowedEvidenceIds) {
|
|
|
80557
80702
|
if (unknownEvidenceIds.length > 0) {
|
|
80558
80703
|
throw new BenchmarkPhaseError("invalid_criterion_result", "criterion result cites evidence outside the evaluator plan", { unknown_evidence_ids: unknownEvidenceIds });
|
|
80559
80704
|
}
|
|
80560
|
-
return criterionKeys.map((key2) =>
|
|
80705
|
+
return criterionKeys.map((key2) => {
|
|
80706
|
+
const criterion = byKey.get(key2);
|
|
80707
|
+
return {
|
|
80708
|
+
...criterion,
|
|
80709
|
+
explanation: redactCommandOutput(Buffer.from(criterion.explanation), spec, additionalSecrets).toString("utf8")
|
|
80710
|
+
};
|
|
80711
|
+
});
|
|
80561
80712
|
} finally {
|
|
80562
80713
|
fs81.closeSync(opened.fd);
|
|
80563
80714
|
}
|
|
@@ -80580,7 +80731,7 @@ function eventType(event) {
|
|
|
80580
80731
|
}
|
|
80581
80732
|
return;
|
|
80582
80733
|
}
|
|
80583
|
-
async function evaluateOne(evaluator, spec, manifest, finalOutput, trajectory, frozenEvidence, context) {
|
|
80734
|
+
async function evaluateOne(evaluator, spec, manifest, frozenWorkspaceRoot, finalOutput, trajectory, frozenEvidence, context) {
|
|
80584
80735
|
const started = Date.now();
|
|
80585
80736
|
const base2 = {
|
|
80586
80737
|
id: evaluator.id,
|
|
@@ -80653,8 +80804,8 @@ async function evaluateOne(evaluator, spec, manifest, finalOutput, trajectory, f
|
|
|
80653
80804
|
}
|
|
80654
80805
|
if (evaluator.type === "workspace_assertion") {
|
|
80655
80806
|
const relative = workspaceRel(evaluator.path);
|
|
80656
|
-
assertNoSymlinkTraversal(
|
|
80657
|
-
const candidate = path88.resolve(
|
|
80807
|
+
assertNoSymlinkTraversal(frozenWorkspaceRoot, relative);
|
|
80808
|
+
const candidate = path88.resolve(frozenWorkspaceRoot, relative);
|
|
80658
80809
|
let stat = null;
|
|
80659
80810
|
try {
|
|
80660
80811
|
stat = fs81.lstatSync(candidate);
|
|
@@ -80675,7 +80826,7 @@ async function evaluateOne(evaluator, spec, manifest, finalOutput, trajectory, f
|
|
|
80675
80826
|
verdict = !exists2;
|
|
80676
80827
|
if (evaluator.assertion.operator === "sha256") {
|
|
80677
80828
|
if (stat?.isFile()) {
|
|
80678
|
-
const opened = openRegularFileNoFollow(candidate, `workspace assertion ${relative}`,
|
|
80829
|
+
const opened = openRegularFileNoFollow(candidate, `workspace assertion ${relative}`, frozenWorkspaceRoot);
|
|
80679
80830
|
try {
|
|
80680
80831
|
actualSha256 = await sha256OfDescriptor(opened.fd);
|
|
80681
80832
|
verdict = actualSha256 === evaluator.assertion.expected;
|
|
@@ -80686,7 +80837,7 @@ async function evaluateOne(evaluator, spec, manifest, finalOutput, trajectory, f
|
|
|
80686
80837
|
}
|
|
80687
80838
|
if (evaluator.assertion.operator === "contains") {
|
|
80688
80839
|
if (stat?.isFile()) {
|
|
80689
|
-
const opened = openRegularFileNoFollow(candidate, `workspace assertion ${relative}`,
|
|
80840
|
+
const opened = openRegularFileNoFollow(candidate, `workspace assertion ${relative}`, frozenWorkspaceRoot);
|
|
80690
80841
|
try {
|
|
80691
80842
|
verdict = readDescriptor(opened.fd).toString("utf8").includes(evaluator.assertion.expected);
|
|
80692
80843
|
} finally {
|
|
@@ -80714,9 +80865,13 @@ async function evaluateOne(evaluator, spec, manifest, finalOutput, trajectory, f
|
|
|
80714
80865
|
let isolatedWorkspace;
|
|
80715
80866
|
let isolatedTestsRoot;
|
|
80716
80867
|
let privateResultRoot;
|
|
80868
|
+
const usesLiveWorkspace = evaluator.workspace_mode === "read_only";
|
|
80717
80869
|
try {
|
|
80718
|
-
const evaluatorWorkspace = await copyFrozenWorkspace(manifest, spec, context);
|
|
80719
|
-
|
|
80870
|
+
const evaluatorWorkspace = usesLiveWorkspace ? spec.workspace_root : await copyFrozenWorkspace(manifest, spec, context, frozenWorkspaceRoot);
|
|
80871
|
+
if (!usesLiveWorkspace)
|
|
80872
|
+
isolatedWorkspace = evaluatorWorkspace;
|
|
80873
|
+
else
|
|
80874
|
+
await verifyWorkspaceManifestUnchanged(manifest, spec, context);
|
|
80720
80875
|
isolatedTestsRoot = await copyEvaluatorTests(spec, context);
|
|
80721
80876
|
const testsPath = evaluatorTestsPath(evaluator, isolatedTestsRoot);
|
|
80722
80877
|
const commandRoot = evaluator.root === "workspace" ? evaluatorWorkspace : isolatedTestsRoot;
|
|
@@ -80741,7 +80896,7 @@ async function evaluateOne(evaluator, spec, manifest, finalOutput, trajectory, f
|
|
|
80741
80896
|
const stderr = await writeLog(spec.logs_root, `${evaluator.id}.stderr.log`, result2.stderr, spec);
|
|
80742
80897
|
let criterionResults;
|
|
80743
80898
|
try {
|
|
80744
|
-
criterionResults = evaluator.criterion_keys && criterionResultPath ? readCriterionResults(criterionResultPath, evaluator.criterion_keys, evaluator.allowed_evidence_ids ?? []) : undefined;
|
|
80899
|
+
criterionResults = evaluator.criterion_keys && criterionResultPath ? readCriterionResults(criterionResultPath, evaluator.criterion_keys, evaluator.allowed_evidence_ids ?? [], spec, result2.redactions) : undefined;
|
|
80745
80900
|
} catch (error2) {
|
|
80746
80901
|
const normalized = stableError(error2);
|
|
80747
80902
|
return {
|
|
@@ -80770,11 +80925,17 @@ async function evaluateOne(evaluator, spec, manifest, finalOutput, trajectory, f
|
|
|
80770
80925
|
...criterionResults ? { criterion_results: criterionResults } : {}
|
|
80771
80926
|
};
|
|
80772
80927
|
} finally {
|
|
80773
|
-
|
|
80774
|
-
if (
|
|
80775
|
-
|
|
80776
|
-
|
|
80777
|
-
|
|
80928
|
+
try {
|
|
80929
|
+
if (usesLiveWorkspace) {
|
|
80930
|
+
await verifyWorkspaceManifestUnchanged(manifest, spec, context);
|
|
80931
|
+
}
|
|
80932
|
+
} finally {
|
|
80933
|
+
for (const temporary of [privateResultRoot, isolatedTestsRoot, isolatedWorkspace]) {
|
|
80934
|
+
if (!temporary)
|
|
80935
|
+
continue;
|
|
80936
|
+
fs81.rmSync(temporary, { recursive: true, force: true });
|
|
80937
|
+
context.temporaryRoots.delete(temporary);
|
|
80938
|
+
}
|
|
80778
80939
|
}
|
|
80779
80940
|
}
|
|
80780
80941
|
}
|
|
@@ -80873,12 +81034,12 @@ async function executeEvaluate(spec, context) {
|
|
|
80873
81034
|
assertEvaluateOutputBudget(spec, context);
|
|
80874
81035
|
}
|
|
80875
81036
|
await verifyRecordsUnchanged(manifest, spec);
|
|
81037
|
+
const frozenWorkspaceRoot = await copyFrozenWorkspace(manifest, spec, context, spec.workspace_root, true);
|
|
80876
81038
|
for (const reference of spec.references) {
|
|
80877
81039
|
const referenceOutputs = await copyMaterial(reference, spec.staging_root, spec.tests_root, "tests", false, context);
|
|
80878
81040
|
outputs.push(...referenceOutputs);
|
|
80879
81041
|
context.outputs.push(...referenceOutputs);
|
|
80880
81042
|
}
|
|
80881
|
-
const frozenOutputCount = context.outputs.length;
|
|
80882
81043
|
const evaluators = [];
|
|
80883
81044
|
const evaluatorOrder = new Map(spec.evaluators.map((evaluator, index) => [evaluator.id, index]));
|
|
80884
81045
|
const executionOrder = [...spec.evaluators].sort((left, right) => Number(left.type === "sandbox_command") - Number(right.type === "sandbox_command"));
|
|
@@ -80886,7 +81047,7 @@ async function executeEvaluate(spec, context) {
|
|
|
80886
81047
|
assertBudget(context);
|
|
80887
81048
|
const started = Date.now();
|
|
80888
81049
|
try {
|
|
80889
|
-
const evaluated = await evaluateOne(evaluator, spec, manifest, finalOutput.buffer.toString("utf8"), trajectory, { finalOutputPath, trajectoryPath }, context);
|
|
81050
|
+
const evaluated = await evaluateOne(evaluator, spec, manifest, frozenWorkspaceRoot, finalOutput.buffer.toString("utf8"), trajectory, { finalOutputPath, trajectoryPath }, context);
|
|
80890
81051
|
assertBudget(context);
|
|
80891
81052
|
evaluators.push(evaluated);
|
|
80892
81053
|
context.evaluators.push(evaluated);
|
|
@@ -80941,7 +81102,7 @@ async function executeEvaluate(spec, context) {
|
|
|
80941
81102
|
assertEvaluateOutputBudget(spec, context);
|
|
80942
81103
|
}
|
|
80943
81104
|
}
|
|
80944
|
-
await verifyRecordsUnchanged([...context.inputs, ...context.outputs
|
|
81105
|
+
await verifyRecordsUnchanged([...context.inputs, ...context.outputs], spec);
|
|
80945
81106
|
if (!verifyOwnedDirectory(spec.tests_root, "tests", spec) || !verifyOwnedDirectory(spec.logs_root, "logs", spec)) {
|
|
80946
81107
|
throw new BenchmarkPhaseError("evidence_tampered", "benchmark evaluator changed an owned phase directory marker");
|
|
80947
81108
|
}
|