From bd0ccca07a053aae87b6bedeb2fd390456d25cef Mon Sep 17 00:00:00 2001 From: Jinjing <6427696+AmethystLiang@users.noreply.github.com> Date: Tue, 4 Aug 2026 12:38:34 -0700 Subject: [PATCH] fix(startup): omit Linux-only package mgrs from PATH on non-Linux Snap and Linuxbrew don't ship installers for Darwin or BSD, so seeding their PATH entries on those platforms adds phantom directories every spawn must stat. Keep them on Linux only, while preserving Nix and Homebrew across all platforms as they have multi-platform support. --- src/main/startup/configure-process.test.ts | 60 ++++++++++++++++++++++ src/main/startup/configure-process.ts | 17 +++--- 2 files changed, 68 insertions(+), 9 deletions(-) diff --git a/src/main/startup/configure-process.test.ts b/src/main/startup/configure-process.test.ts index 512467eb724..eaf9f42aeec 100644 --- a/src/main/startup/configure-process.test.ts +++ b/src/main/startup/configure-process.test.ts @@ -77,6 +77,66 @@ describe('patchPackagedProcessPath', () => { expect(segments).toContain(join('/Users/tester', 'bin')) }) + it('omits Linux-only snap/Linuxbrew dirs but keeps Nix on packaged darwin runs', async () => { + const { app } = await import('electron') + const { patchPackagedProcessPath } = await import('./configure-process') + + setPlatform('darwin') + Object.defineProperty(app, 'isPackaged', { configurable: true, value: true }) + process.env.HOME = '/Users/tester' + process.env.PATH = '/usr/bin:/bin' + + patchPackagedProcessPath() + + const segments = (process.env.PATH ?? '').split(':') + // Why: neither has a macOS installer, so both are phantom PATH entries. + expect(segments).not.toContain('/snap/bin') + expect(segments).not.toContain('/home/linuxbrew/.linuxbrew/bin') + // Why: Nix does ship a macOS default profile, so it stays seeded. + expect(segments).toContain('/nix/var/nix/profiles/default/bin') + expect(segments).toContain('/opt/homebrew/bin') + expect(segments).toContain('/usr/local/bin') + }) + + it('keeps snap, Linuxbrew, and Nix dirs for packaged linux runs', async () => { + const { app } = await import('electron') + const { patchPackagedProcessPath } = await import('./configure-process') + + setPlatform('linux') + Object.defineProperty(app, 'isPackaged', { configurable: true, value: true }) + process.env.HOME = '/home/tester' + process.env.PATH = '/usr/bin:/bin' + + patchPackagedProcessPath() + + const segments = (process.env.PATH ?? '').split(':') + expect(segments).toContain('/snap/bin') + expect(segments).toContain('/home/linuxbrew/.linuxbrew/bin') + expect(segments).toContain('/nix/var/nix/profiles/default/bin') + expect(segments.indexOf('/usr/local/sbin')).toBeLessThan(segments.indexOf('/snap/bin')) + expect(segments.indexOf('/home/linuxbrew/.linuxbrew/bin')).toBeLessThan( + segments.indexOf('/nix/var/nix/profiles/default/bin') + ) + }) + + it('omits snap/Linuxbrew but keeps Nix on non-Linux POSIX platforms', async () => { + const { app } = await import('electron') + const { patchPackagedProcessPath } = await import('./configure-process') + + setPlatform('freebsd') + Object.defineProperty(app, 'isPackaged', { configurable: true, value: true }) + process.env.HOME = '/home/tester' + process.env.PATH = '/usr/bin:/bin' + + patchPackagedProcessPath() + + const segments = (process.env.PATH ?? '').split(':') + expect(segments).not.toContain('/snap/bin') + expect(segments).not.toContain('/home/linuxbrew/.linuxbrew/bin') + expect(segments).toContain('/nix/var/nix/profiles/default/bin') + expect(segments).toContain('/usr/local/bin') + }) + it('leaves PATH untouched when the app is not packaged', async () => { const { app } = await import('electron') const { patchPackagedProcessPath } = await import('./configure-process') diff --git a/src/main/startup/configure-process.ts b/src/main/startup/configure-process.ts index 292f6195258..e545d89da9c 100644 --- a/src/main/startup/configure-process.ts +++ b/src/main/startup/configure-process.ts @@ -99,15 +99,14 @@ export function patchPackagedProcessPath(): void { const extraPaths: string[] = [] if (process.platform !== 'win32') { - extraPaths.push( - '/opt/homebrew/bin', - '/opt/homebrew/sbin', - '/usr/local/bin', - '/usr/local/sbin', - '/snap/bin', - '/home/linuxbrew/.linuxbrew/bin', - '/nix/var/nix/profiles/default/bin' - ) + extraPaths.push('/opt/homebrew/bin', '/opt/homebrew/sbin', '/usr/local/bin', '/usr/local/sbin') + + if (process.platform === 'linux') { + // Why: snap and Linuxbrew ship on Linux only, so seeding them elsewhere adds phantom PATH entries every spawn must stat. + extraPaths.push('/snap/bin', '/home/linuxbrew/.linuxbrew/bin') + } + + extraPaths.push('/nix/var/nix/profiles/default/bin') if (home) { extraPaths.push(