@agentswf/sandbox 0.1.0-beta.0 → 0.1.0-beta.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/package.json +2 -2
- package/src/docker/index.ts +5 -0
- package/src/resolve.ts +8 -2
- package/src/srt/index.ts +6 -3
- package/src/srt/profile.ts +10 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agentswf/sandbox",
|
|
3
|
-
"version": "0.1.0-beta.
|
|
3
|
+
"version": "0.1.0-beta.2",
|
|
4
4
|
"description": "agents.wf: the sandboxes a workflow opens, and their providers",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://github.com/romanlv/agentswf",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"docker"
|
|
29
29
|
],
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@agentswf/contract": "0.1.0-beta.
|
|
31
|
+
"@agentswf/contract": "0.1.0-beta.2"
|
|
32
32
|
},
|
|
33
33
|
"publishConfig": {
|
|
34
34
|
"access": "public"
|
package/src/docker/index.ts
CHANGED
|
@@ -133,6 +133,11 @@ async function openBox(
|
|
|
133
133
|
}
|
|
134
134
|
return result.stdout.trim();
|
|
135
135
|
};
|
|
136
|
+
if (spec.sockets.length > 0) {
|
|
137
|
+
throw new Error(
|
|
138
|
+
`docker: a box cannot reach host sockets (${spec.sockets.join(", ")}); use srt`,
|
|
139
|
+
);
|
|
140
|
+
}
|
|
136
141
|
const socket = daemonSocket(client.environment);
|
|
137
142
|
for (const path of [spec.cwd, ...spec.read, ...spec.write]) {
|
|
138
143
|
// A box that can reach the daemon can start a container with the host mounted.
|
package/src/resolve.ts
CHANGED
|
@@ -5,7 +5,7 @@ import { isRecord } from "@agentswf/contract";
|
|
|
5
5
|
import { SANDBOX_ENVIRONMENTS, type SandboxEnvironmentKey } from "@agentswf/contract/workflow";
|
|
6
6
|
import type { Gitdir, ResolvedSandbox, SandboxProviders } from "./seam";
|
|
7
7
|
|
|
8
|
-
const REACH_KEYS = ["read", "write", "network"] as const;
|
|
8
|
+
const REACH_KEYS = ["read", "write", "network", "sockets", "webSearch"] as const;
|
|
9
9
|
|
|
10
10
|
export type SandboxResolution = {
|
|
11
11
|
/** The environment key the sandbox runs under: the one the spec named, else the default. */
|
|
@@ -110,7 +110,7 @@ export async function resolveSandbox(
|
|
|
110
110
|
await resolvePath(spec.cwd === undefined ? "." : spec.cwd, options.cwd, home, "cwd"),
|
|
111
111
|
"cwd",
|
|
112
112
|
);
|
|
113
|
-
const paths = (field: "read" | "write") =>
|
|
113
|
+
const paths = (field: "read" | "write" | "sockets") =>
|
|
114
114
|
Promise.all(
|
|
115
115
|
list(spec[field], field).map(async (path) =>
|
|
116
116
|
forbidden(await resolvePath(path, cwd, home, field), field),
|
|
@@ -118,6 +118,10 @@ export async function resolveSandbox(
|
|
|
118
118
|
);
|
|
119
119
|
const write = unique(await paths("write"));
|
|
120
120
|
const read = unique(await paths("read")).filter((path) => !write.includes(path));
|
|
121
|
+
const sockets = unique(await paths("sockets"));
|
|
122
|
+
if (spec.webSearch !== undefined && typeof spec.webSearch !== "boolean") {
|
|
123
|
+
throw new Error("sandbox webSearch must be true or false");
|
|
124
|
+
}
|
|
121
125
|
const network = unique(
|
|
122
126
|
list(spec.network, "network").map((domain) => {
|
|
123
127
|
if (!isDomain(domain)) throw new Error(`not a sandbox domain: ${JSON.stringify(domain)}`);
|
|
@@ -174,6 +178,8 @@ export async function resolveSandbox(
|
|
|
174
178
|
read,
|
|
175
179
|
write,
|
|
176
180
|
network,
|
|
181
|
+
sockets,
|
|
182
|
+
webSearch: spec.webSearch === true,
|
|
177
183
|
hidden: holdsRunRoot ? [runRoot] : [],
|
|
178
184
|
gitdirs: [...gitdirs].map(([path, { own, linked }]): Gitdir => {
|
|
179
185
|
// A submodule's gitdir is in its superproject's `modules`, which is guarded whole: it is
|
package/src/srt/index.ts
CHANGED
|
@@ -247,6 +247,8 @@ async function probe(options: SrtOptions, context: SandboxContext): Promise<void
|
|
|
247
247
|
read: [],
|
|
248
248
|
write: [],
|
|
249
249
|
network: [],
|
|
250
|
+
sockets: [],
|
|
251
|
+
webSearch: false,
|
|
250
252
|
hidden: [],
|
|
251
253
|
gitdirs: [],
|
|
252
254
|
environment: {},
|
|
@@ -302,7 +304,8 @@ async function probe(options: SrtOptions, context: SandboxContext): Promise<void
|
|
|
302
304
|
}
|
|
303
305
|
|
|
304
306
|
/**
|
|
305
|
-
* srt as installed on this machine:
|
|
307
|
+
* srt as installed on this machine: the `srt` on `PATH` that answers `--version` (npm releases are
|
|
308
|
+
* 0.0.x; older ones print 1.0.0 outside npm). `undefined` when absent. The
|
|
306
309
|
* toolchain is what `PATH`'s executables under `~` need: their `bin` directories, and each one's
|
|
307
310
|
* install tree (X19): a node package's root, a `bin/` beside a `lib/` (a node or a Python venv),
|
|
308
311
|
* or the executable alone. Never a whole parent of `bin`: `~/.local` holds `state/` and
|
|
@@ -324,8 +327,8 @@ export async function findSrt(
|
|
|
324
327
|
stderr: "pipe",
|
|
325
328
|
timeout: VERSION_MS,
|
|
326
329
|
});
|
|
327
|
-
|
|
328
|
-
|
|
330
|
+
if (version.exitCode !== 0 || !/^\d+\.\d+\.\d+/.test(version.stdout.toString().trim()))
|
|
331
|
+
return undefined;
|
|
329
332
|
const real = [
|
|
330
333
|
...new Set(
|
|
331
334
|
(await Promise.all(path.map((entry) => realpath(entry).catch(() => undefined)))).filter(
|
package/src/srt/profile.ts
CHANGED
|
@@ -63,7 +63,11 @@ export function baseProfile(
|
|
|
63
63
|
const gitdirs = spec.gitdirs.map((gitdir) => gitdir.path);
|
|
64
64
|
return {
|
|
65
65
|
enableWeakerNetworkIsolation: true,
|
|
66
|
-
network: {
|
|
66
|
+
network: {
|
|
67
|
+
allowedDomains: [...spec.network],
|
|
68
|
+
deniedDomains: [],
|
|
69
|
+
allowUnixSockets: [...spec.sockets],
|
|
70
|
+
},
|
|
67
71
|
filesystem: {
|
|
68
72
|
denyRead: unique([host.home, ...DENIED, context.runRoot, ...spec.hidden]),
|
|
69
73
|
allowRead: unique([
|
|
@@ -117,7 +121,11 @@ export function agentProfile(
|
|
|
117
121
|
network: {
|
|
118
122
|
...base.network,
|
|
119
123
|
allowedDomains: unique([...base.network.allowedDomains, ...agent.harness.domains]),
|
|
120
|
-
allowUnixSockets:
|
|
124
|
+
allowUnixSockets: unique([
|
|
125
|
+
...base.network.allowUnixSockets,
|
|
126
|
+
agent.door.endpoint,
|
|
127
|
+
...(short ? [short] : []),
|
|
128
|
+
]),
|
|
121
129
|
},
|
|
122
130
|
filesystem: {
|
|
123
131
|
...base.filesystem,
|