1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2025-01-21 04:52:26 -05:00

fix(node): Prevent node:child_process from always inheriting the parent environment (#27343) (#27340)

Fixes #27343

Currently the node:child_process polyfill is always passing the full
parent environment to all spawned subprocesses. In the case where
`options.env` is provided those keys are overridden but the rest of the
parent environment is still passed through.

On Node the behaviour is for child processes to only inherit the parent
environment when `options.env` isn't specified. When `options.env` is
specified the child process inherits only those keys.

This PR updates the internal node child_process polyfill so that the
`clearEnv` argument is set to true when spawning the subprocess to
prevent the parent environment always being inherited by default. It
also fixes an issue where `normalizeSpawnArguments` wasn't returning the
`env` option if `options.env` was unset.
This commit is contained in:
TateKennington 2025-01-14 10:46:56 +13:00 committed by GitHub
parent 2a2b39eb2e
commit 5a39f2f096
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 69 additions and 0 deletions

View file

@ -277,6 +277,7 @@ export class ChildProcess extends EventEmitter {
try {
this.#process = new Deno.Command(cmd, {
args: cmdArgs,
clearEnv: true,
cwd,
env: stringEnv,
stdin: toDenoStdio(stdin),
@ -839,6 +840,7 @@ export function normalizeSpawnArguments(
args,
cwd,
detached: !!options.detached,
env,
envPairs,
file,
windowsHide: !!options.windowsHide,

View file

@ -656,6 +656,73 @@ Deno.test({
},
});
Deno.test({
name:
"[node/child_process spawn] child inherits Deno.env when options.env is not provided",
async fn() {
const deferred = withTimeout<string>();
Deno.env.set("BAR", "BAR");
const env = spawn(
`"${Deno.execPath()}" eval -p "Deno.env.toObject().BAR"`,
{
shell: true,
},
);
try {
let envOutput = "";
assert(env.stdout);
env.on("error", (err: Error) => deferred.reject(err));
env.stdout.on("data", (data) => {
envOutput += data;
});
env.on("close", () => {
deferred.resolve(envOutput.trim());
});
await deferred.promise;
} finally {
env.kill();
Deno.env.delete("BAR");
}
const value = await deferred.promise;
assertEquals(value, "BAR");
},
});
Deno.test({
name:
"[node/child_process spawn] child doesn't inherit Deno.env when options.env is provided",
async fn() {
const deferred = withTimeout<string>();
Deno.env.set("BAZ", "BAZ");
const env = spawn(
`"${Deno.execPath()}" eval -p "Deno.env.toObject().BAZ"`,
{
env: {},
shell: true,
},
);
try {
let envOutput = "";
assert(env.stdout);
env.on("error", (err: Error) => deferred.reject(err));
env.stdout.on("data", (data) => {
envOutput += data;
});
env.on("close", () => {
deferred.resolve(envOutput.trim());
});
await deferred.promise;
} finally {
env.kill();
Deno.env.delete("BAZ");
}
const value = await deferred.promise;
assertEquals(value, "undefined");
},
});
// Regression test for https://github.com/denoland/deno/issues/20373
Deno.test(async function undefinedValueInEnvVar() {
const deferred = withTimeout<string>();