fix: load shell environment variables on app startup (#7223)

Add shell-env integration to fetch environment variables from the user's
shell config files (.zshrc, .zshenv, etc.) so that proxy settings and
other exports are available in process.env for both Electron and CLI.
This commit is contained in:
lohit
2026-02-19 15:47:27 +00:00
committed by GitHub
parent 2fcfdfc338
commit 6ea079f6b1
7 changed files with 105 additions and 9 deletions

64
package-lock.json generated
View File

@@ -14555,6 +14555,18 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/default-shell": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/default-shell/-/default-shell-2.2.0.tgz",
"integrity": "sha512-sPpMZcVhRQ0nEMDtuMJ+RtCxt7iHPAMBU+I4tAlo5dU1sjRpNax0crj6nR3qKpvVnckaQ9U38enXcwW9nZJeCw==",
"license": "MIT",
"engines": {
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/defer-to-connect": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz",
@@ -15993,7 +16005,6 @@
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz",
"integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==",
"dev": true,
"license": "MIT",
"dependencies": {
"cross-spawn": "^7.0.3",
@@ -16017,7 +16028,6 @@
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz",
"integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=10"
@@ -18290,7 +18300,6 @@
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz",
"integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==",
"dev": true,
"license": "Apache-2.0",
"engines": {
"node": ">=10.17.0"
@@ -21463,7 +21472,6 @@
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
"integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==",
"dev": true,
"license": "MIT"
},
"node_modules/merge2": {
@@ -22055,7 +22063,6 @@
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz",
"integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==",
"dev": true,
"license": "MIT",
"dependencies": {
"path-key": "^3.0.0"
@@ -26683,6 +26690,50 @@
"node": ">=8"
}
},
"node_modules/shell-env": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/shell-env/-/shell-env-4.0.2.tgz",
"integrity": "sha512-8VJLnsyY//uoDJYl7hBcPdX54x0LaKbbfo5htiv8v/jrR4MD7uRUEom6Cb+S54ugMM9GkBbQJSwlLNCI3VXAHQ==",
"license": "MIT",
"dependencies": {
"default-shell": "^2.0.0",
"execa": "^5.1.1",
"strip-ansi": "^7.0.1"
},
"engines": {
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/shell-env/node_modules/ansi-regex": {
"version": "6.2.2",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz",
"integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==",
"license": "MIT",
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/chalk/ansi-regex?sponsor=1"
}
},
"node_modules/shell-env/node_modules/strip-ansi": {
"version": "7.1.2",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz",
"integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==",
"license": "MIT",
"dependencies": {
"ansi-regex": "^6.0.1"
},
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/chalk/strip-ansi?sponsor=1"
}
},
"node_modules/shell-quote": {
"version": "1.8.2",
"resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.2.tgz",
@@ -26781,7 +26832,6 @@
"version": "3.0.7",
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
"integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
"devOptional": true,
"license": "ISC"
},
"node_modules/simple-concat": {
@@ -27389,7 +27439,6 @@
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz",
"integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=6"
@@ -35325,6 +35374,7 @@
"http-proxy-agent": "~7.0.2",
"https-proxy-agent": "~7.0.6",
"is-ip": "^5.0.1",
"shell-env": "^4.0.1",
"socks-proxy-agent": "~8.0.5",
"system-ca": "^2.0.1",
"tough-cookie": "^6.0.0",

View File

@@ -1,5 +1,6 @@
const yargs = require('yargs');
const chalk = require('chalk');
const { initializeShellEnv } = require('@usebruno/requests');
const { CLI_EPILOGUE, CLI_VERSION } = require('./constants');
@@ -8,6 +9,9 @@ const printBanner = () => {
};
const run = async () => {
// Fetch shell environment (useful when CLI is run as subprocess from GUI app or cron)
await initializeShellEnv();
const argLength = process.argv.length;
const commandsToPrintBanner = ['--help', '-h'];

View File

@@ -3,6 +3,10 @@ const path = require('path');
const { execSync } = require('node:child_process');
const isDev = require('electron-is-dev');
const os = require('os');
const { initializeShellEnv } = require('@usebruno/requests');
// Fetch shell environment early (before app ready)
const shellEnvPromise = initializeShellEnv();
if (isDev) {
if (!fs.existsSync(path.join(__dirname, '../../bruno-js/src/sandbox/bundle-browser-rollup.js'))) {
@@ -155,6 +159,9 @@ if (useSingleInstance && !gotTheLock) {
// Prepare the renderer once the app is ready
app.on('ready', async () => {
// Ensure shell environment is loaded before any operations that need it
await shellEnvPromise;
if (isDev) {
const { installExtension, REDUX_DEVTOOLS, REACT_DEVELOPER_TOOLS } = require('electron-devtools-installer');
try {

View File

@@ -34,7 +34,8 @@
"socks-proxy-agent": "~8.0.5",
"system-ca": "^2.0.1",
"tough-cookie": "^6.0.0",
"ws": "^8.18.3"
"ws": "^8.18.3",
"shell-env": "^4.0.1"
},
"devDependencies": {
"@babel/preset-env": "^7.22.0",

View File

@@ -39,6 +39,6 @@ module.exports = [
typescript({ tsconfig: './tsconfig.json' }),
terser()
],
external: (id) => isBuiltin(id) || ['axios', 'qs', 'ws', 'debug'].includes(id)
external: (id) => isBuiltin(id) || ['axios', 'qs', 'ws', 'debug', 'shell-env'].includes(id)
}
];

View File

@@ -8,6 +8,7 @@ export { transformProxyConfig } from './utils/proxy-util';
export { default as createVaultClient, VaultError } from './utils/node-vault';
export type { VaultClient, VaultConfig, VaultRequestOptions } from './utils/node-vault';
export { getHttpHttpsAgents } from './utils/http-https-agents';
export { initializeShellEnv } from './utils/shell-env';
export * as scripting from './scripting';

View File

@@ -0,0 +1,33 @@
/**
* Shell Environment Utility
*
* Fetches environment variables from the user's shell configuration files (e.g., .zshenv, .bashrc)
*/
const fetchShellEnv = async (): Promise<Record<string, string>> => {
// Windows handles environment variables differently - skip
if (process.platform === 'win32') {
return {};
}
try {
// shell-env is ESM-only, so we use dynamic import
const { shellEnv } = await import('shell-env');
const env = await shellEnv();
return env;
} catch (error) {
return {};
}
};
/**
* Initializes process.env with shell environment variables.
* Should be called early in the app startup.
*
* @returns The fetched shell environment variables
*/
export const initializeShellEnv = async (): Promise<Record<string, string>> => {
const shellEnvVars = await fetchShellEnv();
Object.assign(process.env, shellEnvVars);
return shellEnvVars;
};