4b6be0b0df
The Bun.env scrub and filterProcessEnv used isValidEnvName (strict shell identifier shape), which deleted standard Windows variables like ProgramFiles(x86) and CommonProgramFiles(x86). procmgr.ts imports this module before resolving the shell and reads Bun.env['ProgramFiles(x86)'] to find Git Bash under 32-bit Program Files, so installations that only had Git there were no longer discovered and failed with 'No bash shell found'. The unsafe cases for native execve are '=' or NUL in names and NUL in values, not parentheses. Introduce isSafeEnvName covering exactly those cases and use it for the in-place Bun.env scrub and the spawn-env filter. Keep isValidEnvName (strict) for dotenv parsing, where strict shell-identifier shape is the right contract.
85 lines
2.1 KiB
TypeScript
85 lines
2.1 KiB
TypeScript
import { afterEach, describe, expect, it } from "bun:test";
|
|
import * as fs from "node:fs";
|
|
import * as os from "node:os";
|
|
import * as path from "node:path";
|
|
import { filterProcessEnv, parseEnvFile } from "../src/env";
|
|
|
|
const tempDirs: string[] = [];
|
|
|
|
afterEach(() => {
|
|
for (const dir of tempDirs.splice(0)) {
|
|
fs.rmSync(dir, { force: true, recursive: true });
|
|
}
|
|
});
|
|
|
|
function writeTempEnv(content: string): string {
|
|
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "pi-utils-env-"));
|
|
tempDirs.push(dir);
|
|
const filePath = path.join(dir, ".env");
|
|
fs.writeFileSync(filePath, content);
|
|
return filePath;
|
|
}
|
|
|
|
describe("parseEnvFile", () => {
|
|
it("ignores malformed names and nul-containing values", () => {
|
|
const filePath = writeTempEnv(
|
|
[
|
|
"GOOD=value",
|
|
"_ALSO_GOOD='quoted value'",
|
|
"1BAD=value",
|
|
"BAD-NAME=value",
|
|
"BAD NAME=value",
|
|
"BAD_VALUE=before\0after",
|
|
"# comment",
|
|
"NO_EQUALS",
|
|
].join("\n"),
|
|
);
|
|
|
|
expect(parseEnvFile(filePath)).toEqual({
|
|
GOOD: "value",
|
|
_ALSO_GOOD: "quoted value",
|
|
});
|
|
});
|
|
|
|
it("mirrors valid OMP_ variables to PI_ variables", () => {
|
|
const filePath = writeTempEnv("OMP_FEATURE=enabled\nOMP_BAD=before\0after\n");
|
|
|
|
expect(parseEnvFile(filePath)).toEqual({
|
|
OMP_FEATURE: "enabled",
|
|
PI_FEATURE: "enabled",
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("filterProcessEnv", () => {
|
|
it("drops entries that cannot be passed to process spawn env", () => {
|
|
expect(
|
|
filterProcessEnv({
|
|
GOOD: "value",
|
|
EMPTY: "",
|
|
"BAD=NAME": "value",
|
|
BAD_VALUE: "before\0after",
|
|
MISSING: undefined,
|
|
}),
|
|
).toEqual({
|
|
GOOD: "value",
|
|
EMPTY: "",
|
|
});
|
|
});
|
|
|
|
it("preserves Windows-style variable names containing parentheses", () => {
|
|
// `ProgramFiles(x86)` and friends are standard on Windows and must
|
|
// survive the scrub so Git Bash discovery in procmgr.ts can resolve
|
|
// 32-bit Program Files installations.
|
|
expect(
|
|
filterProcessEnv({
|
|
"ProgramFiles(x86)": "C:\\Program Files (x86)",
|
|
"CommonProgramFiles(x86)": "C:\\Program Files (x86)\\Common Files",
|
|
}),
|
|
).toEqual({
|
|
"ProgramFiles(x86)": "C:\\Program Files (x86)",
|
|
"CommonProgramFiles(x86)": "C:\\Program Files (x86)\\Common Files",
|
|
});
|
|
});
|
|
});
|