@blen/fedreg-mcp-server 2.2.2 → 2.2.3
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 +7 -1
- package/README.md +1 -1
- package/SECURITY.md +6 -4
- package/dist/sandbox/deno.d.ts +26 -4
- package/dist/sandbox/deno.d.ts.map +1 -1
- package/dist/sandbox/deno.js +337 -151
- package/dist/sandbox/deno.js.map +1 -1
- package/dist/sandbox/isolate.d.ts +10 -0
- package/dist/sandbox/isolate.d.ts.map +1 -1
- package/dist/sandbox/isolate.js +153 -66
- package/dist/sandbox/isolate.js.map +1 -1
- package/dist/sandbox/limits.d.ts +62 -0
- package/dist/sandbox/limits.d.ts.map +1 -0
- package/dist/sandbox/limits.js +87 -0
- package/dist/sandbox/limits.js.map +1 -0
- package/dist/sandbox/types.d.ts +3 -0
- package/dist/sandbox/types.d.ts.map +1 -1
- package/dist/sdk/bindings.js +1 -1
- package/dist/server/mcpServer.js +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -21,6 +21,11 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
21
21
|
|
|
22
22
|
|
|
23
23
|
|
|
24
|
+
|
|
25
|
+
## [2.2.3] - 2026-11-13
|
|
26
|
+
|
|
27
|
+
### Changed
|
|
28
|
+
- Merge commit from fork
|
|
24
29
|
## [2.2.2] - 2026-11-10
|
|
25
30
|
|
|
26
31
|
### Changed
|
|
@@ -220,7 +225,8 @@ Initial public release.
|
|
|
220
225
|
→ notifications/initialized → tools/list → tools/call → sandbox → SDK
|
|
221
226
|
→ mocked upstream).
|
|
222
227
|
|
|
223
|
-
[Unreleased]: https://github.com/blen-labs/fedreg-mcp-server/compare/v2.2.
|
|
228
|
+
[Unreleased]: https://github.com/blen-labs/fedreg-mcp-server/compare/v2.2.3...HEAD
|
|
229
|
+
[2.2.3]: https://github.com/blen-labs/fedreg-mcp-server/compare/v2.2.2...v2.2.3
|
|
224
230
|
[2.2.2]: https://github.com/blen-labs/fedreg-mcp-server/compare/v2.2.1...v2.2.2
|
|
225
231
|
[2.2.1]: https://github.com/blen-labs/fedreg-mcp-server/compare/v2.2.0...v2.2.1
|
|
226
232
|
[2.2.0]: https://github.com/blen-labs/fedreg-mcp-server/compare/v2.1.0...v2.2.0
|
package/README.md
CHANGED
|
@@ -214,7 +214,7 @@ CLI options: `--http`, `--port`, `--host`, `--sandbox auto|isolate|deno`, `--ins
|
|
|
214
214
|
|
|
215
215
|
## Security
|
|
216
216
|
|
|
217
|
-
User code is sandboxed by design — no network, filesystem, env, or subprocess access, an `acorn` AST preflight, a wall-clock timeout,
|
|
217
|
+
User code is sandboxed by design — no network, filesystem, env, or subprocess access, an `acorn` AST preflight, a host-owned wall-clock timeout, a heap cap, and byte budgets on logs and results. The full threat model is in [`SECURITY.md`](./SECURITY.md). Found a sandbox escape or auth bypass? Please open a [private Security Advisory](https://github.com/blen-labs/fedreg-mcp-server/security/advisories/new) rather than a public issue.
|
|
218
218
|
|
|
219
219
|
## Contributing
|
|
220
220
|
|
package/SECURITY.md
CHANGED
|
@@ -55,10 +55,12 @@ The `execute` tool runs user-supplied JavaScript with two layered defenses:
|
|
|
55
55
|
2. **Runtime isolation** — one of:
|
|
56
56
|
- `isolated-vm`: a fresh V8 isolate, **no host references** other than
|
|
57
57
|
a Reference to the RPC dispatcher and a log sink for `console.*`;
|
|
58
|
-
heap cap, wall-clock cap.
|
|
59
|
-
- `deno run --no-prompt
|
|
60
|
-
so no net/fs/env/ffi/subprocess access
|
|
61
|
-
|
|
58
|
+
heap cap, host-owned wall-clock cap (the isolate is disposed when it fires).
|
|
59
|
+
- `deno run --no-prompt`: subprocess with **no `--allow-*` flags** and a
|
|
60
|
+
minimal environment, so no net/fs/env/ffi/subprocess access. User code
|
|
61
|
+
runs in a Worker with the protocol and ambient globals removed; the host
|
|
62
|
+
validates and size-bounds every frame and kills the process group on
|
|
63
|
+
every exit path, so a frame can never cancel the deadline.
|
|
62
64
|
|
|
63
65
|
Both runners deny network access to user code; the only way to reach
|
|
64
66
|
upstream APIs is via the `fr.*` / `ecfr.*` / `regs.*` proxies, which serialize
|
package/dist/sandbox/deno.d.ts
CHANGED
|
@@ -1,13 +1,35 @@
|
|
|
1
1
|
import type { ExecuteOptions, ExecuteResult, RpcBridge, SandboxRunner } from './types.js';
|
|
2
|
+
import { type SandboxLimits } from './limits.js';
|
|
2
3
|
/**
|
|
3
|
-
* Deno
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* Deno sandbox.
|
|
5
|
+
*
|
|
6
|
+
* Boundary: Node host (owns the deadline, byte budgets, and the child's lifetime)
|
|
7
|
+
* → `deno run` of a fixed supervisor script with NO --allow-* flags (deny-by-default: no net, fs,
|
|
8
|
+
* env, ffi, subprocess), a minimal environment, and no user code on disk
|
|
9
|
+
* → a module Worker that receives the user code by message. Before user code runs, the worker's
|
|
10
|
+
* ambient globals that could reach the process or the protocol (`Deno`, `postMessage`, `fetch`,
|
|
11
|
+
* `Worker`, ...) are replaced with `undefined` and `console` is redirected to log messages.
|
|
12
|
+
*
|
|
13
|
+
* Protocol: the supervisor talks to the host over stdin/stdout with one JSON frame per line,
|
|
14
|
+
* prefixed by a random token the supervisor generates and announces before the worker exists.
|
|
15
|
+
* The worker never sees the token, so it cannot forge frames; any other stdout bytes are treated
|
|
16
|
+
* as untrusted log text. All child output is untrusted: frames are size-bounded and validated, the
|
|
17
|
+
* execution settles exactly once, and the process group is killed on every exit path. A frame can
|
|
18
|
+
* never cancel the host's deadline or its cleanup.
|
|
6
19
|
*/
|
|
7
20
|
export declare class DenoRunner implements SandboxRunner {
|
|
21
|
+
private readonly limits;
|
|
8
22
|
kind: "deno";
|
|
23
|
+
private static supervisorPath?;
|
|
24
|
+
constructor(limits?: SandboxLimits);
|
|
9
25
|
available(): Promise<boolean>;
|
|
26
|
+
/** The supervisor holds no user data; it is written once per process, readable only by us. */
|
|
27
|
+
private static supervisor;
|
|
10
28
|
execute(opts: ExecuteOptions, rpc: RpcBridge): Promise<ExecuteResult>;
|
|
11
29
|
}
|
|
12
|
-
|
|
30
|
+
/**
|
|
31
|
+
* Runs in Deno with no permissions. Holds no user data until the start frame arrives over stdin.
|
|
32
|
+
* Binding names come from the host (pre-validated identifiers) and are only used as object keys.
|
|
33
|
+
*/
|
|
34
|
+
export declare const SUPERVISOR_SOURCE: string;
|
|
13
35
|
//# sourceMappingURL=deno.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deno.d.ts","sourceRoot":"","sources":["../../src/sandbox/deno.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAG1F
|
|
1
|
+
{"version":3,"file":"deno.d.ts","sourceRoot":"","sources":["../../src/sandbox/deno.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAG1F,OAAO,EAAwJ,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AAEvM;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,UAAW,YAAW,aAAa;IAIlC,OAAO,CAAC,QAAQ,CAAC,MAAM;IAHnC,IAAI,EAAG,MAAM,CAAU;IACvB,OAAO,CAAC,MAAM,CAAC,cAAc,CAAC,CAAS;gBAEV,MAAM,GAAE,aAA8B;IAE7D,SAAS,IAAI,OAAO,CAAC,OAAO,CAAC;IAQnC,8FAA8F;IAC9F,OAAO,CAAC,MAAM,CAAC,UAAU;IAanB,OAAO,CAAC,IAAI,EAAE,cAAc,EAAE,GAAG,EAAE,SAAS,GAAG,OAAO,CAAC,aAAa,CAAC;CA0J5E;AAqBD;;;GAGG;AACH,eAAO,MAAM,iBAAiB,QAgI7B,CAAC"}
|
package/dist/sandbox/deno.js
CHANGED
|
@@ -1,203 +1,389 @@
|
|
|
1
1
|
import { spawn } from 'node:child_process';
|
|
2
|
-
import { mkdtempSync, rmSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { existsSync, mkdtempSync, rmSync, writeFileSync, chmodSync } from 'node:fs';
|
|
3
3
|
import { tmpdir } from 'node:os';
|
|
4
4
|
import { join } from 'node:path';
|
|
5
|
+
import { log } from '../util/logger.js';
|
|
5
6
|
import { preflight } from './policy.js';
|
|
7
|
+
import { DEFAULT_LIMITS, LOG_LINE_OVERHEAD, LOG_TRUNCATED, LogSink, MAX_ERROR_MESSAGE, boundMessage, checkRpcArgs, finishValue, policyMessage, resultTooLarge } from './limits.js';
|
|
6
8
|
/**
|
|
7
|
-
* Deno
|
|
8
|
-
*
|
|
9
|
-
*
|
|
9
|
+
* Deno sandbox.
|
|
10
|
+
*
|
|
11
|
+
* Boundary: Node host (owns the deadline, byte budgets, and the child's lifetime)
|
|
12
|
+
* → `deno run` of a fixed supervisor script with NO --allow-* flags (deny-by-default: no net, fs,
|
|
13
|
+
* env, ffi, subprocess), a minimal environment, and no user code on disk
|
|
14
|
+
* → a module Worker that receives the user code by message. Before user code runs, the worker's
|
|
15
|
+
* ambient globals that could reach the process or the protocol (`Deno`, `postMessage`, `fetch`,
|
|
16
|
+
* `Worker`, ...) are replaced with `undefined` and `console` is redirected to log messages.
|
|
17
|
+
*
|
|
18
|
+
* Protocol: the supervisor talks to the host over stdin/stdout with one JSON frame per line,
|
|
19
|
+
* prefixed by a random token the supervisor generates and announces before the worker exists.
|
|
20
|
+
* The worker never sees the token, so it cannot forge frames; any other stdout bytes are treated
|
|
21
|
+
* as untrusted log text. All child output is untrusted: frames are size-bounded and validated, the
|
|
22
|
+
* execution settles exactly once, and the process group is killed on every exit path. A frame can
|
|
23
|
+
* never cancel the host's deadline or its cleanup.
|
|
10
24
|
*/
|
|
11
25
|
export class DenoRunner {
|
|
26
|
+
limits;
|
|
12
27
|
kind = 'deno';
|
|
28
|
+
static supervisorPath;
|
|
29
|
+
constructor(limits = DEFAULT_LIMITS) {
|
|
30
|
+
this.limits = limits;
|
|
31
|
+
}
|
|
13
32
|
async available() {
|
|
14
33
|
return await new Promise(resolve => {
|
|
15
|
-
const p = spawn('deno', ['--version'], { stdio: 'ignore' });
|
|
34
|
+
const p = spawn('deno', ['--version'], { stdio: 'ignore', env: childEnv() });
|
|
16
35
|
p.on('error', () => resolve(false));
|
|
17
36
|
p.on('exit', code => resolve(code === 0));
|
|
18
37
|
});
|
|
19
38
|
}
|
|
39
|
+
/** The supervisor holds no user data; it is written once per process, readable only by us. */
|
|
40
|
+
static supervisor() {
|
|
41
|
+
// Re-check on disk: a long-lived server's temp dir may be reaped by a tmp cleaner.
|
|
42
|
+
if (!DenoRunner.supervisorPath || !existsSync(DenoRunner.supervisorPath)) {
|
|
43
|
+
const dir = mkdtempSync(join(tmpdir(), 'fedreg-deno-'));
|
|
44
|
+
chmodSync(dir, 0o700);
|
|
45
|
+
const path = join(dir, 'supervisor.js');
|
|
46
|
+
writeFileSync(path, SUPERVISOR_SOURCE, { mode: 0o600 });
|
|
47
|
+
DenoRunner.supervisorPath = path;
|
|
48
|
+
process.once('exit', () => { try {
|
|
49
|
+
rmSync(dir, { recursive: true, force: true });
|
|
50
|
+
}
|
|
51
|
+
catch { /* ignore */ } });
|
|
52
|
+
}
|
|
53
|
+
return DenoRunner.supervisorPath;
|
|
54
|
+
}
|
|
20
55
|
async execute(opts, rpc) {
|
|
21
56
|
const started = Date.now();
|
|
57
|
+
const limits = { ...this.limits, ...(opts.limits ?? {}) };
|
|
58
|
+
const timeoutMs = opts.timeoutMs ?? 15_000;
|
|
59
|
+
const fail = (name, message, logs = []) => ({ ok: false, logs, error: { name, message }, durationMs: Date.now() - started });
|
|
22
60
|
const policy = preflight(opts.code);
|
|
23
|
-
if (!policy.ok)
|
|
24
|
-
return
|
|
61
|
+
if (!policy.ok)
|
|
62
|
+
return fail('PolicyError', policyMessage(policy.errors));
|
|
63
|
+
if (Buffer.byteLength(opts.code, 'utf8') > limits.maxCodeBytes)
|
|
64
|
+
return fail('CodeTooLarge', `Code exceeds ${limits.maxCodeBytes} bytes.`);
|
|
65
|
+
let child;
|
|
66
|
+
try {
|
|
67
|
+
child = spawn('deno', [
|
|
68
|
+
'run', '--no-prompt', '--no-config', '--no-lock', '--no-remote', '--no-npm', '--quiet',
|
|
69
|
+
`--v8-flags=--max-old-space-size=${Math.max(16, opts.memoryMb ?? 64)}`,
|
|
70
|
+
DenoRunner.supervisor(),
|
|
71
|
+
], { stdio: ['pipe', 'pipe', 'pipe'], env: childEnv(), detached: process.platform !== 'win32' });
|
|
25
72
|
}
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
// reads the program from stdin until EOF, but we keep stdin open as the RPC
|
|
29
|
-
// channel, so it would never start. A file path leaves stdin free for RPC.
|
|
30
|
-
const tmpDir = mkdtempSync(join(tmpdir(), 'fedreg-deno-'));
|
|
31
|
-
const runnerPath = join(tmpDir, 'runner.ts');
|
|
32
|
-
writeFileSync(runnerPath, runner);
|
|
33
|
-
const cleanup = () => { try {
|
|
34
|
-
rmSync(tmpDir, { recursive: true, force: true });
|
|
73
|
+
catch (err) {
|
|
74
|
+
return fail('SpawnError', err.message);
|
|
35
75
|
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
76
|
+
const logs = new LogSink(limits.maxLogBytes, limits.maxLogLines);
|
|
77
|
+
return await new Promise(resolve => {
|
|
78
|
+
let settled = false;
|
|
79
|
+
let token;
|
|
80
|
+
let partial = [];
|
|
81
|
+
let partialLen = 0;
|
|
82
|
+
let bufferedBytes = 0;
|
|
83
|
+
let pendingRpc = 0;
|
|
84
|
+
// Choosing the outcome and tearing down are separate: the first terminal event fixes the
|
|
85
|
+
// result, and the promise resolves once the child has exited (bounded wait).
|
|
86
|
+
let exited = false;
|
|
87
|
+
const exitWaiters = [];
|
|
88
|
+
child.once('close', () => { exited = true; for (const w of exitWaiters.splice(0))
|
|
89
|
+
w(); });
|
|
90
|
+
const settle = (result) => {
|
|
91
|
+
if (settled)
|
|
92
|
+
return;
|
|
93
|
+
settled = true;
|
|
94
|
+
clearTimeout(deadline);
|
|
95
|
+
const outcome = { ...result, logs: logs.lines(), durationMs: Date.now() - started };
|
|
96
|
+
killTree(child);
|
|
97
|
+
if (exited)
|
|
98
|
+
return resolve(outcome);
|
|
99
|
+
// Normally the child exits within milliseconds of the kill. If it has not after 2 s, kill
|
|
100
|
+
// again, log it, and return the result anyway.
|
|
101
|
+
const giveUp = setTimeout(() => {
|
|
102
|
+
log.error('sandbox.teardown_pending', { pid: child.pid });
|
|
103
|
+
killTree(child);
|
|
104
|
+
resolve(outcome);
|
|
105
|
+
}, 2000);
|
|
106
|
+
exitWaiters.push(() => { clearTimeout(giveUp); resolve(outcome); });
|
|
107
|
+
};
|
|
108
|
+
const deadline = setTimeout(() => settle({ ok: false, error: { name: 'TimeoutError', message: `Execution exceeded ${timeoutMs}ms` } }), timeoutMs);
|
|
109
|
+
child.on('error', err => settle({ ok: false, error: { name: 'SpawnError', message: err.message } }));
|
|
110
|
+
// 'close', not 'exit': stdout may still hold the final frame when the process exits.
|
|
111
|
+
child.on('close', code => settle({ ok: false, error: { name: 'ExitError', message: `The sandbox exited unexpectedly (code ${code}).` } }));
|
|
112
|
+
const send = (frame) => {
|
|
113
|
+
if (settled || !token)
|
|
114
|
+
return;
|
|
115
|
+
let line;
|
|
46
116
|
try {
|
|
47
|
-
|
|
117
|
+
line = `${token}${JSON.stringify(frame)}\n`;
|
|
48
118
|
}
|
|
49
|
-
catch {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
if (msg.kind === 'log') {
|
|
76
|
-
logs.push(msg.text);
|
|
119
|
+
catch {
|
|
120
|
+
// An SDK result that cannot be serialized must still answer the call, or the sandbox waits for the deadline.
|
|
121
|
+
const f = frame;
|
|
122
|
+
if (f.t !== 'rpc-result')
|
|
123
|
+
return;
|
|
124
|
+
line = `${token}${JSON.stringify({ t: 'rpc-result', id: f.id, ok: false, error: { name: 'TypeError', message: 'The SDK result is not JSON-serializable.' } })}\n`;
|
|
125
|
+
}
|
|
126
|
+
try {
|
|
127
|
+
child.stdin.write(line);
|
|
128
|
+
}
|
|
129
|
+
catch { /* child gone; exit handler settles */ }
|
|
130
|
+
};
|
|
131
|
+
const onFrame = async (raw) => {
|
|
132
|
+
let msg;
|
|
133
|
+
try {
|
|
134
|
+
msg = JSON.parse(raw);
|
|
135
|
+
}
|
|
136
|
+
catch {
|
|
137
|
+
return settle({ ok: false, error: { name: 'SandboxProtocolError', message: 'The sandbox sent a malformed frame.' } });
|
|
138
|
+
}
|
|
139
|
+
if (msg.t === 'log' && typeof msg.text === 'string')
|
|
140
|
+
return logs.push(msg.text);
|
|
141
|
+
if (msg.t === 'rpc' && Number.isSafeInteger(msg.id) && typeof msg.binding === 'string'
|
|
142
|
+
&& Array.isArray(msg.path) && Array.isArray(msg.args)) {
|
|
143
|
+
if (pendingRpc >= limits.maxPendingRpc) {
|
|
144
|
+
return send({ t: 'rpc-result', id: msg.id, ok: false, error: { name: 'TooManyPendingCalls', message: `At most ${limits.maxPendingRpc} SDK calls may be pending at once.` } });
|
|
77
145
|
}
|
|
78
|
-
|
|
146
|
+
const tooBig = checkRpcArgs(msg.args, limits);
|
|
147
|
+
if (tooBig)
|
|
148
|
+
return send({ t: 'rpc-result', id: msg.id, ok: false, error: tooBig });
|
|
149
|
+
pendingRpc++;
|
|
150
|
+
try {
|
|
79
151
|
const res = await rpc.dispatch({ binding: msg.binding, path: msg.path, args: msg.args });
|
|
80
|
-
|
|
152
|
+
send({ t: 'rpc-result', id: msg.id, ok: res.ok, value: res.value, error: res.error });
|
|
81
153
|
}
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
try {
|
|
85
|
-
child.stdin.end();
|
|
86
|
-
}
|
|
87
|
-
catch { /* ignore */ }
|
|
88
|
-
resolve({
|
|
89
|
-
ok: msg.ok,
|
|
90
|
-
logs,
|
|
91
|
-
value: msg.value,
|
|
92
|
-
error: msg.error,
|
|
93
|
-
durationMs: Date.now() - started,
|
|
94
|
-
});
|
|
154
|
+
finally {
|
|
155
|
+
pendingRpc--;
|
|
95
156
|
}
|
|
157
|
+
return;
|
|
96
158
|
}
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
159
|
+
if (msg.t === 'done') {
|
|
160
|
+
if (msg.ok === true && typeof msg.json === 'string')
|
|
161
|
+
return settle(finishValue(msg.json, limits));
|
|
162
|
+
if (msg.tooLarge === true && typeof msg.size === 'number')
|
|
163
|
+
return settle({ ok: false, error: resultTooLarge(msg.size, limits) });
|
|
164
|
+
const e = (msg.error ?? {});
|
|
165
|
+
return settle({
|
|
166
|
+
ok: false,
|
|
167
|
+
error: {
|
|
168
|
+
name: typeof e.name === 'string' ? e.name.slice(0, 100) : 'Error',
|
|
169
|
+
message: typeof e.message === 'string' ? boundMessage(e.message) : 'Execution failed',
|
|
170
|
+
...(typeof e.status === 'number' ? { status: e.status } : {}),
|
|
171
|
+
},
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
return settle({ ok: false, error: { name: 'SandboxProtocolError', message: 'The sandbox sent an unexpected frame.' } });
|
|
175
|
+
};
|
|
176
|
+
child.stdout.setEncoding('utf8');
|
|
177
|
+
child.stdout.on('data', (chunk) => {
|
|
178
|
+
if (settled)
|
|
179
|
+
return;
|
|
180
|
+
bufferedBytes += Buffer.byteLength(chunk, 'utf8');
|
|
181
|
+
if (bufferedBytes > limits.maxStdoutBytes) {
|
|
182
|
+
return settle({ ok: false, error: { name: 'OutputTooLarge', message: `The sandbox produced more than ${limits.maxStdoutBytes} bytes of output.` } });
|
|
183
|
+
}
|
|
184
|
+
// Split only the new chunk, so a long unterminated frame is never rescanned or re-flattened.
|
|
185
|
+
const segments = chunk.split('\n');
|
|
186
|
+
const tail = segments.pop();
|
|
187
|
+
for (const seg of segments) {
|
|
188
|
+
if (settled)
|
|
189
|
+
return;
|
|
190
|
+
const line = partial.length ? partial.join('') + seg : seg;
|
|
191
|
+
partial = [];
|
|
192
|
+
partialLen = 0;
|
|
193
|
+
if (!token) {
|
|
194
|
+
// The supervisor's first line announces the frame token; nothing else may precede it.
|
|
195
|
+
const m = /^FEDREG-SANDBOX ([0-9a-f]{64})$/.exec(line);
|
|
196
|
+
if (!m)
|
|
197
|
+
return settle({ ok: false, error: { name: 'SandboxProtocolError', message: 'The sandbox did not start correctly.' } });
|
|
198
|
+
token = m[1];
|
|
199
|
+
send({ t: 'start', code: opts.code, bindings: opts.bindings ?? [], limits: {
|
|
200
|
+
maxLogBytes: limits.maxLogBytes, maxLogLines: limits.maxLogLines, logLineOverhead: LOG_LINE_OVERHEAD,
|
|
201
|
+
logTruncated: LOG_TRUNCATED, maxRpcArgBytes: limits.maxRpcArgBytes, maxResultBytes: limits.maxResultBytes,
|
|
202
|
+
maxError: MAX_ERROR_MESSAGE,
|
|
203
|
+
} });
|
|
204
|
+
continue;
|
|
205
|
+
}
|
|
206
|
+
if (line.startsWith(token)) {
|
|
207
|
+
onFrame(line.slice(token.length)).catch(err => settle({ ok: false, error: { name: 'SandboxProtocolError', message: boundMessage(String(err?.message ?? err)) } }));
|
|
208
|
+
}
|
|
209
|
+
else if (line.length)
|
|
210
|
+
logs.push(line);
|
|
211
|
+
}
|
|
212
|
+
if (settled)
|
|
213
|
+
return;
|
|
214
|
+
partial.push(tail);
|
|
215
|
+
partialLen += tail.length;
|
|
216
|
+
if (partialLen > limits.maxFrameBytes) {
|
|
217
|
+
settle({ ok: false, error: { name: 'OutputTooLarge', message: `A sandbox message exceeded ${limits.maxFrameBytes} bytes.` } });
|
|
109
218
|
}
|
|
110
219
|
});
|
|
220
|
+
child.stderr.setEncoding('utf8');
|
|
221
|
+
child.stderr.on('data', (chunk) => { if (!settled)
|
|
222
|
+
logs.push(chunk.trimEnd()); });
|
|
223
|
+
child.stdin.on('error', () => { });
|
|
111
224
|
});
|
|
112
225
|
}
|
|
113
226
|
}
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
const
|
|
117
|
-
|
|
227
|
+
/** Only what Deno needs to start; never the server's secrets. */
|
|
228
|
+
function childEnv() {
|
|
229
|
+
const env = { NO_COLOR: '1', DENO_NO_UPDATE_CHECK: '1', DENO_NO_PROMPT: '1' };
|
|
230
|
+
for (const k of ['PATH', 'HOME', 'DENO_DIR', 'TMPDIR', 'SystemRoot', 'USERPROFILE', 'LOCALAPPDATA']) {
|
|
231
|
+
if (process.env[k])
|
|
232
|
+
env[k] = process.env[k];
|
|
233
|
+
}
|
|
234
|
+
return env;
|
|
118
235
|
}
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
236
|
+
/** Kill the child and anything it started. POSIX: the whole process group. */
|
|
237
|
+
function killTree(child) {
|
|
238
|
+
try {
|
|
239
|
+
child.stdin.destroy();
|
|
240
|
+
}
|
|
241
|
+
catch { /* ignore */ }
|
|
242
|
+
if (child.exitCode !== null || child.signalCode !== null)
|
|
243
|
+
return;
|
|
244
|
+
if (process.platform !== 'win32' && child.pid) {
|
|
245
|
+
try {
|
|
246
|
+
process.kill(-child.pid, 'SIGKILL');
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
catch { /* fall through */ }
|
|
250
|
+
}
|
|
251
|
+
try {
|
|
252
|
+
child.kill('SIGKILL');
|
|
253
|
+
}
|
|
254
|
+
catch { /* ignore */ }
|
|
132
255
|
}
|
|
256
|
+
/**
|
|
257
|
+
* Runs in Deno with no permissions. Holds no user data until the start frame arrives over stdin.
|
|
258
|
+
* Binding names come from the host (pre-validated identifiers) and are only used as object keys.
|
|
259
|
+
*/
|
|
260
|
+
export const SUPERVISOR_SOURCE = String.raw `
|
|
261
|
+
const enc = new TextEncoder();
|
|
262
|
+
const bytes = new Uint8Array(32);
|
|
263
|
+
crypto.getRandomValues(bytes);
|
|
264
|
+
const TOKEN = Array.from(bytes, b => b.toString(16).padStart(2, '0')).join('');
|
|
265
|
+
const writeLine = (s) => { const b = enc.encode(s + '\n'); let o = 0; while (o < b.length) o += Deno.stdout.writeSync(b.subarray(o)); };
|
|
266
|
+
const frame = (obj) => writeLine(TOKEN + JSON.stringify(obj));
|
|
267
|
+
writeLine('FEDREG-SANDBOX ' + TOKEN);
|
|
133
268
|
|
|
134
|
-
|
|
269
|
+
const WORKER_SOURCE = ${'`'}
|
|
270
|
+
// Trusted primitives, captured before user code exists: budgets below use these, so user code that
|
|
271
|
+
// replaces JSON.stringify, TextEncoder or Promise.prototype.then cannot push oversized data out.
|
|
272
|
+
const post = self.postMessage.bind(self);
|
|
273
|
+
const listen = self.addEventListener.bind(self);
|
|
274
|
+
const S = JSON.stringify, P = JSON.parse, Str = String, apply = Reflect.apply, then = Promise.prototype.then;
|
|
275
|
+
const encoder = new TextEncoder(), encode = TextEncoder.prototype.encode, sl = String.prototype.slice;
|
|
276
|
+
// The intrinsic %TypedArray%.prototype.byteLength getter, captured: user code may redefine
|
|
277
|
+
// Uint8Array.prototype.length, but cannot change a getter we already hold.
|
|
278
|
+
const byteLength = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(Uint8Array.prototype), 'byteLength').get;
|
|
279
|
+
const bytes = (s) => apply(byteLength, apply(encode, encoder, [s]), []);
|
|
280
|
+
const cut = (s, n) => s.length > n ? apply(sl, s, [0, n]) : s;
|
|
281
|
+
let started = false;
|
|
135
282
|
const pending = new Map();
|
|
136
283
|
let nextId = 1;
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
while (inbuf.length >= 9) {
|
|
147
|
-
const lenHex = dec.decode(inbuf.subarray(0, 8));
|
|
148
|
-
const len = parseInt(lenHex, 16);
|
|
149
|
-
if (isNaN(len)) { inbuf = new Uint8Array(0); break; }
|
|
150
|
-
if (inbuf.length < 9 + len) break;
|
|
151
|
-
const payload = dec.decode(inbuf.subarray(9, 9 + len));
|
|
152
|
-
inbuf = inbuf.subarray(9 + len);
|
|
153
|
-
const msg = JSON.parse(payload);
|
|
154
|
-
if (msg.kind === 'rpc-result') {
|
|
155
|
-
const cb = pending.get(msg.id);
|
|
156
|
-
if (cb) { pending.delete(msg.id); cb(msg); }
|
|
157
|
-
}
|
|
158
|
-
}
|
|
284
|
+
listen('message', (ev) => {
|
|
285
|
+
const m = ev.data;
|
|
286
|
+
if (m && m.t === 'rpc-result') {
|
|
287
|
+
const p = pending.get(m.id);
|
|
288
|
+
if (!p) return;
|
|
289
|
+
pending.delete(m.id);
|
|
290
|
+
if (m.ok) p.resolve(m.value);
|
|
291
|
+
else { const e = new Error(String(m.error?.message ?? 'SDK call failed')); e.name = String(m.error?.name ?? 'Error'); if (typeof m.error?.status === 'number') e.status = m.error.status; p.reject(e); }
|
|
292
|
+
return;
|
|
159
293
|
}
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
294
|
+
if (!m || m.t !== 'start' || started) return;
|
|
295
|
+
started = true;
|
|
296
|
+
run(String(m.code), Array.isArray(m.bindings) ? m.bindings.map(String) : [], m.limits || {});
|
|
297
|
+
});
|
|
298
|
+
let L = {};
|
|
163
299
|
function call(binding, path, args) {
|
|
164
300
|
return new Promise((resolve, reject) => {
|
|
301
|
+
let json;
|
|
302
|
+
try { json = S(args ?? []); } catch (e) { reject(new TypeError('SDK arguments must be JSON-serializable')); return; }
|
|
303
|
+
if (typeof json !== 'string' || bytes(json) > L.maxRpcArgBytes) { const e = new Error('SDK call arguments exceed ' + L.maxRpcArgBytes + ' bytes.'); e.name = 'ArgumentsTooLarge'; reject(e); return; }
|
|
165
304
|
const id = nextId++;
|
|
166
|
-
pending.set(id,
|
|
167
|
-
|
|
168
|
-
else resolve(r.value);
|
|
169
|
-
});
|
|
170
|
-
writeFrame({ kind: 'rpc', id, binding, path, args });
|
|
305
|
+
pending.set(id, { resolve, reject });
|
|
306
|
+
post({ t: 'rpc', id, binding, path, args: P(json) });
|
|
171
307
|
});
|
|
172
308
|
}
|
|
173
|
-
|
|
174
309
|
function makeProxy(binding) {
|
|
175
|
-
const handler = (path) => new Proxy(function(){}, {
|
|
176
|
-
get(_, key) { return handler([...path, String(key)]); },
|
|
310
|
+
const handler = (path) => new Proxy(function () {}, {
|
|
311
|
+
get(_, key) { return typeof key === 'symbol' ? undefined : handler([...path, String(key)]); },
|
|
177
312
|
apply(_, __, args) { return call(binding, path, args); },
|
|
178
313
|
});
|
|
179
314
|
return handler([]);
|
|
180
315
|
}
|
|
316
|
+
function run(code, bindings, limits) {
|
|
317
|
+
L = limits;
|
|
318
|
+
const show = (v) => { if (typeof v === 'string') return v; try { const j = S(v); return j === undefined ? Str(v) : j; } catch { return Str(v); } };
|
|
319
|
+
let logBytes = 0, logLines = 0, logDone = false;
|
|
320
|
+
const log = (...a) => {
|
|
321
|
+
if (logDone) return;
|
|
322
|
+
let text = '';
|
|
323
|
+
for (let i = 0; i < a.length; i++) text += (i ? ' ' : '') + show(a[i]);
|
|
324
|
+
text = cut(text, L.maxLogBytes);
|
|
325
|
+
logBytes += bytes(text) + L.logLineOverhead; logLines++;
|
|
326
|
+
if (logBytes > L.maxLogBytes - L.logTruncated.length - L.logLineOverhead || logLines >= L.maxLogLines) { logDone = true; text = L.logTruncated; }
|
|
327
|
+
post({ t: 'log', text });
|
|
328
|
+
};
|
|
329
|
+
self.console = { log, info: log, warn: log, error: log, debug: log };
|
|
330
|
+
for (const k of ['Deno', 'postMessage', 'close', 'fetch', 'WebSocket', 'WebSocketStream', 'Worker', 'EventSource',
|
|
331
|
+
'navigator', 'caches', 'localStorage', 'sessionStorage', 'importScripts', 'BroadcastChannel']) {
|
|
332
|
+
try { Object.defineProperty(self, k, { value: undefined, writable: false, configurable: false }); } catch {}
|
|
333
|
+
}
|
|
334
|
+
for (const name of bindings) {
|
|
335
|
+
try { Object.defineProperty(self, name, { value: makeProxy(name), writable: false, configurable: false }); } catch {}
|
|
336
|
+
}
|
|
337
|
+
let fn;
|
|
338
|
+
try { fn = new Function('"use strict"; return (async () => {\\n' + code + '\\n})();'); }
|
|
339
|
+
catch (e) { post({ t: 'done', ok: false, error: { name: Str(e?.name ?? 'SyntaxError'), message: cut(Str(e?.message ?? e), L.maxError) } }); return; }
|
|
340
|
+
const fail = (e) => {
|
|
341
|
+
let name = 'Error', message = '', status;
|
|
342
|
+
try { name = cut(Str(e?.name ?? 'Error'), 100); message = cut(Str(e?.message !== undefined ? e.message : e), L.maxError); status = typeof e?.status === 'number' ? e.status : undefined; } catch {}
|
|
343
|
+
post({ t: 'done', ok: false, error: { name, message, ...(status === undefined ? {} : { status }) } });
|
|
344
|
+
};
|
|
345
|
+
const done = (value) => {
|
|
346
|
+
let json;
|
|
347
|
+
try { json = S(value === undefined ? null : value); } catch (e) { fail({ name: 'TypeError', message: 'The returned value is not JSON-serializable' }); return; }
|
|
348
|
+
if (typeof json !== 'string') json = 'null';
|
|
349
|
+
const size = bytes(json);
|
|
350
|
+
if (size > L.maxResultBytes) post({ t: 'done', ok: false, tooLarge: true, size });
|
|
351
|
+
else post({ t: 'done', ok: true, json });
|
|
352
|
+
};
|
|
353
|
+
let started;
|
|
354
|
+
try { started = fn(); } catch (e) { fail(e); return; }
|
|
355
|
+
apply(then, started, [done, fail]);
|
|
356
|
+
}
|
|
357
|
+
${'`'};
|
|
181
358
|
|
|
182
|
-
const
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
const
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
${userCode}
|
|
359
|
+
const url = URL.createObjectURL(new Blob([WORKER_SOURCE], { type: 'application/javascript' }));
|
|
360
|
+
const worker = new Worker(url, { type: 'module' });
|
|
361
|
+
worker.onmessage = (ev) => {
|
|
362
|
+
const m = ev.data;
|
|
363
|
+
if (!m || typeof m !== 'object') return;
|
|
364
|
+
if (m.t === 'log') frame({ t: 'log', text: String(m.text).slice(0, 65536) });
|
|
365
|
+
else if (m.t === 'rpc') frame({ t: 'rpc', id: m.id, binding: m.binding, path: m.path, args: m.args });
|
|
366
|
+
else if (m.t === 'done') frame({ t: 'done', ok: m.ok === true, json: m.json, error: m.error, tooLarge: m.tooLarge === true, size: m.size });
|
|
191
367
|
};
|
|
368
|
+
worker.onerror = (e) => { e.preventDefault(); frame({ t: 'done', ok: false, error: { name: 'Error', message: String(e.message ?? 'Worker error') } }); };
|
|
192
369
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
370
|
+
// Host → supervisor: token-prefixed JSON lines on stdin.
|
|
371
|
+
const dec = new TextDecoder();
|
|
372
|
+
let buf = '';
|
|
373
|
+
for await (const chunk of Deno.stdin.readable) {
|
|
374
|
+
buf += dec.decode(chunk, { stream: true });
|
|
375
|
+
let nl;
|
|
376
|
+
while ((nl = buf.indexOf('\n')) >= 0) {
|
|
377
|
+
const line = buf.slice(0, nl);
|
|
378
|
+
buf = buf.slice(nl + 1);
|
|
379
|
+
if (!line.startsWith(TOKEN)) continue;
|
|
380
|
+
let msg;
|
|
381
|
+
try { msg = JSON.parse(line.slice(TOKEN.length)); } catch { continue; }
|
|
382
|
+
if (msg.t === 'start') worker.postMessage({ t: 'start', code: msg.code, bindings: msg.bindings, limits: msg.limits });
|
|
383
|
+
else if (msg.t === 'rpc-result') worker.postMessage(msg);
|
|
384
|
+
}
|
|
202
385
|
}
|
|
386
|
+
// The host went away (stdin closed): do not leave a possibly busy Worker running as an orphan.
|
|
387
|
+
Deno.exit(0);
|
|
388
|
+
`;
|
|
203
389
|
//# sourceMappingURL=deno.js.map
|
package/dist/sandbox/deno.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deno.js","sourceRoot":"","sources":["../../src/sandbox/deno.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"deno.js","sourceRoot":"","sources":["../../src/sandbox/deno.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,16 @@
|
|
|
1
1
|
import type { ExecuteOptions, ExecuteResult, RpcBridge, SandboxRunner } from './types.js';
|
|
2
|
+
import { type SandboxLimits } from './limits.js';
|
|
3
|
+
/**
|
|
4
|
+
* isolated-vm sandbox: a fresh V8 isolate per execution with a heap cap. The host owns a
|
|
5
|
+
* wall-clock deadline that starts before setup: when it fires the isolate
|
|
6
|
+
* is disposed, which stops running code and rejects anything it awaits, and the execution settles
|
|
7
|
+
* once. V8's own `timeout` stays as a second guard for synchronous loops. This runs in the server
|
|
8
|
+
* process, so for hosted multi-user execution prefer the Deno runner (separate process).
|
|
9
|
+
*/
|
|
2
10
|
export declare class IsolateRunner implements SandboxRunner {
|
|
11
|
+
private readonly limits;
|
|
3
12
|
kind: "isolate";
|
|
13
|
+
constructor(limits?: SandboxLimits);
|
|
4
14
|
available(): Promise<boolean>;
|
|
5
15
|
execute(opts: ExecuteOptions, rpc: RpcBridge): Promise<ExecuteResult>;
|
|
6
16
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"isolate.d.ts","sourceRoot":"","sources":["../../src/sandbox/isolate.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"isolate.d.ts","sourceRoot":"","sources":["../../src/sandbox/isolate.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE1F,OAAO,EAA0I,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AAWzL;;;;;;GAMG;AACH,qBAAa,aAAc,YAAW,aAAa;IAGrC,OAAO,CAAC,QAAQ,CAAC,MAAM;IAFnC,IAAI,EAAG,SAAS,CAAU;gBAEG,MAAM,GAAE,aAA8B;IAE7D,SAAS,IAAI,OAAO,CAAC,OAAO,CAAC;IAW7B,OAAO,CAAC,IAAI,EAAE,cAAc,EAAE,GAAG,EAAE,SAAS,GAAG,OAAO,CAAC,aAAa,CAAC;CA2I5E"}
|
package/dist/sandbox/isolate.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { preflight } from './policy.js';
|
|
2
|
+
import { DEFAULT_LIMITS, LOG_LINE_OVERHEAD, LOG_TRUNCATED, LogSink, MAX_ERROR_MESSAGE, boundMessage, finishValue, policyMessage, resultTooLarge } from './limits.js';
|
|
2
3
|
async function loadIvm() {
|
|
3
4
|
const mod = await import('isolated-vm');
|
|
4
5
|
const candidate = (typeof mod.Isolate === 'function' ? mod : mod.default ?? {});
|
|
@@ -6,12 +7,22 @@ async function loadIvm() {
|
|
|
6
7
|
throw new Error('isolated-vm native binding unavailable');
|
|
7
8
|
return candidate;
|
|
8
9
|
}
|
|
10
|
+
/**
|
|
11
|
+
* isolated-vm sandbox: a fresh V8 isolate per execution with a heap cap. The host owns a
|
|
12
|
+
* wall-clock deadline that starts before setup: when it fires the isolate
|
|
13
|
+
* is disposed, which stops running code and rejects anything it awaits, and the execution settles
|
|
14
|
+
* once. V8's own `timeout` stays as a second guard for synchronous loops. This runs in the server
|
|
15
|
+
* process, so for hosted multi-user execution prefer the Deno runner (separate process).
|
|
16
|
+
*/
|
|
9
17
|
export class IsolateRunner {
|
|
18
|
+
limits;
|
|
10
19
|
kind = 'isolate';
|
|
20
|
+
constructor(limits = DEFAULT_LIMITS) {
|
|
21
|
+
this.limits = limits;
|
|
22
|
+
}
|
|
11
23
|
async available() {
|
|
12
24
|
try {
|
|
13
25
|
const ivm = await loadIvm();
|
|
14
|
-
// Confirm the native binding actually loaded by exercising it.
|
|
15
26
|
const iso = new ivm.Isolate({ memoryLimit: 16 });
|
|
16
27
|
iso.dispose();
|
|
17
28
|
return true;
|
|
@@ -22,78 +33,154 @@ export class IsolateRunner {
|
|
|
22
33
|
}
|
|
23
34
|
async execute(opts, rpc) {
|
|
24
35
|
const started = Date.now();
|
|
36
|
+
const limits = { ...this.limits, ...(opts.limits ?? {}) };
|
|
37
|
+
const timeoutMs = opts.timeoutMs ?? 15_000;
|
|
38
|
+
const logs = new LogSink(limits.maxLogBytes, limits.maxLogLines);
|
|
39
|
+
const done = (r) => ({ ...r, logs: logs.lines(), durationMs: Date.now() - started });
|
|
25
40
|
const policy = preflight(opts.code);
|
|
26
|
-
if (!policy.ok)
|
|
27
|
-
return {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
error: { name: 'PolicyError', message: policy.errors.join('; ') },
|
|
31
|
-
durationMs: Date.now() - started,
|
|
32
|
-
};
|
|
41
|
+
if (!policy.ok)
|
|
42
|
+
return done({ ok: false, error: { name: 'PolicyError', message: policyMessage(policy.errors) } });
|
|
43
|
+
if (Buffer.byteLength(opts.code, 'utf8') > limits.maxCodeBytes) {
|
|
44
|
+
return done({ ok: false, error: { name: 'CodeTooLarge', message: `Code exceeds ${limits.maxCodeBytes} bytes.` } });
|
|
33
45
|
}
|
|
34
|
-
// dynamic import — keeps the optional dep optional at runtime.
|
|
35
46
|
const ivm = await loadIvm();
|
|
36
|
-
const isolate = new ivm.Isolate({ memoryLimit: opts.memoryMb ?? 64 });
|
|
37
|
-
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
const logs = [];
|
|
41
|
-
// host-side log sink
|
|
42
|
-
await context.evalClosure(`globalThis.console = { log: (...a) => $0.applyIgnored(undefined, [a.map(String).join(' ')]),
|
|
43
|
-
error: (...a) => $0.applyIgnored(undefined, [a.map(String).join(' ')]),
|
|
44
|
-
warn: (...a) => $0.applyIgnored(undefined, [a.map(String).join(' ')]),
|
|
45
|
-
info: (...a) => $0.applyIgnored(undefined, [a.map(String).join(' ')]) };`, [(line) => logs.push(String(line))], { arguments: { reference: true } });
|
|
46
|
-
// RPC bridge — pass the host function directly; `arguments: { reference: true }`
|
|
47
|
-
// auto-wraps each argument as a Reference inside the isolate.
|
|
48
|
-
const hostRpc = async (binding, path, args) => {
|
|
49
|
-
const result = await rpc.dispatch({ binding, path, args });
|
|
50
|
-
return new ivm.ExternalCopy(result).copyInto();
|
|
51
|
-
};
|
|
52
|
-
// Safe to interpolate: binding names are pre-validated as JS identifiers by
|
|
53
|
-
// getSources() (src/sdk/sources/index.ts). Do NOT interpolate unvalidated strings here.
|
|
54
|
-
const namesLiteral = JSON.stringify(opts.bindings ?? []);
|
|
55
|
-
await context.evalClosure(`function makeProxy(binding, rpc) {
|
|
56
|
-
const handler = (path) => new Proxy(function(){}, {
|
|
57
|
-
get(_, key) { return handler([...path, String(key)]); },
|
|
58
|
-
apply(_, __, args) {
|
|
59
|
-
return rpc.apply(
|
|
60
|
-
undefined,
|
|
61
|
-
[binding, path, args],
|
|
62
|
-
{ arguments: { copy: true }, result: { promise: true, copy: true } },
|
|
63
|
-
).then(r => {
|
|
64
|
-
if (!r.ok) { const e = new Error(r.error.message); e.name = r.error.name; throw e; }
|
|
65
|
-
return r.value;
|
|
66
|
-
});
|
|
67
|
-
},
|
|
68
|
-
});
|
|
69
|
-
return handler([]);
|
|
70
|
-
}
|
|
71
|
-
for (const name of ${namesLiteral}) { globalThis[name] = makeProxy(name, $0); }`, [hostRpc], { arguments: { reference: true } });
|
|
72
|
-
try {
|
|
73
|
-
const wrapped = `(async () => { ${opts.code}\n })()`;
|
|
74
|
-
const script = await isolate.compileScript(wrapped);
|
|
75
|
-
const result = await script.run(context, {
|
|
76
|
-
timeout: opts.timeoutMs ?? 15_000,
|
|
77
|
-
promise: true,
|
|
78
|
-
copy: true,
|
|
79
|
-
});
|
|
80
|
-
return { ok: true, value: result, logs, durationMs: Date.now() - started };
|
|
81
|
-
}
|
|
82
|
-
catch (err) {
|
|
83
|
-
const e = err;
|
|
84
|
-
return {
|
|
85
|
-
ok: false,
|
|
86
|
-
logs,
|
|
87
|
-
error: { name: e.name ?? 'Error', message: e.message ?? String(err), stack: e.stack },
|
|
88
|
-
durationMs: Date.now() - started,
|
|
89
|
-
};
|
|
90
|
-
}
|
|
91
|
-
finally {
|
|
47
|
+
const isolate = new ivm.Isolate({ memoryLimit: Math.max(16, opts.memoryMb ?? 64) });
|
|
48
|
+
let disposed = false;
|
|
49
|
+
const dispose = () => { if (!disposed) {
|
|
50
|
+
disposed = true;
|
|
92
51
|
try {
|
|
93
|
-
context.release();
|
|
94
52
|
isolate.dispose();
|
|
95
53
|
}
|
|
96
54
|
catch { /* ignore */ }
|
|
55
|
+
} };
|
|
56
|
+
let stop;
|
|
57
|
+
const stopped = new Promise(resolve => { stop = resolve; });
|
|
58
|
+
const deadline = setTimeout(() => stop({ ok: false, error: { name: 'TimeoutError', message: `Execution exceeded ${timeoutMs}ms` } }), timeoutMs);
|
|
59
|
+
const run = async () => {
|
|
60
|
+
const context = await isolate.createContext();
|
|
61
|
+
const jail = context.global;
|
|
62
|
+
await jail.set('global', jail.derefInto());
|
|
63
|
+
// Trusted primitives are captured here, before any user code runs, and every budget (logs,
|
|
64
|
+
// SDK arguments, result, error) is enforced with them inside the isolate, in UTF-8 bytes, so
|
|
65
|
+
// replacing JSON.stringify, String.prototype methods or Promise.prototype.then cannot push an
|
|
66
|
+
// oversized value into the host copy path. The host re-checks everything it receives.
|
|
67
|
+
const L = {
|
|
68
|
+
maxLogBytes: limits.maxLogBytes, maxLogLines: limits.maxLogLines, overhead: LOG_LINE_OVERHEAD, marker: LOG_TRUNCATED,
|
|
69
|
+
maxRpcArgBytes: limits.maxRpcArgBytes, maxResultBytes: limits.maxResultBytes, maxError: MAX_ERROR_MESSAGE,
|
|
70
|
+
};
|
|
71
|
+
await context.evalClosure(`const L = ${JSON.stringify(L)};
|
|
72
|
+
const S = JSON.stringify, Str = String, apply = Reflect.apply, then = Promise.prototype.then;
|
|
73
|
+
const cca = String.prototype.charCodeAt, sl = String.prototype.slice, join = Array.prototype.join, map = Array.prototype.map;
|
|
74
|
+
const freeze = Object.freeze, define = Object.defineProperty, isArray = Array.isArray, create = Object.create;
|
|
75
|
+
const bytes = (s) => { let n = 0; const len = s.length; for (let i = 0; i < len; i++) { const c = apply(cca, s, [i]);
|
|
76
|
+
n += c < 0x80 ? 1 : c < 0x800 ? 2 : (c >= 0xD800 && c <= 0xDBFF) ? (i++, 4) : 3; } return n; };
|
|
77
|
+
const cut = (s, n) => s.length > n ? apply(sl, s, [0, n]) : s;
|
|
78
|
+
const show = (v) => { if (typeof v === 'string') return v; try { const j = S(v); return j === undefined ? Str(v) : j; } catch { return Str(v); } };
|
|
79
|
+
let used = 0, lines = 0, done = false;
|
|
80
|
+
const log = (...a) => {
|
|
81
|
+
if (done) return;
|
|
82
|
+
let text = cut(apply(join, apply(map, a, [show]), [' ']), L.maxLogBytes);
|
|
83
|
+
used += bytes(text) + L.overhead; lines++;
|
|
84
|
+
if (used > L.maxLogBytes - L.marker.length - L.overhead || lines >= L.maxLogLines) { done = true; text = L.marker; }
|
|
85
|
+
$0.applyIgnored(undefined, [text]);
|
|
86
|
+
};
|
|
87
|
+
define(globalThis, 'console', { value: freeze({ log, error: log, warn: log, info: log, debug: log }), writable: false, configurable: false });
|
|
88
|
+
const argsJson = (args) => { const j = S(isArray(args) ? args : []); if (bytes(j) > L.maxRpcArgBytes) return undefined; return j; };
|
|
89
|
+
const ok = (v) => { let j; try { j = S(v === undefined ? null : v); } catch (e) { return err({ name: 'TypeError', message: 'The returned value is not JSON-serializable' }); }
|
|
90
|
+
if (typeof j !== 'string') j = 'null';
|
|
91
|
+
const b = bytes(j); return b > L.maxResultBytes ? 'R' + b : 'V' + j; };
|
|
92
|
+
const err = (e) => { let name = 'Error', message = '', status;
|
|
93
|
+
try { name = cut(Str(e && e.name || 'Error'), 100); message = cut(Str(e && e.message !== undefined ? e.message : e), L.maxError); status = e && typeof e.status === 'number' ? e.status : undefined; } catch {}
|
|
94
|
+
// Null-prototype record of primitives: no inherited toJSON or getters can reshape it.
|
|
95
|
+
const rec = create(null); rec.name = name; rec.message = message; if (typeof status === 'number') rec.status = status;
|
|
96
|
+
// name/message were cut before serializing, so the JSON is bounded (escaping at most 6x);
|
|
97
|
+
// it is never sliced, which could break it and lose the name and status.
|
|
98
|
+
let out; try { out = S(rec); } catch {
|
|
99
|
+
const fb = create(null); fb.name = 'Error'; fb.message = 'The error could not be serialized.'; if (typeof status === 'number') fb.status = status;
|
|
100
|
+
out = S(fb); }
|
|
101
|
+
return 'E' + out; };
|
|
102
|
+
define(globalThis, '__fedregInternal', { value: freeze({ argsJson,
|
|
103
|
+
run: (fn) => apply(then, fn(), [ok, err]) }), writable: false, configurable: false, enumerable: false });`, [(line) => logs.push(String(line))], { arguments: { reference: true } });
|
|
104
|
+
let pending = 0;
|
|
105
|
+
const hostRpc = async (binding, path, argsJson) => {
|
|
106
|
+
const fail = (name, message) => new ivm.ExternalCopy({ ok: false, error: { name, message } }).copyInto();
|
|
107
|
+
if (disposed)
|
|
108
|
+
return fail('AbortError', 'Execution has ended.');
|
|
109
|
+
if (pending >= limits.maxPendingRpc)
|
|
110
|
+
return fail('TooManyPendingCalls', `At most ${limits.maxPendingRpc} SDK calls may be pending at once.`);
|
|
111
|
+
if (typeof argsJson !== 'string' || Buffer.byteLength(argsJson, 'utf8') > limits.maxRpcArgBytes)
|
|
112
|
+
return fail('ArgumentsTooLarge', `SDK call arguments exceed ${limits.maxRpcArgBytes} bytes.`);
|
|
113
|
+
let args;
|
|
114
|
+
try {
|
|
115
|
+
args = JSON.parse(argsJson);
|
|
116
|
+
}
|
|
117
|
+
catch {
|
|
118
|
+
return fail('TypeError', 'SDK arguments must be JSON-serializable.');
|
|
119
|
+
}
|
|
120
|
+
pending++;
|
|
121
|
+
try {
|
|
122
|
+
const result = await rpc.dispatch({ binding, path, args });
|
|
123
|
+
return new ivm.ExternalCopy(result).copyInto();
|
|
124
|
+
}
|
|
125
|
+
finally {
|
|
126
|
+
pending--;
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
// Binding names are pre-validated JS identifiers (getSources); safe to embed as JSON.
|
|
130
|
+
await context.evalClosure(`const internal = globalThis.__fedregInternal;
|
|
131
|
+
function makeProxy(binding, rpc) {
|
|
132
|
+
const handler = (path) => new Proxy(function(){}, {
|
|
133
|
+
get(_, key) { return typeof key === 'symbol' ? undefined : handler([...path, String(key)]); },
|
|
134
|
+
apply(_, __, args) {
|
|
135
|
+
let json;
|
|
136
|
+
try { json = internal.argsJson(args); } catch { return Promise.reject(new TypeError('SDK arguments must be JSON-serializable')); }
|
|
137
|
+
if (json === undefined) { const e = new Error('SDK call arguments exceed ${limits.maxRpcArgBytes} bytes.'); e.name = 'ArgumentsTooLarge'; return Promise.reject(e); }
|
|
138
|
+
return rpc.apply(undefined, [binding, path, json], { arguments: { copy: true }, result: { promise: true, copy: true } })
|
|
139
|
+
.then(r => {
|
|
140
|
+
if (!r.ok) { const e = new Error(r.error.message); e.name = r.error.name; if (typeof r.error.status === 'number') e.status = r.error.status; throw e; }
|
|
141
|
+
return r.value;
|
|
142
|
+
});
|
|
143
|
+
},
|
|
144
|
+
});
|
|
145
|
+
return handler([]);
|
|
146
|
+
}
|
|
147
|
+
for (const name of ${JSON.stringify(opts.bindings ?? [])}) {
|
|
148
|
+
Object.defineProperty(globalThis, name, { value: makeProxy(name, $0), writable: false, configurable: false });
|
|
149
|
+
}`, [hostRpc], { arguments: { reference: true } });
|
|
150
|
+
// 'V' + JSON (value), 'R' + bytes (result over budget, never transferred), 'E' + JSON (bounded
|
|
151
|
+
// error, so an SDK error's status survives the copy).
|
|
152
|
+
const script = await isolate.compileScript(`__fedregInternal.run(async () => { ${opts.code}\n })`);
|
|
153
|
+
const tagged = await script.run(context, { timeout: timeoutMs, promise: true, copy: true });
|
|
154
|
+
if (typeof tagged === 'string' && tagged.startsWith('V'))
|
|
155
|
+
return finishValue(tagged.slice(1), limits);
|
|
156
|
+
if (typeof tagged === 'string' && tagged.startsWith('R'))
|
|
157
|
+
return { ok: false, error: resultTooLarge(Number(tagged.slice(1)), limits) };
|
|
158
|
+
if (typeof tagged !== 'string' || !tagged.startsWith('E'))
|
|
159
|
+
return { ok: false, error: { name: 'SandboxProtocolError', message: 'The sandbox returned an invalid result.' } };
|
|
160
|
+
let e;
|
|
161
|
+
try {
|
|
162
|
+
e = JSON.parse(tagged.slice(1));
|
|
163
|
+
}
|
|
164
|
+
catch {
|
|
165
|
+
e = { name: 'Error', message: 'The sandbox returned an unreadable error.' };
|
|
166
|
+
}
|
|
167
|
+
return { ok: false, error: { name: String(e.name ?? 'Error').slice(0, 100), message: boundMessage(String(e.message ?? '')), ...(typeof e.status === 'number' ? { status: e.status } : {}) } };
|
|
168
|
+
};
|
|
169
|
+
try {
|
|
170
|
+
const outcome = await Promise.race([
|
|
171
|
+
run().catch((err) => {
|
|
172
|
+
const e = err;
|
|
173
|
+
if (disposed)
|
|
174
|
+
return { ok: false, error: { name: 'TimeoutError', message: `Execution exceeded ${timeoutMs}ms` } };
|
|
175
|
+
return { ok: false, error: { name: String(e?.name ?? 'Error').slice(0, 100), message: boundMessage(String(e?.message ?? err)), ...(typeof e?.status === 'number' ? { status: e.status } : {}) } };
|
|
176
|
+
}),
|
|
177
|
+
stopped,
|
|
178
|
+
]);
|
|
179
|
+
return done(outcome);
|
|
180
|
+
}
|
|
181
|
+
finally {
|
|
182
|
+
clearTimeout(deadline);
|
|
183
|
+
dispose();
|
|
97
184
|
}
|
|
98
185
|
}
|
|
99
186
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"isolate.js","sourceRoot":"","sources":["../../src/sandbox/isolate.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"isolate.js","sourceRoot":"","sources":["../../src/sandbox/isolate.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Byte budgets for one execution. They bound what the host buffers and what reaches the model,
|
|
3
|
+
* independently of the V8 heap limit inside the sandbox. The defaults are deliberately generous:
|
|
4
|
+
* they exist to stop runaway or hostile output, not to constrain ordinary queries (a filtered
|
|
5
|
+
* `ecfr.full` part or a page of Federal Register documents fits comfortably).
|
|
6
|
+
*/
|
|
7
|
+
export interface SandboxLimits {
|
|
8
|
+
/** Largest accepted user code. */
|
|
9
|
+
maxCodeBytes: number;
|
|
10
|
+
/** Total log size kept (text plus per-line overhead); later lines are dropped with a marker. */
|
|
11
|
+
maxLogBytes: number;
|
|
12
|
+
/** Most log lines kept, however short. */
|
|
13
|
+
maxLogLines: number;
|
|
14
|
+
/** Largest JSON-serialized return value; bigger results fail with ResultTooLarge. */
|
|
15
|
+
maxResultBytes: number;
|
|
16
|
+
/** Largest JSON-serialized argument list for one SDK call. */
|
|
17
|
+
maxRpcArgBytes: number;
|
|
18
|
+
/** SDK calls that may be awaiting a response at once. */
|
|
19
|
+
maxPendingRpc: number;
|
|
20
|
+
/** Deno only: total bytes the child may write to stdout over the execution. */
|
|
21
|
+
maxStdoutBytes: number;
|
|
22
|
+
/** Deno only: largest single frame (line) on stdout. */
|
|
23
|
+
maxFrameBytes: number;
|
|
24
|
+
}
|
|
25
|
+
export declare const DEFAULT_LIMITS: Readonly<SandboxLimits>;
|
|
26
|
+
/** Bytes charged per log line on top of its text, so empty-line floods are bounded too. */
|
|
27
|
+
export declare const LOG_LINE_OVERHEAD = 16;
|
|
28
|
+
export declare const LOG_TRUNCATED = "[logs truncated]";
|
|
29
|
+
/** Host-side log budget. The sandboxes enforce the same budget before sending (defense in depth). */
|
|
30
|
+
export declare class LogSink {
|
|
31
|
+
private readonly max;
|
|
32
|
+
private readonly maxLines;
|
|
33
|
+
private readonly out;
|
|
34
|
+
private bytes;
|
|
35
|
+
private dropped;
|
|
36
|
+
constructor(max: number, maxLines?: number);
|
|
37
|
+
push(line: string): void;
|
|
38
|
+
lines(): string[];
|
|
39
|
+
}
|
|
40
|
+
export declare function checkRpcArgs(args: unknown[], limits: SandboxLimits): {
|
|
41
|
+
name: string;
|
|
42
|
+
message: string;
|
|
43
|
+
} | undefined;
|
|
44
|
+
/** Turn the sandbox's JSON result into the execute envelope, enforcing maxResultBytes. */
|
|
45
|
+
export declare function finishValue(json: string, limits: SandboxLimits): {
|
|
46
|
+
ok: boolean;
|
|
47
|
+
value?: unknown;
|
|
48
|
+
error?: {
|
|
49
|
+
name: string;
|
|
50
|
+
message: string;
|
|
51
|
+
};
|
|
52
|
+
};
|
|
53
|
+
export declare function resultTooLarge(size: number, limits: SandboxLimits): {
|
|
54
|
+
name: string;
|
|
55
|
+
message: string;
|
|
56
|
+
};
|
|
57
|
+
/** Longest error message any execution reports. */
|
|
58
|
+
export declare const MAX_ERROR_MESSAGE = 4000;
|
|
59
|
+
export declare function boundMessage(message: string): string;
|
|
60
|
+
/** Preflight diagnostics: distinct messages only, at most 10, bounded in total. */
|
|
61
|
+
export declare function policyMessage(errors: string[]): string;
|
|
62
|
+
//# sourceMappingURL=limits.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"limits.d.ts","sourceRoot":"","sources":["../../src/sandbox/limits.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,WAAW,aAAa;IAC5B,kCAAkC;IAClC,YAAY,EAAE,MAAM,CAAC;IACrB,gGAAgG;IAChG,WAAW,EAAE,MAAM,CAAC;IACpB,0CAA0C;IAC1C,WAAW,EAAE,MAAM,CAAC;IACpB,qFAAqF;IACrF,cAAc,EAAE,MAAM,CAAC;IACvB,8DAA8D;IAC9D,cAAc,EAAE,MAAM,CAAC;IACvB,yDAAyD;IACzD,aAAa,EAAE,MAAM,CAAC;IACtB,+EAA+E;IAC/E,cAAc,EAAE,MAAM,CAAC;IACvB,wDAAwD;IACxD,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,eAAO,MAAM,cAAc,EAAE,QAAQ,CAAC,aAAa,CAWjD,CAAC;AAEH,2FAA2F;AAC3F,eAAO,MAAM,iBAAiB,KAAK,CAAC;AACpC,eAAO,MAAM,aAAa,qBAAqB,CAAC;AAEhD,qGAAqG;AACrG,qBAAa,OAAO;IAIN,OAAO,CAAC,QAAQ,CAAC,GAAG;IAAU,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAHnE,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAgB;IACpC,OAAO,CAAC,KAAK,CAAK;IAClB,OAAO,CAAC,OAAO,CAAS;gBACK,GAAG,EAAE,MAAM,EAAmB,QAAQ,SAA6B;IAChG,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAcxB,KAAK,IAAI,MAAM,EAAE;CAClB;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,aAAa,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAOlH;AAED,0FAA0F;AAC1F,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,GAAG;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,CAK5I;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAMrG;AAED,mDAAmD;AACnD,eAAO,MAAM,iBAAiB,OAAO,CAAC;AAEtC,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED,mFAAmF;AACnF,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,CAItD"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
export const DEFAULT_LIMITS = Object.freeze({
|
|
2
|
+
maxCodeBytes: 256 * 1024,
|
|
3
|
+
maxLogBytes: 1024 * 1024,
|
|
4
|
+
maxLogLines: 10_000,
|
|
5
|
+
maxResultBytes: 8 * 1024 * 1024,
|
|
6
|
+
maxRpcArgBytes: 1024 * 1024,
|
|
7
|
+
// Matches the per-execute public call budget, so `Promise.all` over a full budget still works.
|
|
8
|
+
maxPendingRpc: 100,
|
|
9
|
+
maxStdoutBytes: 128 * 1024 * 1024,
|
|
10
|
+
// A result travels as an escaped JSON string inside a frame, so allow for escaping overhead.
|
|
11
|
+
maxFrameBytes: 48 * 1024 * 1024,
|
|
12
|
+
});
|
|
13
|
+
/** Bytes charged per log line on top of its text, so empty-line floods are bounded too. */
|
|
14
|
+
export const LOG_LINE_OVERHEAD = 16;
|
|
15
|
+
export const LOG_TRUNCATED = '[logs truncated]';
|
|
16
|
+
/** Host-side log budget. The sandboxes enforce the same budget before sending (defense in depth). */
|
|
17
|
+
export class LogSink {
|
|
18
|
+
max;
|
|
19
|
+
maxLines;
|
|
20
|
+
out = [];
|
|
21
|
+
bytes = 0;
|
|
22
|
+
dropped = false;
|
|
23
|
+
constructor(max, maxLines = DEFAULT_LIMITS.maxLogLines) {
|
|
24
|
+
this.max = max;
|
|
25
|
+
this.maxLines = maxLines;
|
|
26
|
+
}
|
|
27
|
+
push(line) {
|
|
28
|
+
if (this.dropped)
|
|
29
|
+
return;
|
|
30
|
+
const text = line.length > this.max ? line.slice(0, this.max) : line;
|
|
31
|
+
const cost = Buffer.byteLength(text, 'utf8') + LOG_LINE_OVERHEAD;
|
|
32
|
+
// Room for the marker is reserved up front, so the total never exceeds the budget.
|
|
33
|
+
const reserve = Buffer.byteLength(LOG_TRUNCATED, 'utf8') + LOG_LINE_OVERHEAD;
|
|
34
|
+
if (text === LOG_TRUNCATED || this.out.length >= this.maxLines - 1 || this.bytes + cost > this.max - reserve) {
|
|
35
|
+
this.dropped = true;
|
|
36
|
+
if (reserve <= this.max)
|
|
37
|
+
this.out.push(LOG_TRUNCATED);
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
this.bytes += cost;
|
|
41
|
+
this.out.push(text);
|
|
42
|
+
}
|
|
43
|
+
lines() { return [...this.out]; }
|
|
44
|
+
}
|
|
45
|
+
export function checkRpcArgs(args, limits) {
|
|
46
|
+
let size;
|
|
47
|
+
try {
|
|
48
|
+
size = Buffer.byteLength(JSON.stringify(args) ?? '', 'utf8');
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
return { name: 'TypeError', message: 'SDK arguments must be JSON-serializable.' };
|
|
52
|
+
}
|
|
53
|
+
return size > limits.maxRpcArgBytes
|
|
54
|
+
? { name: 'ArgumentsTooLarge', message: `SDK call arguments exceed ${limits.maxRpcArgBytes} bytes.` }
|
|
55
|
+
: undefined;
|
|
56
|
+
}
|
|
57
|
+
/** Turn the sandbox's JSON result into the execute envelope, enforcing maxResultBytes. */
|
|
58
|
+
export function finishValue(json, limits) {
|
|
59
|
+
const size = Buffer.byteLength(json, 'utf8');
|
|
60
|
+
if (size > limits.maxResultBytes)
|
|
61
|
+
return { ok: false, error: resultTooLarge(size, limits) };
|
|
62
|
+
try {
|
|
63
|
+
return { ok: true, value: JSON.parse(json) };
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
return { ok: false, error: { name: 'SandboxProtocolError', message: 'The sandbox returned an invalid result.' } };
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
export function resultTooLarge(size, limits) {
|
|
70
|
+
return {
|
|
71
|
+
name: 'ResultTooLarge',
|
|
72
|
+
message: `The returned value is ${size} bytes; the limit is ${limits.maxResultBytes}. Return only what you need: `
|
|
73
|
+
+ 'request fewer records (per_page), select fields, filter ecfr.full by part or section, map records to the attributes you need, or slice long text.',
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
/** Longest error message any execution reports. */
|
|
77
|
+
export const MAX_ERROR_MESSAGE = 4000;
|
|
78
|
+
export function boundMessage(message) {
|
|
79
|
+
return message.length > MAX_ERROR_MESSAGE ? `${message.slice(0, MAX_ERROR_MESSAGE)}… [truncated]` : message;
|
|
80
|
+
}
|
|
81
|
+
/** Preflight diagnostics: distinct messages only, at most 10, bounded in total. */
|
|
82
|
+
export function policyMessage(errors) {
|
|
83
|
+
const unique = [...new Set(errors)];
|
|
84
|
+
const shown = unique.slice(0, 10).join('; ');
|
|
85
|
+
return boundMessage(unique.length > 10 ? `${shown}; and ${unique.length - 10} more` : shown);
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=limits.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"limits.js","sourceRoot":"","sources":["../../src/sandbox/limits.ts"],"names":[],"mappings":"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"}
|
package/dist/sandbox/types.d.ts
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
|
+
import type { SandboxLimits } from './limits.js';
|
|
1
2
|
export interface ExecuteOptions {
|
|
2
3
|
code: string;
|
|
3
4
|
timeoutMs?: number;
|
|
4
5
|
memoryMb?: number;
|
|
5
6
|
bindings?: string[];
|
|
7
|
+
/** Overrides for the runner's byte budgets. */
|
|
8
|
+
limits?: Partial<SandboxLimits>;
|
|
6
9
|
}
|
|
7
10
|
export interface ExecuteResult {
|
|
8
11
|
ok: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/sandbox/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/sandbox/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEjD,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,+CAA+C;IAC/C,MAAM,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,CAAC;CACjC;AAED,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,OAAO,CAAC;IACZ,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,KAAK,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC3E,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,MAAM,GAAG,MAAM,CAAC;AAEtD,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,SAAS,GAAG,MAAM,GAAG,aAAa,CAAC;IACzC,SAAS,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;IAC9B,OAAO,CAAC,IAAI,EAAE,cAAc,EAAE,GAAG,EAAE,SAAS,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;CACvE;AAED,MAAM,WAAW,OAAO;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,IAAI,EAAE,OAAO,EAAE,CAAC;CACjB;AAED,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC;QAAE,EAAE,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,OAAO,EAAE,MAAM,CAAC;YAAC,MAAM,CAAC,EAAE,MAAM,CAAA;SAAE,CAAA;KAAE,CAAC,CAAC;CAChI"}
|
package/dist/sdk/bindings.js
CHANGED
|
@@ -13,7 +13,7 @@ export function buildSdk(cfg) {
|
|
|
13
13
|
methods: Object.freeze(methods),
|
|
14
14
|
meta: sources.map(({ name, label, enabled, disabledReason }) => ({ name, label, enabled, disabledReason })),
|
|
15
15
|
registeredNames: sources.map(s => s.name),
|
|
16
|
-
version: () => '2.2.
|
|
16
|
+
version: () => '2.2.3', // x-release-version
|
|
17
17
|
};
|
|
18
18
|
}
|
|
19
19
|
//# sourceMappingURL=bindings.js.map
|
package/dist/server/mcpServer.js
CHANGED
|
@@ -34,7 +34,7 @@ function cachedInputSchema(name, jsonSchema) {
|
|
|
34
34
|
return converted;
|
|
35
35
|
}
|
|
36
36
|
export function buildMcpServer(deps, requestCtx) {
|
|
37
|
-
const server = new McpServer({ name: 'fedreg-mcp-server', version: '2.2.
|
|
37
|
+
const server = new McpServer({ name: 'fedreg-mcp-server', version: '2.2.3' }, // x-release-version
|
|
38
38
|
{
|
|
39
39
|
capabilities: { tools: {} },
|
|
40
40
|
cacheHints: { 'tools/list': LIST_CACHE_HINT, 'server/discover': LIST_CACHE_HINT },
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@blen/fedreg-mcp-server",
|
|
3
|
-
"version": "2.2.
|
|
3
|
+
"version": "2.2.3",
|
|
4
4
|
"description": "Code-mode MCP server for the U.S. Federal Register, Electronic Code of Federal Regulations, and regulations.gov APIs.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "BLEN, Inc. (https://blenlabs.com)",
|