| author | |
| committer | |
| log | 12fe2d6d03062c5d7fc3beff168f8c4af1235b50 |
| tree | 84c8a3bed46e33e01ea2b396a07d6d97e6dad235 |
| parent | 6e324b9bbfc72e694c3c16abeb59716c37fc02d5 |
| signature | Signed by PGP key B5690EEEBB952194 |
4 files changed, 29 insertions(+), 11 deletions(-)
apps/desktop/src/shell/DesktopShellEnvironment.test.ts+2-1| ... | @@ -320,7 +320,7 @@ describe("DesktopShellEnvironment", () => { | ... | @@ -320,7 +320,7 @@ describe("DesktopShellEnvironment", () => { |
| 320 | FNM_DIR: "C:\\Users\\testuser\\AppData\\Roaming\\fnm", | 320 | FNM_DIR: "C:\\Users\\testuser\\AppData\\Roaming\\fnm", |
| 321 | FNM_MULTISHELL_PATH: "C:\\Users\\testuser\\AppData\\Local\\fnm_multishells\\123", | 321 | FNM_MULTISHELL_PATH: "C:\\Users\\testuser\\AppData\\Local\\fnm_multishells\\123", |
| 322 | }) | 322 | }) |
| 323 | : envOutput({ PATH: "C:\\Custom\\Bin;C:\\Windows\\System32" }); | 323 | : envOutput({ PATH: 'C:\\Custom\\Bin;C:";C:\\Windows\\System32' }); |
| 324 | }, | 324 | }, |
| 325 | }); | 325 | }); |
| 326 | 326 | ||
| ... | @@ -337,6 +337,7 @@ describe("DesktopShellEnvironment", () => { | ... | @@ -337,6 +337,7 @@ describe("DesktopShellEnvironment", () => { |
| 337 | "C:\\Users\\testuser\\.bun\\bin", | 337 | "C:\\Users\\testuser\\.bun\\bin", |
| 338 | "C:\\Users\\testuser\\scoop\\shims", | 338 | "C:\\Users\\testuser\\scoop\\shims", |
| 339 | "C:\\Custom\\Bin", | 339 | "C:\\Custom\\Bin", |
| 340 | "C:", | ||
| 340 | ].join(";"), | 341 | ].join(";"), |
| 341 | ); | 342 | ); |
| 342 | assert.equal(env.FNM_DIR, "C:\\Users\\testuser\\AppData\\Roaming\\fnm"); | 343 | 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) => { | ... | @@ -151,6 +151,9 @@ const pathComparisonKey = (entry: string, platform: NodeJS.Platform) => { |
| 151 | return platform === "win32" ? normalized.toLowerCase() : normalized; | 151 | return platform === "win32" ? normalized.toLowerCase() : normalized; |
| 152 | }; | 152 | }; |
| 153 | 153 | ||
| 154 | const sanitizePathEntry = (entry: string, platform: NodeJS.Platform) => | ||
| 155 | platform === "win32" ? entry.replaceAll('"', "") : entry; | ||
| 156 | |||
| 154 | const mergePaths = ( | 157 | const mergePaths = ( |
| 155 | platform: NodeJS.Platform, | 158 | platform: NodeJS.Platform, |
| 156 | values: ReadonlyArray<Option.Option<string>>, | 159 | values: ReadonlyArray<Option.Option<string>>, |
| ... | @@ -163,14 +166,14 @@ const mergePaths = ( | ... | @@ -163,14 +166,14 @@ const mergePaths = ( |
| 163 | if (Option.isNone(value)) continue; | 166 | if (Option.isNone(value)) continue; |
| 164 | 167 | ||
| 165 | for (const entry of value.value.split(delimiter)) { | 168 | for (const entry of value.value.split(delimiter)) { |
| 166 | const trimmed = entry.trim(); | 169 | const sanitized = sanitizePathEntry(entry.trim(), platform); |
| 167 | if (trimmed.length === 0) continue; | 170 | if (sanitized.length === 0) continue; |
| 168 | 171 | ||
| 169 | const key = pathComparisonKey(trimmed, platform); | 172 | const key = pathComparisonKey(sanitized, platform); |
| 170 | if (key.length === 0 || seen.has(key)) continue; | 173 | if (key.length === 0 || seen.has(key)) continue; |
| 171 | 174 | ||
| 172 | seen.add(key); | 175 | seen.add(key); |
| 173 | entries.push(trimmed); | 176 | entries.push(sanitized); |
| 174 | } | 177 | } |
| 175 | } | 178 | } |
| 176 | 179 |
packages/shared/src/shell.test.ts+12-2| ... | @@ -304,7 +304,7 @@ describe("readEnvironmentFromWindowsShell", () => { | ... | @@ -304,7 +304,7 @@ describe("readEnvironmentFromWindowsShell", () => { |
| 304 | }); | 304 | }); |
| 305 | 305 | ||
| 306 | describe("mergePathValues", () => { | 306 | describe("mergePathValues", () => { |
| 307 | it("dedupes case-insensitively on Windows while preserving preferred order", () => { | 307 | it("sanitizes and dedupes Windows entries while preserving preferred order", () => { |
| 308 | expect( | 308 | expect( |
| 309 | mergePathValues( | 309 | mergePathValues( |
| 310 | 'C:\\Users\\testuser\\AppData\\Roaming\\npm;"C:\\Program Files\\nodejs"', | 310 | 'C:\\Users\\testuser\\AppData\\Roaming\\npm;"C:\\Program Files\\nodejs"', |
| ... | @@ -312,10 +312,20 @@ describe("mergePathValues", () => { | ... | @@ -312,10 +312,20 @@ describe("mergePathValues", () => { |
| 312 | "win32", | 312 | "win32", |
| 313 | ), | 313 | ), |
| 314 | ).toBe( | 314 | ).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", |
| 316 | ); | 316 | ); |
| 317 | }); | 317 | }); |
| 318 | 318 | ||
| 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 | |||
| 319 | it("dedupes case-sensitively on POSIX", () => { | 329 | it("dedupes case-sensitively on POSIX", () => { |
| 320 | expect(mergePathValues("/usr/local/bin:/usr/bin", "/usr/bin:/USR/BIN", "linux")).toBe( | 330 | expect(mergePathValues("/usr/local/bin:/usr/bin", "/usr/bin:/USR/BIN", "linux")).toBe( |
| 321 | "/usr/local/bin:/usr/bin:/USR/BIN", | 331 | "/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 | ... | @@ -414,6 +414,10 @@ function normalizePathEntryForComparison(entry: string, platform: NodeJS.Platfor |
| 414 | return platform === "win32" ? normalized.toLowerCase() : normalized; | 414 | return platform === "win32" ? normalized.toLowerCase() : normalized; |
| 415 | } | 415 | } |
| 416 | 416 | ||
| 417 | function sanitizePathEntry(entry: string, platform: NodeJS.Platform): string { | ||
| 418 | return platform === "win32" ? entry.replaceAll('"', "") : entry; | ||
| 419 | } | ||
| 420 | |||
| 417 | export function mergePathValues( | 421 | export function mergePathValues( |
| 418 | preferredPath: string | undefined, | 422 | preferredPath: string | undefined, |
| 419 | inheritedPath: string | undefined, | 423 | inheritedPath: string | undefined, |
| ... | @@ -427,14 +431,14 @@ export function mergePathValues( | ... | @@ -427,14 +431,14 @@ export function mergePathValues( |
| 427 | if (!rawValue) continue; | 431 | if (!rawValue) continue; |
| 428 | 432 | ||
| 429 | for (const entry of rawValue.split(delimiter)) { | 433 | for (const entry of rawValue.split(delimiter)) { |
| 430 | const trimmed = entry.trim(); | 434 | const sanitized = sanitizePathEntry(entry.trim(), platform); |
| 431 | if (trimmed.length === 0) continue; | 435 | if (sanitized.length === 0) continue; |
| 432 | 436 | ||
| 433 | const normalized = normalizePathEntryForComparison(trimmed, platform); | 437 | const normalized = normalizePathEntryForComparison(sanitized, platform); |
| 434 | if (normalized.length === 0 || seen.has(normalized)) continue; | 438 | if (normalized.length === 0 || seen.has(normalized)) continue; |
| 435 | 439 | ||
| 436 | seen.add(normalized); | 440 | seen.add(normalized); |
| 437 | merged.push(trimmed); | 441 | merged.push(sanitized); |
| 438 | } | 442 | } |
| 439 | } | 443 | } |
| 440 | 444 |