From 6ea079f6b15c4dda03b4569d36c2e42acec79a67 Mon Sep 17 00:00:00 2001 From: lohit Date: Thu, 19 Feb 2026 15:47:27 +0000 Subject: [PATCH] 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. --- package-lock.json | 64 +++++++++++++++++-- packages/bruno-cli/src/index.js | 4 ++ packages/bruno-electron/src/index.js | 7 ++ packages/bruno-requests/package.json | 3 +- packages/bruno-requests/rollup.config.js | 2 +- packages/bruno-requests/src/index.ts | 1 + .../bruno-requests/src/utils/shell-env.ts | 33 ++++++++++ 7 files changed, 105 insertions(+), 9 deletions(-) create mode 100644 packages/bruno-requests/src/utils/shell-env.ts diff --git a/package-lock.json b/package-lock.json index f09839eea..d60271467 100644 --- a/package-lock.json +++ b/package-lock.json @@ -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", diff --git a/packages/bruno-cli/src/index.js b/packages/bruno-cli/src/index.js index f92f9ce0a..f1c206fa9 100644 --- a/packages/bruno-cli/src/index.js +++ b/packages/bruno-cli/src/index.js @@ -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']; diff --git a/packages/bruno-electron/src/index.js b/packages/bruno-electron/src/index.js index ee4d12a5c..cfd0985a0 100644 --- a/packages/bruno-electron/src/index.js +++ b/packages/bruno-electron/src/index.js @@ -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 { diff --git a/packages/bruno-requests/package.json b/packages/bruno-requests/package.json index e91f79a08..aec9f823c 100644 --- a/packages/bruno-requests/package.json +++ b/packages/bruno-requests/package.json @@ -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", diff --git a/packages/bruno-requests/rollup.config.js b/packages/bruno-requests/rollup.config.js index 04ad20448..598b96a74 100644 --- a/packages/bruno-requests/rollup.config.js +++ b/packages/bruno-requests/rollup.config.js @@ -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) } ]; diff --git a/packages/bruno-requests/src/index.ts b/packages/bruno-requests/src/index.ts index 51f201545..dd728899c 100644 --- a/packages/bruno-requests/src/index.ts +++ b/packages/bruno-requests/src/index.ts @@ -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'; diff --git a/packages/bruno-requests/src/utils/shell-env.ts b/packages/bruno-requests/src/utils/shell-env.ts new file mode 100644 index 000000000..7f3d44830 --- /dev/null +++ b/packages/bruno-requests/src/utils/shell-env.ts @@ -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> => { + // 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> => { + const shellEnvVars = await fetchShellEnv(); + Object.assign(process.env, shellEnvVars); + return shellEnvVars; +};