Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 8 additions & 18 deletions src/extension/noConfigDebugInit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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-<sessionId>.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)) {
Expand Down Expand Up @@ -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 <script.py>`, 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,
Expand Down
11 changes: 6 additions & 5 deletions src/test/unittest/noConfigDebugInit.unit.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -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');
Expand All @@ -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 () => {
Expand Down Expand Up @@ -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);
});
Expand Down