Skip to content

Commit 498ed3f

Browse files
committed
feat: US-061 - Split composeBridgeCode into static and post-restore parts
1 parent d9adc89 commit 498ed3f

2 files changed

Lines changed: 72 additions & 81 deletions

File tree

packages/secure-exec-node/src/execution-driver.ts

Lines changed: 71 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -36,16 +36,23 @@ import { createProcessConfigForExecution } from "./bridge-setup.js";
3636

3737
export { NodeExecutionDriverOptions };
3838

39+
// Module-level cache for the static bridge IIFE (identical across all sessions)
40+
let staticBridgeCodeCache: string | null = null;
41+
3942
/**
40-
* Compose the default bridge code for snapshot warm-up.
41-
* Uses timingMitigation='none' and default budget values so the snapshot
42-
* is ready for the most common session configuration.
43+
* Compose the config-independent bridge IIFE. Output is byte-for-byte
44+
* identical regardless of session options — uses DEFAULT values for all
45+
* config that gets overridden by the post-restore script.
46+
* Used for snapshot creation and as the base of every session's bridge code.
4347
*/
44-
export function composeBridgeCodeForWarmup(): string {
48+
export function composeStaticBridgeCode(): string {
49+
if (staticBridgeCodeCache) return staticBridgeCodeCache;
50+
4551
const parts: string[] = [];
4652

4753
parts.push(getIvmCompatShimSource());
4854

55+
// Default budget values — overridden per-session by post-restore script
4956
parts.push(`globalThis._maxTimers = ${DEFAULT_MAX_TIMERS};`);
5057
parts.push(`globalThis._maxHandles = ${DEFAULT_MAX_HANDLES};`);
5158
parts.push(`globalThis.__runtimeBridgeSetupConfig = ${JSON.stringify({
@@ -61,7 +68,7 @@ export function composeBridgeCodeForWarmup(): string {
6168
parts.push(getRawBridgeCode());
6269
parts.push(getBridgeAttachCode());
6370

64-
// Default: no timing mitigation
71+
// Default: no timing mitigation (freeze applied via post-restore script)
6572
parts.push(getIsolateRuntimeSource("applyTimingMitigationOff"));
6673

6774
parts.push(getRequireSetupCode());
@@ -73,16 +80,64 @@ export function composeBridgeCodeForWarmup(): string {
7380
})};`);
7481
parts.push(getIsolateRuntimeSource("applyCustomGlobalPolicy"));
7582

76-
// Apply default config via __runtimeApplyConfig (no timing freeze for warmup)
83+
staticBridgeCodeCache = parts.join("\n");
84+
return staticBridgeCodeCache;
85+
}
86+
87+
/**
88+
* Compose the per-session post-restore script. Overrides default config
89+
* values from the static IIFE with session-specific values, applies timing
90+
* mitigation, and handles polyfill loading.
91+
*/
92+
export function composePostRestoreScript(config: {
93+
timingMitigation: TimingMitigation;
94+
frozenTimeMs: number;
95+
maxTimers?: number;
96+
maxHandles?: number;
97+
initialCwd?: string;
98+
payloadLimitBytes?: number;
99+
payloadLimitErrorCode?: string;
100+
}): string {
101+
const parts: string[] = [];
102+
103+
// Override per-session budget values if they differ from defaults
104+
if (config.maxTimers !== undefined) {
105+
parts.push(`globalThis._maxTimers = ${config.maxTimers};`);
106+
}
107+
if (config.maxHandles !== undefined) {
108+
parts.push(`globalThis._maxHandles = ${config.maxHandles};`);
109+
}
110+
111+
// Override initial cwd for module resolution
112+
if (config.initialCwd && config.initialCwd !== DEFAULT_SANDBOX_CWD) {
113+
parts.push(`if (globalThis._currentModule) globalThis._currentModule.dirname = ${JSON.stringify(config.initialCwd)};`);
114+
}
115+
116+
// Apply config (timing mitigation, payload limits) via __runtimeApplyConfig
77117
parts.push(`globalThis.__runtimeApplyConfig(${JSON.stringify({
78-
timingMitigation: "none",
79-
payloadLimitBytes: DEFAULT_ISOLATE_JSON_PAYLOAD_BYTES,
80-
payloadLimitErrorCode: PAYLOAD_LIMIT_ERROR_CODE,
118+
timingMitigation: config.timingMitigation,
119+
frozenTimeMs: config.timingMitigation === "freeze" ? config.frozenTimeMs : undefined,
120+
payloadLimitBytes: config.payloadLimitBytes,
121+
payloadLimitErrorCode: config.payloadLimitErrorCode,
81122
})});`);
82123

83124
return parts.join("\n");
84125
}
85126

127+
/**
128+
* Compose the default bridge code for snapshot warm-up.
129+
* Uses timingMitigation='none' and default budget values so the snapshot
130+
* is ready for the most common session configuration.
131+
*/
132+
export function composeBridgeCodeForWarmup(): string {
133+
return composeStaticBridgeCode() + "\n" + composePostRestoreScript({
134+
timingMitigation: "off",
135+
frozenTimeMs: 0,
136+
payloadLimitBytes: DEFAULT_ISOLATE_JSON_PAYLOAD_BYTES,
137+
payloadLimitErrorCode: PAYLOAD_LIMIT_ERROR_CODE,
138+
});
139+
}
140+
86141
const MAX_ERROR_MESSAGE_CHARS = 8192;
87142

88143
function boundErrorMessage(message: string): string {
@@ -100,9 +155,6 @@ export class NodeExecutionDriver implements RuntimeDriver {
100155
private v8InitPromise: Promise<void> | null = null;
101156
private v8RuntimeOverride: V8Runtime | null;
102157

103-
// Cached bridge code (same across executions)
104-
private bridgeCodeCache: string | null = null;
105-
106158
constructor(options: NodeExecutionDriverOptions) {
107159
this.v8RuntimeOverride = options.v8Runtime ?? null;
108160
this.memoryLimit = options.memoryLimit ?? 128;
@@ -222,81 +274,20 @@ export class NodeExecutionDriver implements RuntimeDriver {
222274
});
223275
}
224276

225-
/** Build the config-independent bridge IIFE (cached across executions). */
226-
private getBridgeIIFE(): string {
227-
if (this.bridgeCodeCache) return this.bridgeCodeCache;
228-
229-
const parts: string[] = [];
230-
231-
// 1. ivm-compat shim (wraps bridge functions with .applySync/.applySyncPromise)
232-
parts.push(getIvmCompatShimSource());
233-
234-
// 2. Config value injections
235-
if (this.deps.maxTimers !== undefined) {
236-
parts.push(`globalThis._maxTimers = ${this.deps.maxTimers};`);
237-
}
238-
if (this.deps.maxHandles !== undefined) {
239-
parts.push(`globalThis._maxHandles = ${this.deps.maxHandles};`);
240-
}
241-
parts.push(`globalThis.__runtimeBridgeSetupConfig = ${JSON.stringify({
242-
initialCwd: this.deps.processConfig.cwd ?? "/",
243-
jsonPayloadLimitBytes: this.deps.isolateJsonPayloadLimitBytes,
244-
payloadLimitErrorCode: PAYLOAD_LIMIT_ERROR_CODE,
245-
})};`);
246-
247-
// 3. Global exposure helpers
248-
parts.push(getIsolateRuntimeSource("globalExposureHelpers"));
249-
250-
// 4. Initial bridge globals setup (defines __runtimeApplyConfig)
251-
parts.push(getInitialBridgeGlobalsSetupCode());
252-
253-
// 5. Console setup (hooks into _log/_error)
254-
parts.push(getConsoleSetupCode());
255-
256-
// 5b. Filesystem facade (_fs object wrapping individual _fs* bridge functions)
257-
parts.push(getIsolateRuntimeSource("setupFsFacade"));
258-
259-
// 6. Bridge bundle IIFE
260-
parts.push(getRawBridgeCode());
261-
262-
// 7. Bridge attach
263-
parts.push(getBridgeAttachCode());
264-
265-
// 8. Timing mitigation — default performance polyfill (freeze applied via __runtimeApplyConfig)
266-
parts.push(getIsolateRuntimeSource("applyTimingMitigationOff"));
267-
268-
// 9. Require setup
269-
parts.push(getRequireSetupCode());
270-
271-
// 10. CJS module/exports globals (for run() and exec() with filePath)
272-
parts.push(getIsolateRuntimeSource("initCommonjsModuleGlobals"));
273-
274-
// 11. Harden custom globals (non-writable/configurable for hardened, mutable for mutable)
275-
parts.push(`globalThis.__runtimeCustomGlobalPolicy = ${JSON.stringify({
276-
hardenedGlobals: HARDENED_NODE_CUSTOM_GLOBALS,
277-
mutableGlobals: MUTABLE_NODE_CUSTOM_GLOBALS,
278-
})};`);
279-
parts.push(getIsolateRuntimeSource("applyCustomGlobalPolicy"));
280-
281-
this.bridgeCodeCache = parts.join("\n");
282-
return this.bridgeCodeCache;
283-
}
284-
285-
/** Compose the full bridge code: cached IIFE + per-execution __runtimeApplyConfig call. */
277+
/** Compose the full bridge code: static IIFE + per-execution post-restore script. */
286278
private composeBridgeCode(
287279
timingMitigation: TimingMitigation,
288280
frozenTimeMs: number,
289281
): string {
290-
const iife = this.getBridgeIIFE();
291-
292-
// Append per-execution config application via __runtimeApplyConfig
293-
const configCall = `globalThis.__runtimeApplyConfig(${JSON.stringify({
282+
return composeStaticBridgeCode() + "\n" + composePostRestoreScript({
294283
timingMitigation,
295-
frozenTimeMs: timingMitigation === "freeze" ? frozenTimeMs : undefined,
284+
frozenTimeMs,
285+
maxTimers: this.deps.maxTimers,
286+
maxHandles: this.deps.maxHandles,
287+
initialCwd: this.deps.processConfig.cwd ?? DEFAULT_SANDBOX_CWD,
296288
payloadLimitBytes: this.deps.isolateJsonPayloadLimitBytes,
297289
payloadLimitErrorCode: PAYLOAD_LIMIT_ERROR_CODE,
298-
})});`;
299-
return iife + "\n" + configCall;
290+
});
300291
}
301292

302293
private async executeInternal<T = unknown>(options: {

packages/secure-exec-node/src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ export {
2626
} from "./polyfills.js";
2727

2828
// Node execution driver
29-
export { NodeExecutionDriver, composeBridgeCodeForWarmup } from "./execution-driver.js";
29+
export { NodeExecutionDriver, composeStaticBridgeCode, composePostRestoreScript, composeBridgeCodeForWarmup } from "./execution-driver.js";
3030
export type { NodeExecutionDriverOptions } from "./isolate-bootstrap.js";
3131

3232
// Node system driver

0 commit comments

Comments
 (0)