From e50d845451afd5f584e6bf38300657e39bbaa25a Mon Sep 17 00:00:00 2001 From: Luke Parker <10430890+Hona@users.noreply.github.com> Date: Sat, 19 Sep 2026 14:36:04 +1000 Subject: [PATCH] fix(desktop): run WSL commands with --exec so inline scripts are not pre-expanded (#49902) --- packages/desktop/src/main/wsl/runtime.test.ts | 35 +++++++++++++++++++ packages/desktop/src/main/wsl/runtime.ts | 4 ++- 2 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 packages/desktop/src/main/wsl/runtime.test.ts diff --git a/packages/desktop/src/main/wsl/runtime.test.ts b/packages/desktop/src/main/wsl/runtime.test.ts new file mode 100644 index 00000000000..69a8e45203d --- /dev/null +++ b/packages/desktop/src/main/wsl/runtime.test.ts @@ -0,0 +1,35 @@ +import { expect, test } from "bun:test" +import { listInstalledWslDistros, probeWslRuntime, runWslSh, wslArgs } from "./runtime" + +test("wslArgs bypasses the distro default shell", () => { + expect(wslArgs(["sh", "-lc", 'printf "%s\\n" "$HOME"'], "Debian")).toEqual([ + "-d", + "Debian", + "--exec", + "sh", + "-lc", + 'printf "%s\\n" "$HOME"', + ]) + expect(wslArgs(["bash", "-se"], "Debian", "root")).toEqual([ + "-d", + "Debian", + "--user", + "root", + "--exec", + "bash", + "-se", + ]) +}) + +// Exercise the real wsl.exe argv path: with `--`, WSL routes the command line through the distro's +// default shell, which expands `$cli` to "" before `sh` runs the script (#48640). +const distro = + process.platform === "win32" && (await probeWslRuntime()).available + ? (await listInstalledWslDistros().catch(() => [])).find((item) => item.isDefault)?.name + : undefined + +test.skipIf(!distro)("inline scripts keep their own variable expansion inside WSL", async () => { + const result = await runWslSh(['cli="from-script"', 'printf "%s\\n" "$cli"'].join("\n"), distro) + expect(result.code).toBe(0) + expect(result.stdout.trim()).toBe("from-script") +}) diff --git a/packages/desktop/src/main/wsl/runtime.ts b/packages/desktop/src/main/wsl/runtime.ts index 78f17503a5b..e9866af87e3 100644 --- a/packages/desktop/src/main/wsl/runtime.ts +++ b/packages/desktop/src/main/wsl/runtime.ts @@ -38,7 +38,9 @@ const DEFAULT_WSL_TIMEOUT_MS = 20_000 const DEFAULT_WSL_INSTALL_TIMEOUT_MS = 15 * 60_000 export function wslArgs(args: string[], distro?: string | null, user?: string | null) { - return [...(distro ? ["-d", distro] : []), ...(user ? ["--user", user] : []), "--", ...args] + // `--` hands the command line to the distro's default shell, which expands `$VAR` and `$(...)` + // inside our inline scripts before `sh -lc` ever runs them. `--exec` runs the command directly. + return [...(distro ? ["-d", distro] : []), ...(user ? ["--user", user] : []), "--exec", ...args] } export function runWsl(args: string[], opts: RunWslOptions = {}) {