@inflexa-ai/harness 0.4.4 → 0.4.5
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.
|
@@ -44,7 +44,12 @@ export interface DockerClientConfig {
|
|
|
44
44
|
resolveWorkspaceRoot: ResolveWorkspaceRoot;
|
|
45
45
|
/** Host lib store; bind-mounted read-only at `/mnt/libs` when set. */
|
|
46
46
|
libStorePath?: string;
|
|
47
|
-
/**
|
|
47
|
+
/**
|
|
48
|
+
* Host ref store; bind-mounted read-only at `/mnt/refs`. Embedders pass the
|
|
49
|
+
* configured store location unconditionally — existence is (re-)checked at each
|
|
50
|
+
* sandbox creation, so a store installed mid-session is mounted into subsequent
|
|
51
|
+
* sandboxes without a runtime restart.
|
|
52
|
+
*/
|
|
48
53
|
refStorePath?: string;
|
|
49
54
|
/**
|
|
50
55
|
* Force the container platform (e.g. `linux/amd64`). Set by hosts that mount
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
* Either way the workload ends as uid 1000 with `no-new-privileges` and no
|
|
29
29
|
* effective capabilities.
|
|
30
30
|
*/
|
|
31
|
-
import { existsSync, statSync } from "node:fs";
|
|
31
|
+
import { existsSync, lstatSync, statSync } from "node:fs";
|
|
32
32
|
import { join } from "node:path";
|
|
33
33
|
import Docker from "dockerode";
|
|
34
34
|
import { ResultAsync, err, ok } from "neverthrow";
|
|
@@ -80,6 +80,30 @@ function libStoreUsable(libStorePath) {
|
|
|
80
80
|
}
|
|
81
81
|
return existsSync(join(current, "packages.txt")) && existsSync(join(current, "meta.json"));
|
|
82
82
|
}
|
|
83
|
+
/**
|
|
84
|
+
* Whether `refStorePath` is, right now, a real directory fit to be a bind authority.
|
|
85
|
+
* Deliberately shallow — it checks existence-as-a-directory only, never the store's
|
|
86
|
+
* interior: the harness knows nothing of the ref store's layout, and dataset
|
|
87
|
+
* completeness/receipts are the embedder's concern, so (unlike `libStoreUsable`, which
|
|
88
|
+
* validates harness-known `current` layout) there is nothing here to validate beyond
|
|
89
|
+
* "a directory is present."
|
|
90
|
+
*
|
|
91
|
+
* `lstatSync` (not `statSync`) does NOT follow symlinks, so a symlinked path is rejected
|
|
92
|
+
* even when it resolves to a directory: the bind authority must itself be the store
|
|
93
|
+
* directory, not an indirection that may later point elsewhere.
|
|
94
|
+
*
|
|
95
|
+
* Binding a missing source makes Docker auto-create a root-owned directory at the path —
|
|
96
|
+
* the same hazard `libStoreUsable` documents — which would also brick the embedder's
|
|
97
|
+
* later store install (its store tool cannot write into a root-owned dir).
|
|
98
|
+
*/
|
|
99
|
+
function refStoreUsable(refStorePath) {
|
|
100
|
+
try {
|
|
101
|
+
return lstatSync(refStorePath).isDirectory();
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
83
107
|
async function pollHealth(fetchImpl, url, timeoutMs) {
|
|
84
108
|
const deadline = Date.now() + timeoutMs;
|
|
85
109
|
let lastErr;
|
|
@@ -187,9 +211,16 @@ export function createDockerSandboxOps(config) {
|
|
|
187
211
|
if (config.libStorePath && !libsMounted) {
|
|
188
212
|
logger.warn("lib store configured but `current` is missing or incomplete at sandbox creation — mounting no library store (sandbox degrades to available:false)", { libStorePath: config.libStorePath, sandboxId });
|
|
189
213
|
}
|
|
214
|
+
// Re-checked here too, so a ref store installed after boot is mounted into
|
|
215
|
+
// the next sandbox. Unlike libs, a missing ref store is NOT warned: a missing
|
|
216
|
+
// lib store is a degradation (it was configured and working, then broke),
|
|
217
|
+
// whereas a missing ref store is the normal cold state — the user simply has
|
|
218
|
+
// not installed reference data yet — and warning on every create would be
|
|
219
|
+
// noise. A store that appears mid-session is picked up by the next create.
|
|
220
|
+
const refsMounted = !!config.refStorePath && refStoreUsable(config.refStorePath);
|
|
190
221
|
const plan = buildMountPlan(meta, {
|
|
191
222
|
libs: libsMounted,
|
|
192
|
-
refs:
|
|
223
|
+
refs: refsMounted,
|
|
193
224
|
});
|
|
194
225
|
const hostTreePath = config.resolveWorkspaceRoot(meta.analysisId);
|
|
195
226
|
// `stepWritePrefix` (not a raw `join`) so the RW bind source runs through
|
|
@@ -200,7 +231,7 @@ export function createDockerSandboxOps(config) {
|
|
|
200
231
|
`${hostTreePath}:${plan.readonlyTreePath}:ro`,
|
|
201
232
|
...(plan.writableStepPath ? [`${hostStepPath}:${plan.writableStepPath}:rw`] : []),
|
|
202
233
|
...(libsMounted && config.libStorePath ? [`${config.libStorePath}:${plan.libsPath}:ro`] : []),
|
|
203
|
-
...(config.refStorePath ? [`${config.refStorePath}:${plan.refsPath}:ro`] : []),
|
|
234
|
+
...(refsMounted && config.refStorePath ? [`${config.refStorePath}:${plan.refsPath}:ro`] : []),
|
|
204
235
|
];
|
|
205
236
|
const createFailed = (status, cause) => ({
|
|
206
237
|
type: "container_create_failed",
|
package/package.json
CHANGED