fix: harden preprocessing state and child capabilities
This commit is contained in:
@@ -1,4 +1,6 @@
|
||||
import { createRequire } from "node:module";
|
||||
import { closeSync, openSync } from "node:fs";
|
||||
import { spawn } from "node:child_process";
|
||||
import type { WorkspaceFsAtBindingV1, NativeWorkspaceFsAtHandleV1, NativeWorkspaceFsAtStatV1, NativeWorkspaceFsAtComponentV1 } from "../native/workspace-fs-at-binding.js";
|
||||
const require = createRequire(import.meta.url);
|
||||
const binding = require("../../native/workspace-fs-at/build/Release/workspace_fs_at.node") as WorkspaceFsAtBindingV1 & {
|
||||
@@ -70,3 +72,28 @@ export class WorkspaceFsAtV1 {
|
||||
withLockFd(owned, fd => fsExt.flockSync(fd, operation));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Internal child boundary. It deliberately returns a ChildProcess result, never an FD. */
|
||||
export function spawnChildWithWorkspaceCapabilities(
|
||||
writer: OwnedWorkspaceFsAtRegularFile,
|
||||
root: OwnedWorkspaceFsAtDirectory,
|
||||
executable: string,
|
||||
args: readonly string[],
|
||||
environment: NodeJS.ProcessEnv = process.env,
|
||||
): Promise<{ exitCode: number; stdout: Uint8Array; stderr: Uint8Array }> {
|
||||
if (!rawHandles.has(writer) || !rawHandles.has(root)) throw new Error("preprocessing_conflict");
|
||||
const writerRaw = rawHandles.get(writer)!; const rootRaw = rawHandles.get(root)!;
|
||||
const opened: number[] = [];
|
||||
try {
|
||||
const writerFd = openSync("/dev/null", "r"); opened.push(writerFd);
|
||||
const rootFd = openSync("/dev/null", "r"); opened.push(rootFd);
|
||||
binding.duplicateForChildStdio(writerRaw, rootRaw, writerFd, rootFd);
|
||||
const child = spawn(executable, [...args], { stdio: ["ignore", "pipe", "pipe", writerFd, rootFd], env: { ...environment, THOTH_WORKSPACE_CAPABILITY_REQUIRED: "1" } });
|
||||
const out: Buffer[] = []; const err: Buffer[] = [];
|
||||
child.stdout?.on("data", (chunk: Buffer) => out.push(chunk)); child.stderr?.on("data", (chunk: Buffer) => err.push(chunk));
|
||||
return new Promise((resolve, reject) => {
|
||||
child.once("error", reject); child.once("close", code => resolve({ exitCode: code ?? 1, stdout: Buffer.concat(out), stderr: Buffer.concat(err) }));
|
||||
});
|
||||
} finally { for (const fd of opened) { try { closeSync(fd); } catch {} } }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user