reeval 0.0.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/LICENSE +202 -0
- package/THIRD_PARTY_NOTICES.md +2160 -0
- package/assets/package.json +9 -0
- package/assets/pnpm-lock.yaml +1336 -0
- package/dist/agent-DVHkx8aT.js +532 -0
- package/dist/agent-DVHkx8aT.js.map +1 -0
- package/dist/analysis-CxSCt1YY.js +16 -0
- package/dist/analysis-CxSCt1YY.js.map +1 -0
- package/dist/assemble-B-nmz8oH.js +695 -0
- package/dist/assemble-B-nmz8oH.js.map +1 -0
- package/dist/assemble-CmRVDZ2Q.js +2 -0
- package/dist/attempt-BdRQ9jKX.js +176 -0
- package/dist/attempt-BdRQ9jKX.js.map +1 -0
- package/dist/bridge/index.mjs +1911 -0
- package/dist/bridge/package.json +13 -0
- package/dist/bridge/pnpm-lock.yaml +1041 -0
- package/dist/bridge/pnpm-workspace.yaml +2 -0
- package/dist/budget-DBUrH4jX.js +8 -0
- package/dist/budget-DBUrH4jX.js.map +1 -0
- package/dist/cli--CQ3Iy9q.js +1865 -0
- package/dist/cli--CQ3Iy9q.js.map +1 -0
- package/dist/cli-spec-DKAu09Gi.js +478 -0
- package/dist/cli-spec-DKAu09Gi.js.map +1 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +8 -0
- package/dist/cli.js.map +1 -0
- package/dist/colors-QV9dFVhN.js +34 -0
- package/dist/colors-QV9dFVhN.js.map +1 -0
- package/dist/command-BSJzHMtP.js +280 -0
- package/dist/command-BSJzHMtP.js.map +1 -0
- package/dist/command-CEm8PZ1N.js +1043 -0
- package/dist/command-CEm8PZ1N.js.map +1 -0
- package/dist/command-D-jnQWVG.js +673 -0
- package/dist/command-D-jnQWVG.js.map +1 -0
- package/dist/command-DQAvbG7d.js +432 -0
- package/dist/command-DQAvbG7d.js.map +1 -0
- package/dist/commands-A4udfyKZ.js +2 -0
- package/dist/commands-CF8mOfiu.js +207 -0
- package/dist/commands-CF8mOfiu.js.map +1 -0
- package/dist/config-Cuj0kVYj.js +415 -0
- package/dist/config-Cuj0kVYj.js.map +1 -0
- package/dist/context-loi9OCZv.js +106 -0
- package/dist/context-loi9OCZv.js.map +1 -0
- package/dist/core-tLN-z1Be.js +96 -0
- package/dist/core-tLN-z1Be.js.map +1 -0
- package/dist/db-Cjj2ZsfQ.js +2 -0
- package/dist/db-DxDzMhtB.js +827 -0
- package/dist/db-DxDzMhtB.js.map +1 -0
- package/dist/debug-D24NOQH1.js +89 -0
- package/dist/debug-D24NOQH1.js.map +1 -0
- package/dist/debug-SEmW4w8f.js +2 -0
- package/dist/dist-BZXYHN2X.js +1673 -0
- package/dist/dist-BZXYHN2X.js.map +1 -0
- package/dist/docker-DQDZWXF9.js +20 -0
- package/dist/docker-DQDZWXF9.js.map +1 -0
- package/dist/docker-DnWAVdEm.js +2 -0
- package/dist/docker-oSbCExHL.js +153 -0
- package/dist/docker-oSbCExHL.js.map +1 -0
- package/dist/doctor-CxlH1pDM.js +525 -0
- package/dist/doctor-CxlH1pDM.js.map +1 -0
- package/dist/egress-73SQfKdx.js +619 -0
- package/dist/egress-73SQfKdx.js.map +1 -0
- package/dist/env-BQqj93gu.js +21 -0
- package/dist/env-BQqj93gu.js.map +1 -0
- package/dist/environment-Mz7wvrtD.js +552 -0
- package/dist/environment-Mz7wvrtD.js.map +1 -0
- package/dist/errors-C9w_ud7g.js +160 -0
- package/dist/errors-C9w_ud7g.js.map +1 -0
- package/dist/errors-CSxfJ4qu.js +11 -0
- package/dist/errors-CSxfJ4qu.js.map +1 -0
- package/dist/files--6CEUXm7.js +2 -0
- package/dist/files-BLlrhU4-.js +62 -0
- package/dist/files-BLlrhU4-.js.map +1 -0
- package/dist/files-Bd25OAQH.js +2 -0
- package/dist/files-BvHCFWgD.js +2 -0
- package/dist/files-D2-qn_Dl.js +275 -0
- package/dist/files-D2-qn_Dl.js.map +1 -0
- package/dist/files-bF2fPuT9.js +99 -0
- package/dist/files-bF2fPuT9.js.map +1 -0
- package/dist/git-D6hMeieS.js +44 -0
- package/dist/git-D6hMeieS.js.map +1 -0
- package/dist/harness-ls5aX1UO.js +131 -0
- package/dist/harness-ls5aX1UO.js.map +1 -0
- package/dist/harness.d.ts +74 -0
- package/dist/harness.js +2 -0
- package/dist/header-DzFDoMCI.js +78 -0
- package/dist/header-DzFDoMCI.js.map +1 -0
- package/dist/ids-Bp6ut7ZD.js +49 -0
- package/dist/ids-Bp6ut7ZD.js.map +1 -0
- package/dist/images-Cc1-coFc.js +286 -0
- package/dist/images-Cc1-coFc.js.map +1 -0
- package/dist/index.d.ts +97 -0
- package/dist/index.js +1959 -0
- package/dist/index.js.map +1 -0
- package/dist/init-CFljS8BJ.js +344 -0
- package/dist/init-CFljS8BJ.js.map +1 -0
- package/dist/init-z2ZPn9Tj.js +2 -0
- package/dist/invocations-rXktgSAn.js +157 -0
- package/dist/invocations-rXktgSAn.js.map +1 -0
- package/dist/jiti-BOLXpKyG.js +46 -0
- package/dist/jiti-BOLXpKyG.js.map +1 -0
- package/dist/judge-D8Uf4dA9.js +146 -0
- package/dist/judge-D8Uf4dA9.js.map +1 -0
- package/dist/judge.d.ts +21 -0
- package/dist/judge.js +19 -0
- package/dist/judge.js.map +1 -0
- package/dist/live-Bs3LReMV.js +98 -0
- package/dist/live-Bs3LReMV.js.map +1 -0
- package/dist/matchers-DyLvm7EG.js +374 -0
- package/dist/matchers-DyLvm7EG.js.map +1 -0
- package/dist/model-BdO79gWz.js +44 -0
- package/dist/model-BdO79gWz.js.map +1 -0
- package/dist/model-CDL98xue.js +725 -0
- package/dist/model-CDL98xue.js.map +1 -0
- package/dist/model-v-0_Ik7S.js +2 -0
- package/dist/node-kG64XxdE.js +506 -0
- package/dist/node-kG64XxdE.js.map +1 -0
- package/dist/opencode-providers-DZuD_oYt.js +3149 -0
- package/dist/opencode-providers-DZuD_oYt.js.map +1 -0
- package/dist/options-CAQhu--C.js +452 -0
- package/dist/options-CAQhu--C.js.map +1 -0
- package/dist/patch-BkKje4cp.js +69 -0
- package/dist/patch-BkKje4cp.js.map +1 -0
- package/dist/paths-CBvm6pap.js +72 -0
- package/dist/paths-CBvm6pap.js.map +1 -0
- package/dist/plan-gwk6dJ8c.js +237 -0
- package/dist/plan-gwk6dJ8c.js.map +1 -0
- package/dist/preflight-BtubXKQ8.js +2 -0
- package/dist/preflight-BypZMNBG.js +185 -0
- package/dist/preflight-BypZMNBG.js.map +1 -0
- package/dist/prepare-Cwv0bHs_.js +3 -0
- package/dist/prepare-D6Uzcubb.js +213 -0
- package/dist/prepare-D6Uzcubb.js.map +1 -0
- package/dist/provenance-Dfb8YY5Y.js +129 -0
- package/dist/provenance-Dfb8YY5Y.js.map +1 -0
- package/dist/provider-BDbNOQhQ.js +2 -0
- package/dist/provider-CmAYTQQs.js +14 -0
- package/dist/provider-CmAYTQQs.js.map +1 -0
- package/dist/providers-2p3ylMHI.js +107 -0
- package/dist/providers-2p3ylMHI.js.map +1 -0
- package/dist/providers-BUOxitcT.js +2 -0
- package/dist/query-CFATHZmV.js +91 -0
- package/dist/query-CFATHZmV.js.map +1 -0
- package/dist/query-DR4m6CXf.js +2 -0
- package/dist/record-DQ8wzyco.js +99 -0
- package/dist/record-DQ8wzyco.js.map +1 -0
- package/dist/redact-C4fL_bZP.js +167 -0
- package/dist/redact-C4fL_bZP.js.map +1 -0
- package/dist/results-CeXb8Wde.js +37 -0
- package/dist/results-CeXb8Wde.js.map +1 -0
- package/dist/root-CFDjpWuc.js +110 -0
- package/dist/root-CFDjpWuc.js.map +1 -0
- package/dist/sandbox-By2gkdkC.js +133 -0
- package/dist/sandbox-By2gkdkC.js.map +1 -0
- package/dist/sandbox.d.ts +41 -0
- package/dist/sandbox.js +2 -0
- package/dist/server-Bi61uiY0.js +350 -0
- package/dist/server-Bi61uiY0.js.map +1 -0
- package/dist/server-CsSBL8NC.js +2 -0
- package/dist/source-BXzrmof5.js +2 -0
- package/dist/source-Bsfa3LZH.js +40 -0
- package/dist/source-Bsfa3LZH.js.map +1 -0
- package/dist/src-55j1zNHH.js +3 -0
- package/dist/src-AEwxd1UP.js +602 -0
- package/dist/src-AEwxd1UP.js.map +1 -0
- package/dist/src-BDwSuyIo.js +3 -0
- package/dist/src-BQyMiWri.js +490 -0
- package/dist/src-BQyMiWri.js.map +1 -0
- package/dist/src-C-LHyTSV.js +3 -0
- package/dist/src-Cmp-7YrD.js +1136 -0
- package/dist/src-Cmp-7YrD.js.map +1 -0
- package/dist/src-D0RdqpNb.js +252 -0
- package/dist/src-D0RdqpNb.js.map +1 -0
- package/dist/src-D8KYzxBX.js +793 -0
- package/dist/src-D8KYzxBX.js.map +1 -0
- package/dist/src-DEgff9Z7.js +4 -0
- package/dist/src-DXx_29pq.js +567 -0
- package/dist/src-DXx_29pq.js.map +1 -0
- package/dist/src-DwwiVLqv.js +2937 -0
- package/dist/src-DwwiVLqv.js.map +1 -0
- package/dist/src-N7E_mfcZ.js +2 -0
- package/dist/src-W9g-y5X5.js +3 -0
- package/dist/src-daS0wKH2.js +3 -0
- package/dist/state-Cyw3QTsN.js +2 -0
- package/dist/state-DZ7eqb1F.js +167 -0
- package/dist/state-DZ7eqb1F.js.map +1 -0
- package/dist/stats-BNAHlNMD.js +114 -0
- package/dist/stats-BNAHlNMD.js.map +1 -0
- package/dist/studio-app/assets/index-D6XyfFSH.js +58 -0
- package/dist/studio-app/assets/index-xwzWdcE_.css +2 -0
- package/dist/studio-app/favicon.svg +1 -0
- package/dist/studio-app/index.html +15 -0
- package/dist/summary-D7Ttky0z.js +166 -0
- package/dist/summary-D7Ttky0z.js.map +1 -0
- package/dist/text-gEcKjAyp.js +29 -0
- package/dist/text-gEcKjAyp.js.map +1 -0
- package/dist/types-C5vI3g1C.js +9 -0
- package/dist/types-C5vI3g1C.js.map +1 -0
- package/dist/types-DLec-6Cx.d.ts +1535 -0
- package/dist/usage-DsYUqIUM.js +24 -0
- package/dist/usage-DsYUqIUM.js.map +1 -0
- package/dist/view/index.d.ts +645 -0
- package/dist/view/index.js +8 -0
- package/dist/views-BrHOv6wg.js +220 -0
- package/dist/views-BrHOv6wg.js.map +1 -0
- package/dist/views-CwCWLWqo.js +3 -0
- package/dist/worker-entry-DnYkANPG.js +506 -0
- package/dist/worker-entry-DnYkANPG.js.map +1 -0
- package/dist/workspace-C2S0Z6gl.js +327 -0
- package/dist/workspace-C2S0Z6gl.js.map +1 -0
- package/dist/workspace-CyoXG6CY.js +2 -0
- package/docker/Dockerfile +19 -0
- package/package.json +79 -0
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
//#region src/view/record.ts
|
|
2
|
+
const READ_DEFAULTS = {
|
|
3
|
+
"run-record": [
|
|
4
|
+
{
|
|
5
|
+
path: "plan.sandboxWarnings",
|
|
6
|
+
empty: () => []
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
path: "stack.harnesses[].resolvedModels",
|
|
10
|
+
empty: () => []
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
path: "evals[].todo",
|
|
14
|
+
empty: () => false
|
|
15
|
+
}
|
|
16
|
+
],
|
|
17
|
+
"transcript-line": [],
|
|
18
|
+
analysis: [],
|
|
19
|
+
"debug-request": [],
|
|
20
|
+
"live-progress": [],
|
|
21
|
+
"cli-invocation": []
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* Turns a file at schemaVersion `n` into one at `n + 1`, keyed by `n`. A change that can't be a new
|
|
25
|
+
* optional field or a read default bumps the shape's schemaVersion and adds one here.
|
|
26
|
+
*/
|
|
27
|
+
const MIGRATIONS = {};
|
|
28
|
+
/** The newest schemaVersion of each versioned shape this reeval reads. */
|
|
29
|
+
const SCHEMA_VERSIONS = {
|
|
30
|
+
"run-record": 1,
|
|
31
|
+
analysis: 1
|
|
32
|
+
};
|
|
33
|
+
/** A file from a newer reeval, whose schemaVersion this reeval doesn't know. */
|
|
34
|
+
var NewerSchemaError = class extends Error {
|
|
35
|
+
name = "NewerSchemaError";
|
|
36
|
+
/** The message without its subject: `written by a newer reeval (…). Upgrade reeval to read it.` */
|
|
37
|
+
reason;
|
|
38
|
+
constructor(what, version, newest) {
|
|
39
|
+
const reason = `written by a newer reeval (schemaVersion ${version}; this reeval reads up to ${newest}). Upgrade reeval to read it.`;
|
|
40
|
+
super(`${what} was ${reason}`);
|
|
41
|
+
this.reason = reason;
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
const isObject = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
45
|
+
function fill(value, segments, empty) {
|
|
46
|
+
if (!isObject(value)) return;
|
|
47
|
+
const [head = "", ...rest] = segments;
|
|
48
|
+
const branch = /^<(\w+)=(.+)>$/.exec(head);
|
|
49
|
+
if (branch) {
|
|
50
|
+
if (String(value[branch[1]]) === branch[2]) fill(value, rest, empty);
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
const [, key = head, walk] = /^(.+?)(\[\]|\{\})?$/.exec(head) ?? [];
|
|
54
|
+
if (!rest.length && !walk) {
|
|
55
|
+
if (value[key] === void 0) value[key] = empty();
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
const child = value[key];
|
|
59
|
+
const children = walk === "[]" ? Array.isArray(child) ? child : [] : walk === "{}" ? isObject(child) ? Object.values(child) : [] : [child];
|
|
60
|
+
for (const c of children) fill(c, rest, empty);
|
|
61
|
+
}
|
|
62
|
+
/** Fills in each read default of `shape` that `value` is missing, in place. */
|
|
63
|
+
function fillDefaults(shape, value) {
|
|
64
|
+
for (const d of READ_DEFAULTS[shape]) fill(value, d.path.split("."), d.empty);
|
|
65
|
+
return value;
|
|
66
|
+
}
|
|
67
|
+
function upgrade(shape, value, what) {
|
|
68
|
+
const newest = SCHEMA_VERSIONS[shape];
|
|
69
|
+
let version = value.schemaVersion;
|
|
70
|
+
if (typeof version !== "number") return value;
|
|
71
|
+
if (version > newest) throw new NewerSchemaError(what, version, newest);
|
|
72
|
+
let v = value;
|
|
73
|
+
for (; version < newest; version++) {
|
|
74
|
+
const migrate = MIGRATIONS[shape]?.[version];
|
|
75
|
+
if (!migrate) break;
|
|
76
|
+
v = migrate(v);
|
|
77
|
+
}
|
|
78
|
+
return v;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* A record as every reader sees it: migrated to this reeval's schemaVersion, with each field added
|
|
82
|
+
* after it was written read as its default, so older runs keep loading in `reeval show`, `reeval query`,
|
|
83
|
+
* compare, history and the studio. A record from a newer reeval throws a `NewerSchemaError`.
|
|
84
|
+
*/
|
|
85
|
+
function readableRecord(record, what = `Run ${record.runId}`) {
|
|
86
|
+
return fillDefaults("run-record", upgrade("run-record", record, what));
|
|
87
|
+
}
|
|
88
|
+
/** A transcript line as every reader sees it. */
|
|
89
|
+
const readableTranscriptLine = (line) => fillDefaults("transcript-line", line);
|
|
90
|
+
/** An analysis document as every reader sees it; one from a newer reeval throws. */
|
|
91
|
+
const readableAnalysis = (doc, what = "This analysis") => fillDefaults("analysis", upgrade("analysis", doc, what));
|
|
92
|
+
/** A gateway request line from `.reeval/debug` as the studio sees it. */
|
|
93
|
+
const readableDebugRequest = (request) => fillDefaults("debug-request", request);
|
|
94
|
+
/** A line of `.reeval/cli.jsonl` as `reeval report` sees it. */
|
|
95
|
+
const readableCliInvocation = (entry) => fillDefaults("cli-invocation", entry);
|
|
96
|
+
//#endregion
|
|
97
|
+
export { readableDebugRequest as a, readableCliInvocation as i, fillDefaults as n, readableRecord as o, readableAnalysis as r, readableTranscriptLine as s, NewerSchemaError as t };
|
|
98
|
+
|
|
99
|
+
//# sourceMappingURL=record-DQ8wzyco.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"record-DQ8wzyco.js","names":[],"sources":["../src/view/record.ts"],"mappings":";AA4BA,MAAa,gBAAkD;CAC7D,cAAc;EACZ;GAAE,MAAM;GAAwB,aAAa,CAAC;EAAE;EAChD;GAAE,MAAM;GAAoC,aAAa,CAAC;EAAE;EAC5D;GAAE,MAAM;GAAgB,aAAa;EAAM;CAC7C;CACA,mBAAmB,CAAC;CACpB,UAAU,CAAC;CACX,iBAAiB,CAAC;CAClB,iBAAiB,CAAC;CAClB,kBAAkB,CAAC;AACrB;;;;;AAMA,MAAa,aAAoF,CAAC;;AAGlG,MAAa,kBAAkB;CAAE,cAAA;CAA8B,UAAU;AAAE;;AAG3E,IAAa,mBAAb,cAAsC,MAAM;CAC1C,OAAgB;;CAEhB;CACA,YAAY,MAAc,SAAiB,QAAgB;EACzD,MAAM,SAAS,4CAA4C,QAAQ,4BAA4B,OAAO;EACtG,MAAM,GAAG,KAAK,OAAO,QAAQ;EAC7B,KAAK,SAAS;CAChB;AACF;AAGA,MAAM,YAAY,MAAyB,OAAO,MAAM,YAAY,MAAM,QAAQ,CAAC,MAAM,QAAQ,CAAC;AAElG,SAAS,KAAK,OAAgB,UAAoB,OAA4B;CAC5E,IAAI,CAAC,SAAS,KAAK,GAAG;CACtB,MAAM,CAAC,OAAO,IAAI,GAAG,QAAQ;CAC7B,MAAM,SAAS,iBAAiB,KAAK,IAAI;CACzC,IAAI,QAAQ;EACV,IAAI,OAAO,MAAM,OAAO,GAAa,MAAM,OAAO,IAAI,KAAK,OAAO,MAAM,KAAK;EAC7E;CACF;CACA,MAAM,GAAG,MAAM,MAAM,QAAQ,sBAAsB,KAAK,IAAI,KAAK,CAAC;CAClE,IAAI,CAAC,KAAK,UAAU,CAAC,MAAM;EACzB,IAAI,MAAM,SAAS,KAAA,GAAW,MAAM,OAAO,MAAM;EACjD;CACF;CACA,MAAM,QAAQ,MAAM;CACpB,MAAM,WACJ,SAAS,OACL,MAAM,QAAQ,KAAK,IACjB,QACA,CAAC,IACH,SAAS,OACP,SAAS,KAAK,IACZ,OAAO,OAAO,KAAK,IACnB,CAAC,IACH,CAAC,KAAK;CACd,KAAK,MAAM,KAAK,UAAU,KAAK,GAAG,MAAM,KAAK;AAC/C;;AAGA,SAAgB,aAAgB,OAAkB,OAAa;CAC7D,KAAK,MAAM,KAAK,cAAc,QAAQ,KAAK,OAAO,EAAE,KAAK,MAAM,GAAG,GAAG,EAAE,KAAK;CAC5E,OAAO;AACT;AAEA,SAAS,QAAW,OAAqC,OAAU,MAAiB;CAClF,MAAM,SAAS,gBAAgB;CAC/B,IAAI,UAAW,MAAc;CAC7B,IAAI,OAAO,YAAY,UAAU,OAAO;CACxC,IAAI,UAAU,QAAQ,MAAM,IAAI,iBAAiB,MAAM,SAAS,MAAM;CACtE,IAAI,IAAa;CACjB,OAAO,UAAU,QAAQ,WAAW;EAClC,MAAM,UAAU,WAAW,MAAM,GAAG;EACpC,IAAI,CAAC,SAAS;EACd,IAAI,QAAQ,CAAU;CACxB;CACA,OAAO;AACT;;;;;;AAOA,SAAgB,eAAe,QAAmB,OAAO,OAAO,OAAO,SAAoB;CACzF,OAAO,aAAa,cAAc,QAAQ,cAAc,QAAQ,IAAI,CAAC;AACvE;;AAGA,MAAa,0BAA0B,SACrC,aAAa,mBAAmB,IAAI;;AAGtC,MAAa,oBAAoB,KAAkB,OAAO,oBACxD,aAAa,YAAY,QAAQ,YAAY,KAAK,IAAI,CAAC;;AAGzD,MAAa,wBAAwB,YACnC,aAAa,iBAAiB,OAAO;;AAGvC,MAAa,yBAAyB,UACpC,aAAa,kBAAkB,KAAK"}
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
//#region src/redact.ts
|
|
2
|
+
/** What a masked value reads as. */
|
|
3
|
+
const REDACTED = "[REDACTED]";
|
|
4
|
+
const SECRET_NAME = /KEY|TOKEN|SECRET|PASSWORD|CREDENTIAL/i;
|
|
5
|
+
/** Well-known credential shapes, masked even when they aren't in this process's environment. */
|
|
6
|
+
const TOKEN_PATTERNS = [
|
|
7
|
+
/AIza[0-9A-Za-z_-]{35}/g,
|
|
8
|
+
/\bsk-(?:ant-|proj-)?[A-Za-z0-9_-]{20,}/g,
|
|
9
|
+
/\b(?:ghp|gho|ghu|ghs|ghr)_[A-Za-z0-9]{36,}/g,
|
|
10
|
+
/\bgithub_pat_[A-Za-z0-9_]{22,}/g,
|
|
11
|
+
/\b(?:AKIA|ASIA)[0-9A-Z]{16}\b/g,
|
|
12
|
+
/\bxox[abprs]-[A-Za-z0-9-]{10,}/g,
|
|
13
|
+
/\beyJ[A-Za-z0-9_-]{10,}\.eyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}/g,
|
|
14
|
+
/-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z ]*PRIVATE KEY-----/g
|
|
15
|
+
];
|
|
16
|
+
/** Values declared with `secret()`, masked whatever their variable is called. */
|
|
17
|
+
const declared = /* @__PURE__ */ new Set();
|
|
18
|
+
function registerSecret(value) {
|
|
19
|
+
if (value && value.length >= 4) declared.add(value);
|
|
20
|
+
}
|
|
21
|
+
/** Encoded forms shorter than this aren't masked, so they can't eat ordinary text. */
|
|
22
|
+
const MIN_ENCODED = 8;
|
|
23
|
+
/**
|
|
24
|
+
* The stretch of base64 that encodes `value` wherever it starts in a longer input: one per byte
|
|
25
|
+
* offset (0, 1 or 2), without the characters shared with the bytes around it. Plus the URL-safe
|
|
26
|
+
* alphabet of each.
|
|
27
|
+
*/
|
|
28
|
+
function base64Forms(value) {
|
|
29
|
+
const bytes = Buffer.from(value);
|
|
30
|
+
const out = [];
|
|
31
|
+
for (const offset of [
|
|
32
|
+
0,
|
|
33
|
+
1,
|
|
34
|
+
2
|
|
35
|
+
]) {
|
|
36
|
+
const padded = Buffer.concat([Buffer.alloc(offset), bytes]);
|
|
37
|
+
const encoded = padded.toString("base64").replace(/=+$/, "");
|
|
38
|
+
const skip = Math.ceil(offset * 8 / 6);
|
|
39
|
+
const tail = padded.length % 3;
|
|
40
|
+
const keep = Math.floor(padded.length / 3) * 4 + tail;
|
|
41
|
+
const form = encoded.slice(skip, keep);
|
|
42
|
+
out.push(form, form.replaceAll("+", "-").replaceAll("/", "_"));
|
|
43
|
+
}
|
|
44
|
+
return out;
|
|
45
|
+
}
|
|
46
|
+
/** How a value may appear once a client or a log has encoded it: JSON, URL and base64. */
|
|
47
|
+
function encodedForms(value) {
|
|
48
|
+
const forms = [
|
|
49
|
+
jsonEscaped(value),
|
|
50
|
+
encodeURIComponent(value),
|
|
51
|
+
new URLSearchParams({ v: value }).toString().slice(2),
|
|
52
|
+
...base64Forms(value)
|
|
53
|
+
];
|
|
54
|
+
return [...new Set(forms)].filter((f) => f !== value && f.length >= MIN_ENCODED);
|
|
55
|
+
}
|
|
56
|
+
const jsonEscaped = (s) => JSON.stringify(s).slice(1, -1);
|
|
57
|
+
const formsCache = /* @__PURE__ */ new Map();
|
|
58
|
+
/**
|
|
59
|
+
* The value and its encoded forms, each also as it reads inside a JSON string: redaction runs on
|
|
60
|
+
* serialised records, where a JSON-escaped form the agent printed is escaped a second time.
|
|
61
|
+
*/
|
|
62
|
+
const formsOf = (value) => {
|
|
63
|
+
let forms = formsCache.get(value);
|
|
64
|
+
if (!forms) {
|
|
65
|
+
forms = [...new Set([value, ...encodedForms(value)].flatMap((f) => [f, jsonEscaped(f)]))];
|
|
66
|
+
formsCache.set(value, forms);
|
|
67
|
+
}
|
|
68
|
+
return forms;
|
|
69
|
+
};
|
|
70
|
+
/**
|
|
71
|
+
* Whether a secret-named variable's value looks like a credential, so its fragments are masked
|
|
72
|
+
* too. Paths, URLs and prose (`SSH_KEY_PATH=/home/me/.ssh/id_rsa`) would otherwise mask every
|
|
73
|
+
* `/home/me` in the output. Declared secrets of 12 or more characters always count.
|
|
74
|
+
*/
|
|
75
|
+
const tokenLike = (value) => value.length >= 16 && /^[\w.~+/=:-]+$/.test(value) && !/^[/~.]/.test(value) && !value.includes("://") && /[A-Za-z]/.test(value) && /\d/.test(value);
|
|
76
|
+
/** Windows that could be an ordinary word or number (`password`, `20260926`) aren't masked alone. */
|
|
77
|
+
const WORDISH = /^(?:[a-z]+|[A-Z]+|\d+)$/;
|
|
78
|
+
/**
|
|
79
|
+
* Windows with quotes, backslashes, commas, brackets or whitespace aren't masked alone: they can
|
|
80
|
+
* match the structure of serialised JSON (`","sha256":"`) and break the record around them.
|
|
81
|
+
*/
|
|
82
|
+
const STRUCTURAL = /["'\\,:{}[\]\s]/;
|
|
83
|
+
const pairHash = (text, i) => (text.charCodeAt(i) * 31 ^ text.charCodeAt(i + 1)) & 65535;
|
|
84
|
+
let cached;
|
|
85
|
+
function envSecrets(env) {
|
|
86
|
+
const named = Object.entries(env).filter(([name, value]) => SECRET_NAME.test(name) && value && value.length >= 8).map(([, value]) => value);
|
|
87
|
+
const values = [.../* @__PURE__ */ new Set([...named, ...declared])];
|
|
88
|
+
const key = values.map((v) => `${declared.has(v) ? "d" : "n"}${v}`).join("\0");
|
|
89
|
+
if (cached?.key === key) return cached.secrets;
|
|
90
|
+
const forms = [...new Set(values.flatMap(formsOf))].sort((a, b) => b.length - a.length);
|
|
91
|
+
const windows = /* @__PURE__ */ new Set();
|
|
92
|
+
const starts = /* @__PURE__ */ new Uint8Array(65536);
|
|
93
|
+
for (const value of values) {
|
|
94
|
+
if (!(declared.has(value) ? value.length >= 12 : tokenLike(value))) continue;
|
|
95
|
+
for (let i = 0; i + 8 <= value.length; i++) {
|
|
96
|
+
const window = value.slice(i, i + 8);
|
|
97
|
+
if (WORDISH.test(window) || STRUCTURAL.test(window)) continue;
|
|
98
|
+
windows.add(window);
|
|
99
|
+
starts[pairHash(value, i)] = 1;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
const secrets = {
|
|
103
|
+
forms,
|
|
104
|
+
windows,
|
|
105
|
+
starts
|
|
106
|
+
};
|
|
107
|
+
cached = {
|
|
108
|
+
key,
|
|
109
|
+
secrets
|
|
110
|
+
};
|
|
111
|
+
return secrets;
|
|
112
|
+
}
|
|
113
|
+
/** The `[start, end)` stretches of `text` made of some secret's fragments, merged. */
|
|
114
|
+
function fragmentRanges(text, { windows, starts }) {
|
|
115
|
+
const ranges = [];
|
|
116
|
+
if (windows.size === 0) return ranges;
|
|
117
|
+
for (let i = 0; i + 8 <= text.length; i++) {
|
|
118
|
+
if (!starts[pairHash(text, i)] || !windows.has(text.slice(i, i + 8))) continue;
|
|
119
|
+
const last = ranges.at(-1);
|
|
120
|
+
if (last && i <= last[1]) last[1] = i + 8;
|
|
121
|
+
else ranges.push([i, i + 8]);
|
|
122
|
+
}
|
|
123
|
+
return ranges;
|
|
124
|
+
}
|
|
125
|
+
function maskFragments(text, secrets) {
|
|
126
|
+
const ranges = fragmentRanges(text, secrets);
|
|
127
|
+
if (ranges.length === 0) return text;
|
|
128
|
+
let out = "";
|
|
129
|
+
let at = 0;
|
|
130
|
+
for (const [start, end] of ranges) {
|
|
131
|
+
out += `${text.slice(at, start)}${REDACTED}`;
|
|
132
|
+
at = end;
|
|
133
|
+
}
|
|
134
|
+
return out + text.slice(at);
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Masks the values of secret-looking environment variables and declared secrets, raw or
|
|
138
|
+
* JSON-, URL- or base64-encoded, any stretch of `MIN_FRAGMENT` or more of their characters, and
|
|
139
|
+
* well-known token shapes, anywhere in `text`.
|
|
140
|
+
*/
|
|
141
|
+
function redactSecrets(text, env = process.env) {
|
|
142
|
+
const secrets = envSecrets(env);
|
|
143
|
+
let out = text;
|
|
144
|
+
for (const secret of secrets.forms) out = out.replaceAll(secret, REDACTED);
|
|
145
|
+
out = maskFragments(out, secrets);
|
|
146
|
+
for (const pattern of TOKEN_PATTERNS) out = out.replace(pattern, REDACTED);
|
|
147
|
+
return out;
|
|
148
|
+
}
|
|
149
|
+
/** Counts what `redactSecrets` would mask. Used as a last check before anything leaves the machine. */
|
|
150
|
+
function countSecrets(text, env = process.env) {
|
|
151
|
+
const secrets = envSecrets(env);
|
|
152
|
+
let count = 0;
|
|
153
|
+
let rest = text;
|
|
154
|
+
for (const secret of secrets.forms) {
|
|
155
|
+
count += rest.split(secret).length - 1;
|
|
156
|
+
rest = rest.replaceAll(secret, "\0");
|
|
157
|
+
}
|
|
158
|
+
count += fragmentRanges(rest, secrets).length;
|
|
159
|
+
for (const pattern of TOKEN_PATTERNS) count += rest.match(pattern)?.length ?? 0;
|
|
160
|
+
return count;
|
|
161
|
+
}
|
|
162
|
+
/** Drops `user:password@` from a URL so it can be recorded or shown. */
|
|
163
|
+
const stripCredentials = (url) => url.replace(/^([a-z][a-z0-9+.-]*:\/\/)[^@/]*@/i, "$1");
|
|
164
|
+
//#endregion
|
|
165
|
+
export { registerSecret as a, redactSecrets as i, SECRET_NAME as n, stripCredentials as o, countSecrets as r, REDACTED as t };
|
|
166
|
+
|
|
167
|
+
//# sourceMappingURL=redact-C4fL_bZP.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redact-C4fL_bZP.js","names":[],"sources":["../src/redact.ts"],"mappings":"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"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { a as renderSummary } from "./summary-D7Ttky0z.js";
|
|
2
|
+
import { f as scratchDir, m as writeRun } from "./files-D2-qn_Dl.js";
|
|
3
|
+
import { n as assembleRun } from "./assemble-B-nmz8oH.js";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
import { readdir, rm, stat } from "node:fs/promises";
|
|
6
|
+
//#region src/results.ts
|
|
7
|
+
const STALE_STAGING_MS = 864e5;
|
|
8
|
+
/** Where workers write raw per-eval records before the run is assembled. */
|
|
9
|
+
const stagingDir = (root, runId) => join(root, ".reeval", "staging", runId);
|
|
10
|
+
/** Removes staging left behind by runs that were killed before they could clean up. */
|
|
11
|
+
async function sweepStaging(root) {
|
|
12
|
+
const dir = join(root, ".reeval", "staging");
|
|
13
|
+
const entries = await readdir(dir).catch(() => []);
|
|
14
|
+
for (const name of entries) if (await stat(join(dir, name)).then((s) => Date.now() - s.mtimeMs, () => 0) > STALE_STAGING_MS) await rm(join(dir, name), {
|
|
15
|
+
recursive: true,
|
|
16
|
+
force: true
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
/** Assembles the run into `.reeval/runs/`, with every artifact and a summary.md. */
|
|
20
|
+
async function writeScratchRun(input, landed) {
|
|
21
|
+
const { record, artifacts } = await assembleRun(input);
|
|
22
|
+
artifacts.set("summary.md", Buffer.from(renderSummary(record)));
|
|
23
|
+
const written = await writeRun(scratchDir(input.ctx.config.root), record, artifacts);
|
|
24
|
+
landed?.();
|
|
25
|
+
await rm(input.ctx.stagingDir, {
|
|
26
|
+
recursive: true,
|
|
27
|
+
force: true
|
|
28
|
+
});
|
|
29
|
+
return {
|
|
30
|
+
...written,
|
|
31
|
+
record
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
//#endregion
|
|
35
|
+
export { stagingDir, sweepStaging, writeScratchRun };
|
|
36
|
+
|
|
37
|
+
//# sourceMappingURL=results-CeXb8Wde.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"results-CeXb8Wde.js","names":[],"sources":["../src/results.ts"],"mappings":";;;;;;AAOA,MAAM,mBAAmB;;AAGzB,MAAa,cAAc,MAAc,UAAkB,KAAK,MAAM,WAAW,WAAW,KAAK;;AAGjG,eAAsB,aAAa,MAA6B;CAC9D,MAAM,MAAM,KAAK,MAAM,WAAW,SAAS;CAC3C,MAAM,UAAU,MAAM,QAAQ,GAAG,CAAC,CAAC,YAAY,CAAC,CAAC;CACjD,KAAK,MAAM,QAAQ,SAKjB,IAAI,MAJc,KAAK,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,MACrC,MAAM,KAAK,IAAI,IAAI,EAAE,eAChB,CACR,IACU,kBAAkB,MAAM,GAAG,KAAK,KAAK,IAAI,GAAG;EAAE,WAAW;EAAM,OAAO;CAAK,CAAC;AAE1F;;AAGA,eAAsB,gBACpB,OACA,QAC6C;CAC7C,MAAM,EAAE,QAAQ,cAAc,MAAM,YAAY,KAAK;CACrD,UAAU,IAAI,cAAc,OAAO,KAAK,cAAc,MAAM,CAAC,CAAC;CAC9D,MAAM,UAAU,MAAM,SAAS,WAAW,MAAM,IAAI,OAAO,IAAI,GAAG,QAAQ,SAAS;CACnF,SAAS;CACT,MAAM,GAAG,MAAM,IAAI,YAAY;EAAE,WAAW;EAAM,OAAO;CAAK,CAAC;CAC/D,OAAO;EAAE,GAAG;EAAS;CAAO;AAC9B"}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
import { existsSync, mkdirSync, readFileSync, readdirSync, renameSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { homedir } from "node:os";
|
|
4
|
+
import { basename, dirname, join, sep } from "node:path";
|
|
5
|
+
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
6
|
+
import { createHash } from "node:crypto";
|
|
7
|
+
//#region src/root.ts
|
|
8
|
+
const HERE = import.meta.url;
|
|
9
|
+
/**
|
|
10
|
+
* Whether reeval runs as a single-file executable (`bun build --compile`, scripts/bun-compile.mjs).
|
|
11
|
+
* Its own files are embedded in it, in a package's layout, at the root of Bun's virtual
|
|
12
|
+
* filesystem, beside the bundled code.
|
|
13
|
+
*/
|
|
14
|
+
const COMPILED = /^file:\/\/\/(?:\$bunfs|[A-Za-z]:\/~BUN)\//.test(HERE);
|
|
15
|
+
const PACKAGE_DIR = fileURLToPath(new URL(COMPILED ? "./" : "../", HERE));
|
|
16
|
+
const DIST_DIR = join(PACKAGE_DIR, "dist");
|
|
17
|
+
/** One of reeval's own files, by its path in the package (`docker`, `dist/studio-app`, …). */
|
|
18
|
+
const ownFile = (path) => join(PACKAGE_DIR, path);
|
|
19
|
+
/**
|
|
20
|
+
* `ownFile` as a URL; a trailing `/` stays, so the URL resolves names inside the directory.
|
|
21
|
+
* Compiled, a directory is `ownDir`'s copy on disk.
|
|
22
|
+
*/
|
|
23
|
+
function ownFileURL(path) {
|
|
24
|
+
const file = ownFile(path);
|
|
25
|
+
if (!COMPILED || !statSync(file, { throwIfNoEntry: false })?.isDirectory()) return pathToFileURL(file);
|
|
26
|
+
return pathToFileURL(ownDir(path) + (/[\\/]$/.test(path) ? sep : ""));
|
|
27
|
+
}
|
|
28
|
+
const extracted = /* @__PURE__ */ new Map();
|
|
29
|
+
/**
|
|
30
|
+
* One of reeval's own directories, as a real one on disk. Compiled, it's copied out of the
|
|
31
|
+
* executable once, to a cache directory named for its contents: `docker build` and copying the
|
|
32
|
+
* studio app need real files.
|
|
33
|
+
*/
|
|
34
|
+
function ownDir(path) {
|
|
35
|
+
const from = ownFile(path);
|
|
36
|
+
if (!COMPILED) return from;
|
|
37
|
+
const known = extracted.get(from);
|
|
38
|
+
if (known) return known;
|
|
39
|
+
const files = readdirSync(from, {
|
|
40
|
+
recursive: true,
|
|
41
|
+
encoding: "utf8"
|
|
42
|
+
}).filter((f) => statSync(join(from, f)).isFile()).sort();
|
|
43
|
+
const hash = createHash("sha256");
|
|
44
|
+
for (const f of files) hash.update(`${f.replaceAll(sep, "/")}\0`).update(readFileSync(join(from, f)));
|
|
45
|
+
const to = join(cacheDir(), `${basename(from)}-${hash.digest("hex").slice(0, 16)}`);
|
|
46
|
+
if (!existsSync(to)) {
|
|
47
|
+
const partial = `${to}.${process.pid}.partial`;
|
|
48
|
+
for (const f of files) {
|
|
49
|
+
mkdirSync(dirname(join(partial, f)), { recursive: true });
|
|
50
|
+
writeFileSync(join(partial, f), readFileSync(join(from, f)));
|
|
51
|
+
}
|
|
52
|
+
try {
|
|
53
|
+
renameSync(partial, to);
|
|
54
|
+
} catch (error) {
|
|
55
|
+
rmSync(partial, {
|
|
56
|
+
recursive: true,
|
|
57
|
+
force: true
|
|
58
|
+
});
|
|
59
|
+
if (!existsSync(to)) throw error;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
extracted.set(from, to);
|
|
63
|
+
return to;
|
|
64
|
+
}
|
|
65
|
+
/** Where a compiled es keeps what it copies out of itself. */
|
|
66
|
+
function cacheDir() {
|
|
67
|
+
const base = process.env.XDG_CACHE_HOME || (process.platform === "win32" ? process.env.LOCALAPPDATA || join(homedir(), "AppData", "Local") : process.platform === "darwin" ? join(homedir(), "Library", "Caches") : join(homedir(), ".cache"));
|
|
68
|
+
return join(base, "reeval");
|
|
69
|
+
}
|
|
70
|
+
/** `require` as seen from reeval's package: its dependencies and Node's built-ins. */
|
|
71
|
+
const ownRequire = createRequire(ownFile("package.json"));
|
|
72
|
+
let versions;
|
|
73
|
+
/**
|
|
74
|
+
* The version of one of reeval's dependencies, as installed; compiled, as bundled, from the
|
|
75
|
+
* `versions.json` embedded beside its files. Throws for a package it doesn't have.
|
|
76
|
+
*/
|
|
77
|
+
function ownVersion(name) {
|
|
78
|
+
if (!COMPILED) return ownRequire(`${name}/package.json`).version;
|
|
79
|
+
versions ??= JSON.parse(readFileSync(ownFile("versions.json"), "utf8"));
|
|
80
|
+
const version = versions[name];
|
|
81
|
+
if (!version) throw new Error(`Cannot find module '${name}/package.json'`);
|
|
82
|
+
return version;
|
|
83
|
+
}
|
|
84
|
+
const manifest = JSON.parse(readFileSync(ownFile("package.json"), "utf8"));
|
|
85
|
+
/** This reeval's package name and version, from its package.json. */
|
|
86
|
+
const PACKAGE_NAME = manifest.name;
|
|
87
|
+
const PACKAGE_VERSION = manifest.version;
|
|
88
|
+
/** The names a project imports reeval by: the package's, and the monorepo's alias for it. */
|
|
89
|
+
const PACKAGE_NAMES = [.../* @__PURE__ */ new Set([PACKAGE_NAME, "reeval"])];
|
|
90
|
+
/**
|
|
91
|
+
* This build of reeval: its version and its code's mtime. npm gives every installed file the same
|
|
92
|
+
* mtime, so the version tells releases apart; a rebuild moves the mtime.
|
|
93
|
+
*/
|
|
94
|
+
const BUILD_ID = `${PACKAGE_VERSION}:${statSync(COMPILED ? process.execPath : fileURLToPath(HERE)).mtimeMs}`;
|
|
95
|
+
/**
|
|
96
|
+
* The command that runs the `reeval` at `cli` (a package's `dist/cli.js`) with `args`: Node with
|
|
97
|
+
* `nodeArgs` and the file, or, compiled, this executable, which runs its own code.
|
|
98
|
+
*/
|
|
99
|
+
function esCommand(cli, args, nodeArgs = []) {
|
|
100
|
+
return COMPILED ? [process.execPath, ...args] : [
|
|
101
|
+
process.execPath,
|
|
102
|
+
...nodeArgs,
|
|
103
|
+
cli,
|
|
104
|
+
...args
|
|
105
|
+
];
|
|
106
|
+
}
|
|
107
|
+
//#endregion
|
|
108
|
+
export { PACKAGE_NAMES as a, ownDir as c, ownVersion as d, PACKAGE_DIR as i, ownFileURL as l, COMPILED as n, PACKAGE_VERSION as o, DIST_DIR as r, esCommand as s, BUILD_ID as t, ownRequire as u };
|
|
109
|
+
|
|
110
|
+
//# sourceMappingURL=root-CFDjpWuc.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"root-CFDjpWuc.js","names":[],"sources":["../src/root.ts"],"mappings":"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"}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { t as UsageError } from "./errors-CSxfJ4qu.js";
|
|
2
|
+
import { r as callerDir, x as parseDuration } from "./environment-Mz7wvrtD.js";
|
|
3
|
+
import { existsSync, statSync } from "node:fs";
|
|
4
|
+
import { isAbsolute, resolve } from "node:path";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
//#region src/sandbox.ts
|
|
7
|
+
const DOCKER_KEYS = [
|
|
8
|
+
"id",
|
|
9
|
+
"image",
|
|
10
|
+
"from",
|
|
11
|
+
"dockerfile",
|
|
12
|
+
"install",
|
|
13
|
+
"maxConcurrent",
|
|
14
|
+
"root",
|
|
15
|
+
"capabilities",
|
|
16
|
+
"memory",
|
|
17
|
+
"cpus",
|
|
18
|
+
"pids"
|
|
19
|
+
];
|
|
20
|
+
const DOCKER_HINTS = {
|
|
21
|
+
steps: "install",
|
|
22
|
+
run: "install",
|
|
23
|
+
setup: "install",
|
|
24
|
+
image_steps: "install",
|
|
25
|
+
file: "dockerfile",
|
|
26
|
+
build: "dockerfile",
|
|
27
|
+
base: "from",
|
|
28
|
+
user: "root",
|
|
29
|
+
privileged: "root",
|
|
30
|
+
capAdd: "capabilities",
|
|
31
|
+
caps: "capabilities",
|
|
32
|
+
mem: "memory",
|
|
33
|
+
memoryLimit: "memory",
|
|
34
|
+
cpu: "cpus",
|
|
35
|
+
pidsLimit: "pids"
|
|
36
|
+
};
|
|
37
|
+
/** Docker's memory size: bytes, or a number with `b`, `k`, `m` or `g`. */
|
|
38
|
+
const MEMORY = /^\d+(\.\d+)?[bkmg]?$/i;
|
|
39
|
+
function checkConfinement(options) {
|
|
40
|
+
const { root, capabilities, memory, cpus, pids } = options;
|
|
41
|
+
if (root !== void 0 && typeof root !== "boolean") throw new UsageError(`docker({ root }) is true or false (got ${JSON.stringify(root)})`);
|
|
42
|
+
if (capabilities !== void 0 && (!Array.isArray(capabilities) || !capabilities.every((c) => typeof c === "string" && /^(CAP_)?[A-Z_]+$/.test(c)))) throw new UsageError(`docker({ capabilities }) takes Linux capability names, e.g. capabilities: ['NET_RAW'] (got ${JSON.stringify(capabilities)})`);
|
|
43
|
+
if (memory !== void 0 && !(typeof memory === "number" ? Number.isInteger(memory) && memory > 0 : MEMORY.test(memory))) throw new UsageError(`docker({ memory }) takes a size such as '4g' or '512m', or bytes (got ${JSON.stringify(memory)})`);
|
|
44
|
+
if (cpus !== void 0 && !(typeof cpus === "number" && cpus > 0 && Number.isFinite(cpus))) throw new UsageError(`docker({ cpus }) takes a number of CPUs above zero, e.g. 1.5 (got ${JSON.stringify(cpus)})`);
|
|
45
|
+
if (pids !== void 0 && !(Number.isInteger(pids) && pids > 0)) throw new UsageError(`docker({ pids }) takes a whole number of processes above zero (got ${JSON.stringify(pids)})`);
|
|
46
|
+
}
|
|
47
|
+
function checkInstall(install) {
|
|
48
|
+
if (!Array.isArray(install) || install.length === 0) throw new UsageError(`docker({ install }) takes a non-empty list of shell commands, e.g. install: ['apt-get update && apt-get install -y jq'] (got ${JSON.stringify(install)})`);
|
|
49
|
+
for (const step of install) {
|
|
50
|
+
const run = typeof step === "string" ? step : step?.run;
|
|
51
|
+
const timeout = typeof step === "string" ? void 0 : step.timeout;
|
|
52
|
+
if (typeof run !== "string" || !run.trim()) throw new UsageError(`docker({ install }) commands are strings or { run, timeout? } objects (got ${JSON.stringify(step)})`);
|
|
53
|
+
if (timeout === void 0) continue;
|
|
54
|
+
try {
|
|
55
|
+
parseDuration(timeout);
|
|
56
|
+
} catch (error) {
|
|
57
|
+
throw new UsageError(`docker({ install }) command "${run}": ${error.message}`);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return structuredClone(install);
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* One local Docker container per attempt. By default it's the image `reeval image build` makes. One
|
|
64
|
+
* base at most:
|
|
65
|
+
*
|
|
66
|
+
* - `image`: another image that already has the harness baked in, used as is.
|
|
67
|
+
* - `from`: a Debian or Ubuntu based toolchain image (e.g. `python:3.12-slim`); reeval bakes Node and
|
|
68
|
+
* the harness on top on first use.
|
|
69
|
+
* - `dockerfile`: your Dockerfile, built with `docker build` from its directory. Start it
|
|
70
|
+
* `ARG REEVAL_BASE` / `FROM ${REEVAL_BASE}` to layer on reeval's sandbox image; from any other Debian or
|
|
71
|
+
* Ubuntu base, reeval bakes Node and the harness on top, as for `from`.
|
|
72
|
+
*
|
|
73
|
+
* `install` bakes shell commands onto the base in one cached layer (not with `dockerfile`: put
|
|
74
|
+
* them in it). They run as root from `/`, in order, and never see secrets or the workspace; what
|
|
75
|
+
* needs either belongs in the environment's `setup`.
|
|
76
|
+
*
|
|
77
|
+
* At run time the agent, setup steps and checks run as the unprivileged `es` user with every
|
|
78
|
+
* capability dropped, `no-new-privileges`, and `memory`, `cpus` and `pids` limits. `root: true`
|
|
79
|
+
* opts an eval into root; `capabilities` adds specific ones back.
|
|
80
|
+
*/
|
|
81
|
+
function docker(options = {}) {
|
|
82
|
+
if (typeof options !== "object" || options === null || Array.isArray(options)) throw new UsageError(`docker() takes an options object (got ${JSON.stringify(options)})`);
|
|
83
|
+
for (const key of Object.keys(options)) {
|
|
84
|
+
if (DOCKER_KEYS.includes(key)) continue;
|
|
85
|
+
if (key === "environment" || key === "env") throw new UsageError(`Unknown docker() option "${key}". The sandbox is what's baked into the image; variables and secrets belong in defineEnvironment({ env }).`);
|
|
86
|
+
const hint = DOCKER_HINTS[key] ? ` Did you mean "${DOCKER_HINTS[key]}"?` : "";
|
|
87
|
+
throw new UsageError(`Unknown docker() option "${key}".${hint}`);
|
|
88
|
+
}
|
|
89
|
+
const bases = [
|
|
90
|
+
"image",
|
|
91
|
+
"from",
|
|
92
|
+
"dockerfile"
|
|
93
|
+
].filter((k) => options[k] !== void 0);
|
|
94
|
+
if (bases.length > 1) throw new UsageError(`docker() takes one base image, but got ${bases.join(" and ")}. Use image (has the harness), from (a toolchain image reeval bakes the harness onto) or dockerfile.`);
|
|
95
|
+
for (const key of [
|
|
96
|
+
"id",
|
|
97
|
+
"image",
|
|
98
|
+
"from"
|
|
99
|
+
]) {
|
|
100
|
+
const value = options[key];
|
|
101
|
+
if (value !== void 0 && (typeof value !== "string" || !value.trim())) throw new UsageError(`docker({ ${key} }) must be a non-empty string (got ${JSON.stringify(value)})`);
|
|
102
|
+
}
|
|
103
|
+
checkConfinement(options);
|
|
104
|
+
const { dockerfile, install, ...rest } = options;
|
|
105
|
+
const descriptor = {
|
|
106
|
+
kind: "docker",
|
|
107
|
+
...rest
|
|
108
|
+
};
|
|
109
|
+
if (rest.capabilities) descriptor.capabilities = [...rest.capabilities];
|
|
110
|
+
if (dockerfile !== void 0) {
|
|
111
|
+
if (install !== void 0) throw new UsageError("docker() takes dockerfile or install, not both: put the install commands in the Dockerfile as RUN lines, so there's one recipe for the image.");
|
|
112
|
+
if (!(dockerfile instanceof URL) && (typeof dockerfile !== "string" || !dockerfile.trim())) throw new UsageError(`docker({ dockerfile }) takes a path, e.g. dockerfile: './Dockerfile' (got ${JSON.stringify(dockerfile)})`);
|
|
113
|
+
const path = dockerfile instanceof URL ? fileURLToPath(dockerfile) : dockerfile;
|
|
114
|
+
const full = isAbsolute(path) ? path : resolve(callerDir() ?? process.cwd(), path);
|
|
115
|
+
if (!existsSync(full) || !statSync(full).isFile()) throw new UsageError(`docker({ dockerfile: ${JSON.stringify(path)} }): ${full} doesn't exist. Paths are relative to the file that calls docker().`);
|
|
116
|
+
descriptor.dockerfile = full;
|
|
117
|
+
}
|
|
118
|
+
if (install !== void 0) descriptor.install = checkInstall(install);
|
|
119
|
+
return descriptor;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* A temp directory on the host with no isolation. For tests and the fake harness only. `dir` may
|
|
123
|
+
* be a `file:` URL, such as `new URL('./sandboxes', import.meta.url)`.
|
|
124
|
+
*/
|
|
125
|
+
const fakeSandbox = ({ dir, ...options } = {}) => ({
|
|
126
|
+
kind: "fake",
|
|
127
|
+
...options,
|
|
128
|
+
...dir !== void 0 && { dir: dir instanceof URL ? fileURLToPath(dir) : dir }
|
|
129
|
+
});
|
|
130
|
+
//#endregion
|
|
131
|
+
export { fakeSandbox as n, docker as t };
|
|
132
|
+
|
|
133
|
+
//# sourceMappingURL=sandbox-By2gkdkC.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sandbox-By2gkdkC.js","names":[],"sources":["../src/sandbox.ts"],"mappings":"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"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { Q as SandboxDescriptor, j as FakeSandboxDescriptor, m as DockerSandboxDescriptor } from "./types-DLec-6Cx.js";
|
|
2
|
+
//#region src/sandbox.d.ts
|
|
3
|
+
export type DockerOptions = Omit<DockerSandboxDescriptor, 'kind' | 'dockerfile'> & {
|
|
4
|
+
/** Relative to the file that calls `docker()`, or an absolute path or `URL`. */
|
|
5
|
+
dockerfile?: string | URL;
|
|
6
|
+
};
|
|
7
|
+
/**
|
|
8
|
+
* One local Docker container per attempt. By default it's the image `reeval image build` makes. One
|
|
9
|
+
* base at most:
|
|
10
|
+
*
|
|
11
|
+
* - `image`: another image that already has the harness baked in, used as is.
|
|
12
|
+
* - `from`: a Debian or Ubuntu based toolchain image (e.g. `python:3.12-slim`); reeval bakes Node and
|
|
13
|
+
* the harness on top on first use.
|
|
14
|
+
* - `dockerfile`: your Dockerfile, built with `docker build` from its directory. Start it
|
|
15
|
+
* `ARG REEVAL_BASE` / `FROM ${REEVAL_BASE}` to layer on reeval's sandbox image; from any other Debian or
|
|
16
|
+
* Ubuntu base, reeval bakes Node and the harness on top, as for `from`.
|
|
17
|
+
*
|
|
18
|
+
* `install` bakes shell commands onto the base in one cached layer (not with `dockerfile`: put
|
|
19
|
+
* them in it). They run as root from `/`, in order, and never see secrets or the workspace; what
|
|
20
|
+
* needs either belongs in the environment's `setup`.
|
|
21
|
+
*
|
|
22
|
+
* At run time the agent, setup steps and checks run as the unprivileged `es` user with every
|
|
23
|
+
* capability dropped, `no-new-privileges`, and `memory`, `cpus` and `pids` limits. `root: true`
|
|
24
|
+
* opts an eval into root; `capabilities` adds specific ones back.
|
|
25
|
+
*/
|
|
26
|
+
export declare function docker(options?: DockerOptions): DockerSandboxDescriptor;
|
|
27
|
+
/**
|
|
28
|
+
* A temp directory on the host with no isolation. For tests and the fake harness only. `dir` may
|
|
29
|
+
* be a `file:` URL, such as `new URL('./sandboxes', import.meta.url)`.
|
|
30
|
+
*/
|
|
31
|
+
export declare const fakeSandbox: ({ dir, ...options }?: Omit<FakeSandboxDescriptor, 'kind' | 'dir'> & {
|
|
32
|
+
dir?: string | URL;
|
|
33
|
+
}) => {
|
|
34
|
+
id?: string;
|
|
35
|
+
maxConcurrent?: number;
|
|
36
|
+
kind: "fake";
|
|
37
|
+
dir?: string | undefined;
|
|
38
|
+
};
|
|
39
|
+
//#endregion
|
|
40
|
+
export type { DockerSandboxDescriptor, FakeSandboxDescriptor, SandboxDescriptor };
|
|
41
|
+
//# sourceMappingURL=sandbox.d.ts.map
|
package/dist/sandbox.js
ADDED