fix(coding-agent): work around Bun empty process.env inside sandbox (#3807)
Bun bug oven-sh/bun#27802 causes process.env to be empty when running inside a Linux sandbox (Landlock/seccomp). This breaks npm resolution because PATH is missing, crashing pi on startup with: Failed to run npm root -g: Executable not found in $PATH: "npm" Add getSandboxEnv() to read /proc/self/environ as a fallback on Linux when process.env has zero keys. Pass this env to all spawn calls in package-manager.ts. Also fix runCommandSync error handling: check result.error in addition to result.status, and include result.error?.message in the error text so spawn failures (e.g. ENOENT) produce useful diagnostics instead of "null". Fixes #3806
This commit is contained in:
@@ -2,6 +2,26 @@ import { type ChildProcess, type ChildProcessByStdio, spawn, spawnSync } from "n
|
||||
import { createHash } from "node:crypto";
|
||||
import { existsSync, mkdirSync, readdirSync, readFileSync, rmSync, statSync, writeFileSync } from "node:fs";
|
||||
import { homedir, tmpdir } from "node:os";
|
||||
|
||||
function getEnv(): NodeJS.ProcessEnv {
|
||||
if (process.platform !== "linux" || Object.keys(process.env).length > 0) {
|
||||
return process.env;
|
||||
}
|
||||
try {
|
||||
const data = readFileSync("/proc/self/environ", "utf-8");
|
||||
const env: NodeJS.ProcessEnv = {};
|
||||
for (const entry of data.split("\0")) {
|
||||
const idx = entry.indexOf("=");
|
||||
if (idx > 0) {
|
||||
env[entry.slice(0, idx)] = entry.slice(idx + 1);
|
||||
}
|
||||
}
|
||||
return env;
|
||||
} catch {
|
||||
return process.env;
|
||||
}
|
||||
}
|
||||
|
||||
import { basename, dirname, join, relative, resolve, sep } from "node:path";
|
||||
import type { Readable } from "node:stream";
|
||||
import { globSync } from "glob";
|
||||
@@ -2326,6 +2346,7 @@ export class DefaultPackageManager implements PackageManager {
|
||||
cwd: options?.cwd,
|
||||
stdio: isStdoutTakenOver() ? ["ignore", 2, 2] : "inherit",
|
||||
shell: this.shouldUseWindowsShell(command),
|
||||
env: getEnv(),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -2334,11 +2355,12 @@ export class DefaultPackageManager implements PackageManager {
|
||||
args: string[],
|
||||
options?: { cwd?: string; env?: Record<string, string> },
|
||||
): ChildProcessByStdio<null, Readable, Readable> {
|
||||
const baseEnv = getEnv();
|
||||
return spawn(command, args, {
|
||||
cwd: options?.cwd,
|
||||
stdio: ["ignore", "pipe", "pipe"],
|
||||
shell: this.shouldUseWindowsShell(command),
|
||||
env: options?.env ? { ...process.env, ...options.env } : process.env,
|
||||
env: options?.env ? { ...baseEnv, ...options.env } : baseEnv,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -2405,9 +2427,12 @@ export class DefaultPackageManager implements PackageManager {
|
||||
stdio: ["ignore", "pipe", "pipe"],
|
||||
encoding: "utf-8",
|
||||
shell: this.shouldUseWindowsShell(command),
|
||||
env: getEnv(),
|
||||
});
|
||||
if (result.status !== 0) {
|
||||
throw new Error(`Failed to run ${command} ${args.join(" ")}: ${result.stderr || result.stdout}`);
|
||||
if (result.error || result.status !== 0) {
|
||||
throw new Error(
|
||||
`Failed to run ${command} ${args.join(" ")}: ${result.error?.message || result.stderr || result.stdout}`,
|
||||
);
|
||||
}
|
||||
return (result.stdout || result.stderr || "").trim();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user