From e6e00789e18a649a35b2cf89de3efd54c4150696 Mon Sep 17 00:00:00 2001 From: Qiuner Date: Wed, 19 Aug 2026 16:26:51 +0800 Subject: [PATCH] fix(desktop): enforce volume checks for dropped workspaces --- dsh-plugin-desktop/src/client/index.ts | 5 ++++- .../src/client/workspace-folder-drop.ts | 4 ++++ .../tests/client-workspace-folder-drop.spec.ts | 16 ++++++++++++++++ 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/dsh-plugin-desktop/src/client/index.ts b/dsh-plugin-desktop/src/client/index.ts index 12487e6ccf..816d7ad75c 100644 --- a/dsh-plugin-desktop/src/client/index.ts +++ b/dsh-plugin-desktop/src/client/index.ts @@ -7,7 +7,7 @@ import type {} from '@deepseek-ai/dsh-client-ui-settings/client' import type {} from '@deepseek-ai/dsh-client-ui-theme/client' import { applyAdvancedShell } from './advanced-shell.ts' import { startRendererBootReporter } from './boot-health.ts' -import { installDesktopDirectoryPickerBridge } from './directory-picker.ts' +import { installDesktopDirectoryPickerBridge, requestDesktopDirectoryValidation } from './directory-picker.ts' import { parseDesktopClientEnvironment } from './environment.ts' import { installWorkspaceFolderDrop } from './workspace-folder-drop.ts' @@ -42,6 +42,9 @@ export function apply(ctx: ClientContext): void { () => installWorkspaceFolderDrop({ create: input => ctx.workspaces.create(input), startSession: workspaceId => { ctx.workspaces.startSession(workspaceId) }, + ...(environment.platform === 'win32' + ? { validateDirectory: (path: string) => requestDesktopDirectoryValidation(path) } + : {}), }), 'dsh-plugin-desktop: workspace folder drop', ) diff --git a/dsh-plugin-desktop/src/client/workspace-folder-drop.ts b/dsh-plugin-desktop/src/client/workspace-folder-drop.ts index 09d47fa565..b19e74bafc 100644 --- a/dsh-plugin-desktop/src/client/workspace-folder-drop.ts +++ b/dsh-plugin-desktop/src/client/workspace-folder-drop.ts @@ -7,6 +7,7 @@ export const WORKSPACE_DROP_TARGET = '[data-dsh-workspace-drop-target]' export interface WorkspaceFolderDropActions { create(input: { path: string }): Promise startSession(workspaceId: WorkspaceId): void + validateDirectory?(path: string): Promise } type DropState = 'ready' | 'busy' | 'error' @@ -62,6 +63,9 @@ export async function adoptWorkspaceFolder( ): Promise { const path = bridge.getPathForFile(file).trim() if (path.length === 0) throw new Error('DSH Desktop could not read this folder path') + if (actions.validateDirectory !== undefined && !await actions.validateDirectory(path)) { + throw new Error('DSH Desktop rejected this workspace location') + } const workspace = await actions.create({ path }) actions.startSession(workspace.workspaceId) } diff --git a/dsh-plugin-desktop/tests/client-workspace-folder-drop.spec.ts b/dsh-plugin-desktop/tests/client-workspace-folder-drop.spec.ts index 5920f09348..ca8897366d 100644 --- a/dsh-plugin-desktop/tests/client-workspace-folder-drop.spec.ts +++ b/dsh-plugin-desktop/tests/client-workspace-folder-drop.spec.ts @@ -54,4 +54,20 @@ describe('desktop workspace folder drop', () => { .rejects.toThrow('could not read this folder path') expect(actions.create).not.toHaveBeenCalled() }) + + it('rejects a workspace when desktop validation denies its volume', async () => { + const actions: WorkspaceFolderDropActions = { + create: vi.fn(), + startSession: vi.fn(), + validateDirectory: vi.fn(async () => false), + } + + await expect(adoptWorkspaceFolder( + { name: 'repo' } as File, + { getPathForFile: () => 'E:\\repo' }, + actions, + )).rejects.toThrow('DSH Desktop rejected this workspace location') + expect(actions.validateDirectory).toHaveBeenCalledWith('E:\\repo') + expect(actions.create).not.toHaveBeenCalled() + }) })