import { describe, expect, it, vi } from "vitest"; import { syncShellEnvironment } from "./syncShellEnvironment"; describe("syncShellEnvironment", () => { it("hydrates PATH and missing SSH_AUTH_SOCK from the login shell on macOS", () => { const env: NodeJS.ProcessEnv = { SHELL: "/bin/zsh", PATH: "/Users/test/.local/bin:/usr/bin", }; const readEnvironment = vi.fn(() => ({ PATH: "/opt/homebrew/bin:/usr/bin", SSH_AUTH_SOCK: "/tmp/secretive.sock", HOMEBREW_PREFIX: "/opt/homebrew", })); syncShellEnvironment(env, { platform: "darwin", readEnvironment, }); expect(readEnvironment).toHaveBeenCalledWith("/bin/zsh", [ "PATH", "SSH_AUTH_SOCK", "HOMEBREW_PREFIX", "HOMEBREW_CELLAR", "HOMEBREW_REPOSITORY", "XDG_CONFIG_HOME", "XDG_DATA_HOME", ]); expect(env.PATH).toBe("/opt/homebrew/bin:/usr/bin:/Users/test/.local/bin"); expect(env.SSH_AUTH_SOCK).toBe("/tmp/secretive.sock"); expect(env.HOMEBREW_PREFIX).toBe("/opt/homebrew"); }); it("preserves an inherited SSH_AUTH_SOCK value", () => { const env: NodeJS.ProcessEnv = { SHELL: "/bin/zsh", PATH: "/usr/bin", SSH_AUTH_SOCK: "/tmp/inherited.sock", }; const readEnvironment = vi.fn(() => ({ PATH: "/opt/homebrew/bin:/usr/bin", SSH_AUTH_SOCK: "/tmp/login-shell.sock", })); syncShellEnvironment(env, { platform: "darwin", readEnvironment, }); expect(env.PATH).toBe("/opt/homebrew/bin:/usr/bin"); expect(env.SSH_AUTH_SOCK).toBe("/tmp/inherited.sock"); }); it("preserves inherited values when the login shell omits them", () => { const env: NodeJS.ProcessEnv = { SHELL: "/bin/zsh", PATH: "/usr/bin", SSH_AUTH_SOCK: "/tmp/inherited.sock", }; const readEnvironment = vi.fn(() => ({ PATH: "/opt/homebrew/bin:/usr/bin", })); syncShellEnvironment(env, { platform: "darwin", readEnvironment, }); expect(env.PATH).toBe("/opt/homebrew/bin:/usr/bin"); expect(env.SSH_AUTH_SOCK).toBe("/tmp/inherited.sock"); }); it("hydrates PATH and missing SSH_AUTH_SOCK from the login shell on linux", () => { const env: NodeJS.ProcessEnv = { SHELL: "/bin/zsh", PATH: "/usr/bin", }; const readEnvironment = vi.fn(() => ({ PATH: "/home/linuxbrew/.linuxbrew/bin:/usr/bin", SSH_AUTH_SOCK: "/tmp/secretive.sock", })); syncShellEnvironment(env, { platform: "linux", readEnvironment, }); expect(readEnvironment).toHaveBeenCalledWith("/bin/zsh", [ "PATH", "SSH_AUTH_SOCK", "HOMEBREW_PREFIX", "HOMEBREW_CELLAR", "HOMEBREW_REPOSITORY", "XDG_CONFIG_HOME", "XDG_DATA_HOME", ]); expect(env.PATH).toBe("/home/linuxbrew/.linuxbrew/bin:/usr/bin"); expect(env.SSH_AUTH_SOCK).toBe("/tmp/secretive.sock"); }); it("falls back to launchctl PATH on macOS when shell probing does not return one", () => { const env: NodeJS.ProcessEnv = { SHELL: "/opt/homebrew/bin/nu", PATH: "/usr/bin", }; const readEnvironment = vi .fn() .mockImplementationOnce(() => { throw new Error("unknown flag"); }) .mockImplementationOnce(() => ({})); const readLaunchctlPath = vi.fn(() => "/opt/homebrew/bin:/usr/bin"); const logWarning = vi.fn(); syncShellEnvironment(env, { platform: "darwin", readEnvironment, readLaunchctlPath, userShell: "/bin/zsh", logWarning, }); expect(readEnvironment).toHaveBeenNthCalledWith(1, "/opt/homebrew/bin/nu", [ "PATH", "SSH_AUTH_SOCK", "HOMEBREW_PREFIX", "HOMEBREW_CELLAR", "HOMEBREW_REPOSITORY", "XDG_CONFIG_HOME", "XDG_DATA_HOME", ]); expect(readEnvironment).toHaveBeenNthCalledWith(2, "/bin/zsh", [ "PATH", "SSH_AUTH_SOCK", "HOMEBREW_PREFIX", "HOMEBREW_CELLAR", "HOMEBREW_REPOSITORY", "XDG_CONFIG_HOME", "XDG_DATA_HOME", ]); expect(readLaunchctlPath).toHaveBeenCalledTimes(1); expect(logWarning).toHaveBeenCalledWith( "Failed to read login shell environment from /opt/homebrew/bin/nu.", expect.any(Error), ); expect(env.PATH).toBe("/opt/homebrew/bin:/usr/bin"); }); it("does nothing outside macOS and linux", () => { const env: NodeJS.ProcessEnv = { SHELL: "C:/Program Files/Git/bin/bash.exe", PATH: "C:\\Windows\\System32", SSH_AUTH_SOCK: "/tmp/inherited.sock", }; const readEnvironment = vi.fn(() => ({ PATH: "/usr/local/bin:/usr/bin", SSH_AUTH_SOCK: "/tmp/secretive.sock", })); syncShellEnvironment(env, { platform: "win32", readEnvironment, }); expect(readEnvironment).not.toHaveBeenCalled(); expect(env.PATH).toBe("C:\\Windows\\System32"); expect(env.SSH_AUTH_SOCK).toBe("/tmp/inherited.sock"); }); });