[codex] Centralize subprocess env boundaries (#585)

* Centralize subprocess env boundaries

* Remove env boundary static audit test

* Tighten env boundary process launches

* Fix Windows native process launches

* Inline provider env pass-throughs
This commit is contained in:
Mohamed Boudra
2026-04-27 13:24:16 +08:00
committed by GitHub
parent 90032570ec
commit 15df680a64
40 changed files with 760 additions and 304 deletions
@@ -1,8 +1,8 @@
import { spawn, spawnSync } from "node:child_process";
import { spawnSync } from "node:child_process";
import { existsSync, readFileSync } from "node:fs";
import { createRequire } from "node:module";
import path from "node:path";
import { loadConfig, resolvePaseoHome } from "@getpaseo/server";
import { loadConfig, resolvePaseoHome, spawnProcess } from "@getpaseo/server";
import { tryConnectToDaemon } from "../../utils/client.js";
export interface DaemonStartOptions {
@@ -373,16 +373,17 @@ export async function startLocalDaemonDetached(
throw new Error("Cannot use --listen and --port together");
}
const daemonRunnerEntry = resolveDaemonRunnerEntry();
const childEnv = buildChildEnv(options);
const paseoHome = resolvePaseoHome(childEnv);
const logPath = path.join(paseoHome, DAEMON_LOG_FILENAME);
const daemonRunnerEntry = resolveDaemonRunnerEntry();
const child = spawn(
const child = spawnProcess(
process.execPath,
[...process.execArgv, daemonRunnerEntry, ...buildRunnerArgs(options)],
{
detached: true,
envMode: "internal",
env: childEnv,
stdio: ["ignore", "ignore", "ignore"],
},
@@ -438,8 +439,8 @@ export function startLocalDaemonForeground(options: DaemonStartOptions): number
throw new Error("Cannot use --listen and --port together");
}
const childEnv = buildChildEnv(options);
const daemonRunnerEntry = resolveDaemonRunnerEntry();
const childEnv = buildChildEnv(options);
const result = spawnSync(
process.execPath,
[...process.execArgv, daemonRunnerEntry, ...buildRunnerArgs(options)],
+1 -8
View File
@@ -1,11 +1,6 @@
import type { Command } from "commander";
import { createRequire } from "node:module";
import {
getOrCreateServerId,
findExecutable,
applyProviderEnv,
execCommand,
} from "@getpaseo/server";
import { getOrCreateServerId, findExecutable, execCommand } from "@getpaseo/server";
import { tryConnectToDaemon } from "../../utils/client.js";
import type { CommandOptions, ListResult, OutputSchema } from "../../output/index.js";
import { resolveLocalDaemonState, resolveTcpHostFromListen } from "./local-daemon.js";
@@ -177,11 +172,9 @@ async function checkProviderBinary(
if (!binaryPath) {
return { path: null, version: null };
}
const env = applyProviderEnv(process.env);
try {
const { stdout } = await execCommand(binaryPath, ["--version"], {
timeout: 5000,
env,
});
return { path: binaryPath, version: stdout.trim() || null };
} catch {
+4 -2
View File
@@ -1,7 +1,7 @@
import { existsSync } from "node:fs";
import { spawn } from "node:child_process";
import { homedir } from "node:os";
import path from "node:path";
import { spawnProcess } from "@getpaseo/server";
function findDesktopApp(): string | null {
if (process.platform === "darwin") {
@@ -54,11 +54,13 @@ function cleanEnvForDesktopLaunch(): NodeJS.ProcessEnv {
// desktop process inherits the env directly, so we must strip it or the
// desktop app would start as a bare Node process instead of Electron.
delete env.ELECTRON_RUN_AS_NODE;
delete env.ELECTRON_NO_ATTACH_CONSOLE;
delete env.PASEO_NODE_ENV;
return env;
}
function spawnDetached(command: string, args: string[]): void {
spawn(command, args, {
spawnProcess(command, args, {
detached: true,
stdio: "ignore",
env: cleanEnvForDesktopLaunch(),