Make sure we don't override any environments

This commit is contained in:
Reinier Criel 2025-11-11 15:22:06 -08:00
parent f9d241e474
commit 6bcd3d3b8f
2 changed files with 48 additions and 17 deletions

View file

@ -20,29 +20,39 @@ export async function runPip(command, args) {
// so that any network request made by pip, including those outside explicit CLI args, // so that any network request made by pip, including those outside explicit CLI args,
// validates correctly under both MITM'd and tunneled HTTPS. // validates correctly under both MITM'd and tunneled HTTPS.
const combinedCaPath = getCombinedCaBundlePath(); const combinedCaPath = getCombinedCaBundlePath();
env.REQUESTS_CA_BUNDLE = combinedCaPath;
env.SSL_CERT_FILE = combinedCaPath; if (!env.REQUESTS_CA_BUNDLE) {
env.REQUESTS_CA_BUNDLE = combinedCaPath;
}
if (!env.SSL_CERT_FILE) {
env.SSL_CERT_FILE = combinedCaPath;
}
// To counter behavior that is sometimes seen where pip ignores REQUESTS_CA_BUNDLE/SSL_CERT_FILE, // To counter behavior that is sometimes seen where pip ignores REQUESTS_CA_BUNDLE/SSL_CERT_FILE,
// We will set additional env vars for pip // We will set additional env vars for pip
env.PIP_CERT = combinedCaPath; if (!env.PIP_CERT) {
env.PIP_CERT = combinedCaPath;
}
// Create a temporary pip config file // Only create and set PIP_CONFIG_FILE if not already set
const tmpDir = os.tmpdir(); if (!env.PIP_CONFIG_FILE) {
const pipConfigPath = path.join(tmpDir, `safe-chain-pip-${Date.now()}.ini`); const tmpDir = os.tmpdir();
const pipConfigPath = path.join(tmpDir, `safe-chain-pip-${Date.now()}.ini`);
// Proxy settings // Proxy settings
const httpProxy = env.HTTP_PROXY || ''; const httpProxy = env.HTTP_PROXY || '';
const httpsProxy = env.HTTPS_PROXY || ''; const httpsProxy = env.HTTPS_PROXY || '';
// Build pip config INI // Build pip config INI
let pipConfig = '[global]\n'; let pipConfig = '[global]\n';
pipConfig += `cert = ${combinedCaPath}\n`; pipConfig += `cert = ${combinedCaPath}\n`;
if (httpProxy) pipConfig += `proxy = ${httpProxy}\n`; if (httpProxy) pipConfig += `proxy = ${httpProxy}\n`;
if (httpsProxy) pipConfig += `proxy = ${httpsProxy}\n`; if (httpsProxy) pipConfig += `proxy = ${httpsProxy}\n`;
await fs.writeFile(pipConfigPath, pipConfig); await fs.writeFile(pipConfigPath, pipConfig);
env.PIP_CONFIG_FILE = pipConfigPath; env.PIP_CONFIG_FILE = pipConfigPath;
}
const result = await safeSpawn(command, args, { const result = await safeSpawn(command, args, {
stdio: "inherit", stdio: "inherit",

View file

@ -4,6 +4,7 @@ import assert from "node:assert";
describe("runPipCommand environment variable handling", () => { describe("runPipCommand environment variable handling", () => {
let runPip; let runPip;
let capturedArgs = null; let capturedArgs = null;
let customEnv = null;
beforeEach(async () => { beforeEach(async () => {
capturedArgs = null; capturedArgs = null;
@ -18,11 +19,12 @@ describe("runPipCommand environment variable handling", () => {
}, },
}); });
// Mock proxy env merge // Mock proxy env merge, allow custom env override
mock.module("../../registryProxy/registryProxy.js", { mock.module("../../registryProxy/registryProxy.js", {
namedExports: { namedExports: {
mergeSafeChainProxyEnvironmentVariables: (env) => ({ mergeSafeChainProxyEnvironmentVariables: (env) => ({
...env, ...env,
...(customEnv || {}),
HTTPS_PROXY: "http://localhost:8080", HTTPS_PROXY: "http://localhost:8080",
}), }),
}, },
@ -43,6 +45,25 @@ describe("runPipCommand environment variable handling", () => {
mock.reset(); mock.reset();
}); });
it("should not overwrite existing env vars for certs and config", async () => {
// Set custom env vars before merge
customEnv = {
REQUESTS_CA_BUNDLE: "/custom/ca-bundle.pem",
SSL_CERT_FILE: "/custom/ssl-cert.pem",
PIP_CERT: "/custom/pip-cert.pem",
PIP_CONFIG_FILE: "/custom/pip.conf"
};
const res = await runPip("pip3", ["install", "requests"]);
assert.strictEqual(res.status, 0);
assert.ok(capturedArgs, "safeSpawn should have been called");
// Should preserve custom env vars
assert.strictEqual(capturedArgs.options.env.REQUESTS_CA_BUNDLE, "/custom/ca-bundle.pem");
assert.strictEqual(capturedArgs.options.env.SSL_CERT_FILE, "/custom/ssl-cert.pem");
assert.strictEqual(capturedArgs.options.env.PIP_CERT, "/custom/pip-cert.pem");
assert.strictEqual(capturedArgs.options.env.PIP_CONFIG_FILE, "/custom/pip.conf");
customEnv = null;
});
it("should set PIP_CERT env var and create config file", async () => { it("should set PIP_CERT env var and create config file", async () => {
const res = await runPip("pip3", ["install", "requests"]); const res = await runPip("pip3", ["install", "requests"]);
assert.strictEqual(res.status, 0); assert.strictEqual(res.status, 0);