diff --git a/src/extension/noConfigDebugInit.ts b/src/extension/noConfigDebugInit.ts index 23ed3790..a83d000e 100644 --- a/src/extension/noConfigDebugInit.ts +++ b/src/extension/noConfigDebugInit.ts @@ -8,9 +8,9 @@ import { DebugSessionOptions, Disposable, GlobalEnvironmentVariableCollection, + env, l10n, RelativePattern, - workspace, } from 'vscode'; import { createFileSystemWatcher, debugStartDebugging } from './utils'; import { traceError, traceVerbose } from './common/log/logging'; @@ -39,23 +39,13 @@ export async function registerNoConfigDebug( const collection = envVarCollection; // create a temp directory for the noConfigDebugAdapterEndpoints - // file path format: extPath/.noConfigDebugAdapterEndpoints/endpoint-stableWorkspaceHash.txt - let workspaceString = workspace.workspaceFile?.fsPath; - if (!workspaceString) { - workspaceString = workspace.workspaceFolders?.map((e) => e.uri.fsPath).join(';'); - } - if (!workspaceString) { - traceError('No workspace folder found'); - return Promise.resolve(new Disposable(() => {})); - } - - // create a stable hash for the workspace folder, reduce terminal variable churn - const hash = crypto.createHash('sha256'); - hash.update(workspaceString.toString()); - const stableWorkspaceHash = hash.digest('hex').slice(0, 16); + // file path format: extPath/.noConfigDebugAdapterEndpoints/endpoint-.txt + // sessionId is unique per VS Code window, ensuring isolation between windows const tempDirPath = path.join(extPath, '.noConfigDebugAdapterEndpoints'); - const tempFilePath = path.join(tempDirPath, `endpoint-${stableWorkspaceHash}.txt`); + const sessionIdHash = crypto.createHash('sha256').update(env.sessionId).digest('hex').slice(0, 16); + const endpointFilename = `endpoint-${sessionIdHash}.txt`; + const tempFilePath = path.join(tempDirPath, endpointFilename); // create the temp directory if it doesn't exist if (!fs.existsSync(tempDirPath)) { @@ -92,8 +82,8 @@ export async function registerNoConfigDebug( 'Enables use of [no-config debugging](https://github.com/microsoft/vscode-python-debugger/wiki/No%E2%80%90Config-Debugging), `debugpy `, in the terminal.', ); - // create file system watcher for the debuggerAdapterEndpointFolder for when the communication port is written - const fileSystemWatcher = createFileSystemWatcher(new RelativePattern(tempDirPath, '**/*.txt')); + // create file system watcher for the debugger adapter endpoint for when the communication port is written + const fileSystemWatcher = createFileSystemWatcher(new RelativePattern(tempDirPath, endpointFilename)); const fileCreationEvent = fileSystemWatcher.onDidCreate(async (uri) => { sendTelemetryEvent(EventName.DEBUG_SESSION_START, undefined, { trigger: 'noConfig' as TriggerType, diff --git a/src/test/unittest/noConfigDebugInit.unit.test.ts b/src/test/unittest/noConfigDebugInit.unit.test.ts index 3cf6e401..f7261807 100644 --- a/src/test/unittest/noConfigDebugInit.unit.test.ts +++ b/src/test/unittest/noConfigDebugInit.unit.test.ts @@ -6,7 +6,7 @@ import { IExtensionContext } from '../../extension/common/types'; import { registerNoConfigDebug as registerNoConfigDebug } from '../../extension/noConfigDebugInit'; import * as TypeMoq from 'typemoq'; import * as sinon from 'sinon'; -import { DebugConfiguration, DebugSessionOptions, RelativePattern, Uri, workspace } from 'vscode'; +import { DebugConfiguration, DebugSessionOptions, env, RelativePattern, Uri } from 'vscode'; import * as utils from '../../extension/utils'; import { assert } from 'console'; import * as fs from 'fs'; @@ -21,7 +21,8 @@ suite('setup for no-config debug scenario', function () { let bundledDebugPath: string; let DEBUGPY_ADAPTER_ENDPOINTS = 'DEBUGPY_ADAPTER_ENDPOINTS'; let BUNDLED_DEBUGPY_PATH = 'BUNDLED_DEBUGPY_PATH'; - let workspaceUriStub: sinon.SinonStub; + const testSessionId = 'test-session-id-1234'; + const hashedSessionId = crypto.createHash('sha256').update(testSessionId).digest('hex').slice(0, 16); const testDataDir = path.join(__dirname, 'testData'); const testFilePath = path.join(testDataDir, 'debuggerAdapterEndpoint.txt'); @@ -39,14 +40,14 @@ suite('setup for no-config debug scenario', function () { // Provide a valid Buffer object randomBytesStub.callsFake((_size: number) => Buffer.from('1234567899', 'hex')); - workspaceUriStub = sinon.stub(workspace, 'workspaceFolders').value([{ uri: Uri.parse(os.tmpdir()) }]); + // Stub env.sessionId to return a consistent value for tests + sinon.stub(env, 'sessionId').value(testSessionId); } catch (error) { console.error('Error in setup:', error); } }); teardown(() => { sinon.restore(); - workspaceUriStub.restore(); }); test('should add environment variables for DEBUGPY_ADAPTER_ENDPOINTS, BUNDLED_DEBUGPY_PATH, and PATH', async () => { @@ -195,7 +196,7 @@ suite('setup for no-config debug scenario', function () { sinon.assert.calledOnce(createFileSystemWatcherFunct); const expectedPattern = new RelativePattern( path.join(os.tmpdir(), '.noConfigDebugAdapterEndpoints'), - '**/*.txt', + `endpoint-${hashedSessionId}.txt`, ); sinon.assert.calledWith(createFileSystemWatcherFunct, expectedPattern); });