@@ -422,39 +422,24 @@ export async function createPythonVenv(
422422 return createStepBasedVenvFlow ( nativeFinder , api , log , manager , basePythons , venvRoot , options ) ;
423423}
424424
425- /**
426- * Checks if a path is a drive root (e.g., "C:\" on Windows or "/" on Unix).
427- */
428425function isDriveRoot ( fsPath : string ) : boolean {
429426 const normalized = path . normalize ( fsPath ) ;
430427 if ( os . platform ( ) === 'win32' ) {
431- // Windows drive root: "C:\" or "C:"
432428 return / ^ [ a - z A - Z ] : [ \\ / ] ? $ / . test ( normalized ) ;
433429 }
434- // Unix root
435430 return normalized === '/' ;
436431}
437432
438- /**
439- * Checks if a path has a minimum number of directory components to be considered safe.
440- * This helps prevent accidental deletion of high-level directories.
441- */
442433function hasMinimumPathDepth ( fsPath : string , minDepth : number = 2 ) : boolean {
443434 const normalized = path . normalize ( fsPath ) ;
444435 const parts = normalized . split ( path . sep ) . filter ( ( p ) => p . length > 0 && p !== '.' ) ;
445436
446437 if ( os . platform ( ) === 'win32' ) {
447- // On Windows, the drive letter counts as one component
448- // e.g., "C:\folder" has parts ["C:", "folder"] -> depth 2
449438 return parts . length >= minDepth ;
450439 }
451- // On Unix, "/home/user" has parts ["home", "user"] -> depth 2
452440 return parts . length >= minDepth ;
453441}
454442
455- /**
456- * Validates that a path appears to be a virtual environment by checking for pyvenv.cfg.
457- */
458443async function isValidVenvPath ( fsPath : string ) : Promise < boolean > {
459444 try {
460445 const pyvenvCfgPath = path . join ( fsPath , 'pyvenv.cfg' ) ;
@@ -464,24 +449,17 @@ async function isValidVenvPath(fsPath: string): Promise<boolean> {
464449 }
465450}
466451
467- /**
468- * Validates that a path is safe to remove as a virtual environment.
469- * Returns an error message if unsafe, or undefined if safe.
470- */
471452async function validateVenvRemovalPath ( envPath : string , log : LogOutputChannel ) : Promise < string | undefined > {
472- // Check if it's a drive root
473453 if ( isDriveRoot ( envPath ) ) {
474454 log . error ( `Refusing to remove drive root: ${ envPath } ` ) ;
475455 return VenvManagerStrings . venvRemoveUnsafePath ;
476456 }
477457
478- // Check minimum path depth (at least 2 components to be safe)
479458 if ( ! hasMinimumPathDepth ( envPath , 2 ) ) {
480459 log . error ( `Refusing to remove path with insufficient depth: ${ envPath } ` ) ;
481460 return VenvManagerStrings . venvRemoveUnsafePath ;
482461 }
483462
484- // Check if it's actually a venv (has pyvenv.cfg)
485463 if ( ! ( await isValidVenvPath ( envPath ) ) ) {
486464 log . error ( `Path does not appear to be a valid venv (no pyvenv.cfg): ${ envPath } ` ) ;
487465 return VenvManagerStrings . venvRemoveInvalidPath ;
@@ -493,11 +471,9 @@ async function validateVenvRemovalPath(envPath: string, log: LogOutputChannel):
493471export async function removeVenv ( environment : PythonEnvironment , log : LogOutputChannel ) : Promise < boolean > {
494472 const pythonPath = os . platform ( ) === 'win32' ? 'python.exe' : 'python' ;
495473
496- // Normalize path separators before checking endsWith
497474 const envFsPath = path . normalize ( environment . environmentPath . fsPath ) ;
498475 const envPath = envFsPath . endsWith ( pythonPath ) ? path . dirname ( path . dirname ( envFsPath ) ) : envFsPath ;
499476
500- // Safety validation before proceeding
501477 const validationError = await validateVenvRemovalPath ( envPath , log ) ;
502478 if ( validationError ) {
503479 showErrorMessage ( validationError ) ;
0 commit comments