From ef303eb84a7bc25aaaec16103e25842e8716fba0 Mon Sep 17 00:00:00 2001 From: Akhilesh Kumar Date: Thu, 21 May 2026 17:32:18 +0000 Subject: [PATCH] fix(core): fix workspace path validation with file:// URLs and encoded spaces Fixed a bug in validateWorkspacePath where splitting by path.delimiter on Unix would break file:// URLs due to colons. Added splitWorkspacePaths helper to handle this. Updated tests to use file:// URLs for encoded paths and added a test case to ensure literal %20 in cwd is not incorrectly resolved. --- .../core/src/ide/ide-connection-utils.test.ts | 15 ++++++++------- packages/core/src/ide/ide-connection-utils.ts | 11 +++++++++-- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/packages/core/src/ide/ide-connection-utils.test.ts b/packages/core/src/ide/ide-connection-utils.test.ts index f0e719e992..f337eacfc6 100644 --- a/packages/core/src/ide/ide-connection-utils.test.ts +++ b/packages/core/src/ide/ide-connection-utils.test.ts @@ -468,7 +468,7 @@ describe('ide-connection-utils', () => { describe('with special characters and encoding', () => { it('should return true for a URI-encoded path with spaces', () => { const workspaceDir = path.resolve('/test/my workspace'); - const workspacePath = '/test/my%20workspace'; + const workspacePath = pathToFileURL(workspaceDir).toString(); const cwd = path.join(workspaceDir, 'sub-dir'); const result = validateWorkspacePath(workspacePath, cwd); expect(result.isValid).toBe(true); @@ -476,7 +476,7 @@ describe('ide-connection-utils', () => { it('should return true for a URI-encoded path with Korean characters', () => { const workspaceDir = path.resolve('/test/테스트'); - const workspacePath = '/test/%ED%85%8C%EC%8A%A4%ED%8A%B8'; // "테스트" + const workspacePath = pathToFileURL(workspaceDir).toString(); const cwd = path.join(workspaceDir, 'sub-dir'); const result = validateWorkspacePath(workspacePath, cwd); expect(result.isValid).toBe(true); @@ -494,7 +494,7 @@ describe('ide-connection-utils', () => { const workspaceDir2 = path.resolve('/test/테스트'); const workspacePath = [ workspaceDir1, - '/test/%ED%85%8C%EC%8A%A4%ED%8A%B8', // "테스트" + pathToFileURL(workspaceDir2).toString(), ].join(path.delimiter); const cwd = path.join(workspaceDir2, 'sub-dir'); const result = validateWorkspacePath(workspacePath, cwd); @@ -536,17 +536,18 @@ describe('ide-connection-utils', () => { expectedValid: true, }, { - description: 'should return true when workspace has encoded spaces', - workspacePath: path.resolve('test', 'my ws').replace(/ /g, '%20'), + description: + 'should return true when workspace has encoded spaces in file:// URL', + workspacePath: pathToFileURL(path.resolve('test', 'my ws')).toString(), cwd: path.resolve('test', 'my ws'), expectedValid: true, }, { description: - 'should return true when cwd needs normalization matching workspace', + 'should return false when cwd has literal %20 and workspace has space', workspacePath: path.resolve('test', 'my ws'), cwd: path.resolve('test', 'my ws').replace(/ /g, '%20'), - expectedValid: true, + expectedValid: false, }, ])('$description', ({ workspacePath, cwd, expectedValid }) => { expect(validateWorkspacePath(workspacePath, cwd)).toMatchObject({ diff --git a/packages/core/src/ide/ide-connection-utils.ts b/packages/core/src/ide/ide-connection-utils.ts index 381297a28c..74e809e015 100644 --- a/packages/core/src/ide/ide-connection-utils.ts +++ b/packages/core/src/ide/ide-connection-utils.ts @@ -33,6 +33,14 @@ export type ConnectionConfig = { stdio?: StdioConfig; }; +function splitWorkspacePaths(paths: string): string[] { + if (process.platform === 'win32') { + return paths.split(';'); + } else { + return paths.split(/:(?!\/\/)/); + } +} + export function validateWorkspacePath( ideWorkspacePath: string | undefined, cwd: string, @@ -51,8 +59,7 @@ export function validateWorkspacePath( }; } - const ideWorkspacePaths = ideWorkspacePath - .split(path.delimiter) + const ideWorkspacePaths = splitWorkspacePaths(ideWorkspacePath) .map((p) => resolveToRealPath(p)) .filter((e) => !!e); const realCwd = resolveToRealPath(cwd);