This commit is contained in:
Emrik Östling
2026-09-11 19:07:37 +02:00
parent b795d669b6
commit cf6d730dba
2 changed files with 33 additions and 27 deletions
+19 -19
View File
@@ -107,6 +107,24 @@ export function createSandboxedExec(config: SandboxConfig): ExecFileFn {
const cb: ExecFileCallback = callback ?? (() => {});
// Provide isolated per-job TMPDIR, HOME, and XDG directories
const sandboxedEnv = {
...process.env,
...options.env,
TMPDIR: resolvedTemp,
TEMP: resolvedTemp,
TMP: resolvedTemp,
HOME: resolvedTemp,
XDG_CONFIG_HOME: `${resolvedTemp}/.config`,
XDG_CACHE_HOME: `${resolvedTemp}/.cache`,
XDG_DATA_HOME: `${resolvedTemp}/.local/share`,
};
const sandboxedOptions: ExecFileOptions = {
...options,
env: sandboxedEnv,
};
if (!runnerPath) {
if (isStrict) {
const error = new Error(
@@ -122,7 +140,7 @@ export function createSandboxedExec(config: SandboxConfig): ExecFileFn {
o: ExecFileOptions,
f: ExecFileCallback,
) => ChildProcess
)(cmd, args, options, cb);
)(cmd, args, sandboxedOptions, cb);
}
// Build landlock-runner arguments
@@ -147,24 +165,6 @@ export function createSandboxedExec(config: SandboxConfig): ExecFileFn {
runnerArgs.push("--", cmd, ...args);
// Provide isolated per-job TMPDIR, HOME, and XDG directories
const sandboxedEnv = {
...process.env,
...options.env,
TMPDIR: resolvedTemp,
TEMP: resolvedTemp,
TMP: resolvedTemp,
HOME: resolvedTemp,
XDG_CONFIG_HOME: `${resolvedTemp}/.config`,
XDG_CACHE_HOME: `${resolvedTemp}/.cache`,
XDG_DATA_HOME: `${resolvedTemp}/.local/share`,
};
const sandboxedOptions: ExecFileOptions = {
...options,
env: sandboxedEnv,
};
return (
execFileOriginal as (
c: string,
+14 -8
View File
@@ -55,13 +55,18 @@ test("createSandboxedExec sets TMPDIR and HOME in environment", async () => {
tempDir,
});
await new Promise<void>((resolve) => {
sandboxedExec("/bin/sh", ["-c", "echo $TMPDIR"], (_err, stdout) => {
expect(stdout.trim()).toBe(tempDir);
resolve();
const stdout = await new Promise<string>((resolve, reject) => {
sandboxedExec("/bin/sh", ["-c", 'echo "$TMPDIR $HOME"'], (err, out) => {
if (err) {
reject(err);
} else {
resolve(String(out));
}
});
});
expect(stdout.trim()).toBe(`${tempDir} ${tempDir}`);
rmSync(testDir, { recursive: true, force: true });
});
@@ -95,12 +100,13 @@ test("createSandboxedExec passes options before callback correctly", async () =>
});
let called = false;
sandboxedExec("echo", ["hi"], { maxBuffer: 1024 }, () => {
called = true;
await new Promise<void>((resolve) => {
sandboxedExec("echo", ["hi"], { maxBuffer: 1024 }, () => {
called = true;
resolve();
});
});
// Give child process time if real exec was spawned
await new Promise((r) => setTimeout(r, 50));
expect(called).toBe(true);
rmSync(testDir, { recursive: true, force: true });