authorgravatar for 73941998+UtkarshUsername@users.noreply.github.comUtkarsh Patil <73941998+UtkarshUsername@users.noreply.github.com> 2026-08-31 03:14:10+05:30
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-08-30 17:44:10-04:00
log12fe2d6d03062c5d7fc3beff168f8c4af1235b50
tree84c8a3bed46e33e01ea2b396a07d6d97e6dad235
parent6e324b9bbfc72e694c3c16abeb59716c37fc02d5
signature Signed by PGP key B5690EEEBB952194

fix(windows): strip quotes from repaired PATH (#8746)


4 files changed, 29 insertions(+), 11 deletions(-)

apps/desktop/src/shell/DesktopShellEnvironment.test.ts+2-1
......@@ -320,7 +320,7 @@ describe("DesktopShellEnvironment", () => {
320320 FNM_DIR: "C:\\Users\\testuser\\AppData\\Roaming\\fnm",
321321 FNM_MULTISHELL_PATH: "C:\\Users\\testuser\\AppData\\Local\\fnm_multishells\\123",
322322 })
323 : envOutput({ PATH: "C:\\Custom\\Bin;C:\\Windows\\System32" });
323 : envOutput({ PATH: 'C:\\Custom\\Bin;C:";C:\\Windows\\System32' });
324324 },
325325 });
326326
......@@ -337,6 +337,7 @@ describe("DesktopShellEnvironment", () => {
337337 "C:\\Users\\testuser\\.bun\\bin",
338338 "C:\\Users\\testuser\\scoop\\shims",
339339 "C:\\Custom\\Bin",
340 "C:",
340341 ].join(";"),
341342 );
342343 assert.equal(env.FNM_DIR, "C:\\Users\\testuser\\AppData\\Roaming\\fnm");
apps/desktop/src/shell/DesktopShellEnvironment.ts+7-4
......@@ -151,6 +151,9 @@ const pathComparisonKey = (entry: string, platform: NodeJS.Platform) => {
151151 return platform === "win32" ? normalized.toLowerCase() : normalized;
152152};
153153
154const sanitizePathEntry = (entry: string, platform: NodeJS.Platform) =>
155 platform === "win32" ? entry.replaceAll('"', "") : entry;
156
154157const mergePaths = (
155158 platform: NodeJS.Platform,
156159 values: ReadonlyArray<Option.Option<string>>,
......@@ -163,14 +166,14 @@ const mergePaths = (
163166 if (Option.isNone(value)) continue;
164167
165168 for (const entry of value.value.split(delimiter)) {
166 const trimmed = entry.trim();
167 if (trimmed.length === 0) continue;
169 const sanitized = sanitizePathEntry(entry.trim(), platform);
170 if (sanitized.length === 0) continue;
168171
169 const key = pathComparisonKey(trimmed, platform);
172 const key = pathComparisonKey(sanitized, platform);
170173 if (key.length === 0 || seen.has(key)) continue;
171174
172175 seen.add(key);
173 entries.push(trimmed);
176 entries.push(sanitized);
174177 }
175178 }
176179
packages/shared/src/shell.test.ts+12-2
......@@ -304,7 +304,7 @@ describe("readEnvironmentFromWindowsShell", () => {
304304});
305305
306306describe("mergePathValues", () => {
307 it("dedupes case-insensitively on Windows while preserving preferred order", () => {
307 it("sanitizes and dedupes Windows entries while preserving preferred order", () => {
308308 expect(
309309 mergePathValues(
310310 'C:\\Users\\testuser\\AppData\\Roaming\\npm;"C:\\Program Files\\nodejs"',
......@@ -312,10 +312,20 @@ describe("mergePathValues", () => {
312312 "win32",
313313 ),
314314 ).toBe(
315 'C:\\Users\\testuser\\AppData\\Roaming\\npm;"C:\\Program Files\\nodejs";C:\\Windows\\System32',
315 "C:\\Users\\testuser\\AppData\\Roaming\\npm;C:\\Program Files\\nodejs;C:\\Windows\\System32",
316316 );
317317 });
318318
319 it("removes stray quotes from Windows entries", () => {
320 expect(
321 mergePathValues(
322 'C:\\Windows\\System32;C:\\cloudflared.exe;C:";C:\\Program Files\\nodejs',
323 undefined,
324 "win32",
325 ),
326 ).toBe("C:\\Windows\\System32;C:\\cloudflared.exe;C:;C:\\Program Files\\nodejs");
327 });
328
319329 it("dedupes case-sensitively on POSIX", () => {
320330 expect(mergePathValues("/usr/local/bin:/usr/bin", "/usr/bin:/USR/BIN", "linux")).toBe(
321331 "/usr/local/bin:/usr/bin:/USR/BIN",
packages/shared/src/shell.ts+8-4
......@@ -414,6 +414,10 @@ function normalizePathEntryForComparison(entry: string, platform: NodeJS.Platfor
414414 return platform === "win32" ? normalized.toLowerCase() : normalized;
415415}
416416
417function sanitizePathEntry(entry: string, platform: NodeJS.Platform): string {
418 return platform === "win32" ? entry.replaceAll('"', "") : entry;
419}
420
417421export function mergePathValues(
418422 preferredPath: string | undefined,
419423 inheritedPath: string | undefined,
......@@ -427,14 +431,14 @@ export function mergePathValues(
427431 if (!rawValue) continue;
428432
429433 for (const entry of rawValue.split(delimiter)) {
430 const trimmed = entry.trim();
431 if (trimmed.length === 0) continue;
434 const sanitized = sanitizePathEntry(entry.trim(), platform);
435 if (sanitized.length === 0) continue;
432436
433 const normalized = normalizePathEntryForComparison(trimmed, platform);
437 const normalized = normalizePathEntryForComparison(sanitized, platform);
434438 if (normalized.length === 0 || seen.has(normalized)) continue;
435439
436440 seen.add(normalized);
437 merged.push(trimmed);
441 merged.push(sanitized);
438442 }
439443 }
440444