From 4e3a4adf18ec0831f15c003fecc4d1c24f6d0812 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 4 Feb 2026 19:43:05 +0000 Subject: [PATCH 1/7] Initial plan From 99429bf78b698ba6ca3dcd1cb9bfef075d16760f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 4 Feb 2026 19:45:14 +0000 Subject: [PATCH 2/7] feat: add validation for DEV_USER_EXTENSIONS_PATH environment variable Co-authored-by: yCodeTech <31927084+yCodeTech@users.noreply.github.com> --- src/extensionData.ts | 37 +++++++++++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/src/extensionData.ts b/src/extensionData.ts index 6a37b5e..d9651dc 100644 --- a/src/extensionData.ts +++ b/src/extensionData.ts @@ -1,10 +1,12 @@ import * as vscode from "vscode"; import * as path from "path"; +import * as fs from "fs"; import isWsl from "is-wsl"; import {IPackageJson} from "package-json-type"; import {readJsonFile} from "./utils"; import {ExtensionMetaData, ExtensionPaths, ExtensionMetaDataValue} from "./interfaces/extensionMetaData"; +import {logger} from "./logger"; export class ExtensionData { /** @@ -94,20 +96,39 @@ export class ExtensionData { * Set the extension discovery paths into the extensionDiscoveryPaths Map. */ private setExtensionDiscoveryPaths() { - // Get the DEV_USER_EXTENSIONS_PATH env variable if it exists. - const devUserExtensionsPath = process.env.DEV_USER_EXTENSIONS_PATH; - - // The path to the user extensions. + // The default path to the user extensions. // // On Windows/Linux/Mac: ~/.vscode[-server|remote]/extensions // On WSL: ~/.vscode-[server|remote]/extensions // // Because the extensionPath is created from __dirname and retrieves where this extension // is located, in extension testing/development mode, this path will point to the local - // development path, not the actual user extensions path. So we use the custom - // DEV_USER_EXTENSIONS_PATH env variable to override it. - const userExtensionsPath = - devUserExtensionsPath || (isWsl ? path.join(vscode.env.appRoot, "../../", "extensions") : path.join(this.extensionPath, "../")); + // development path, not the actual user extensions path. + const defaultUserExtensionsPath = isWsl ? path.join(vscode.env.appRoot, "../../", "extensions") : path.join(this.extensionPath, "../"); + + // Get the DEV_USER_EXTENSIONS_PATH env variable if it exists. + let devUserExtensionsPath = process.env.DEV_USER_EXTENSIONS_PATH; + + // Validate and sanitize DEV_USER_EXTENSIONS_PATH if provided + if (devUserExtensionsPath) { + // Trim whitespace and resolve the path to an absolute path + devUserExtensionsPath = path.resolve(devUserExtensionsPath.trim()); + + // Check if the path exists and is a directory + try { + const stats = fs.statSync(devUserExtensionsPath); + if (!stats.isDirectory()) { + logger.error(`DEV_USER_EXTENSIONS_PATH is not a directory: ${devUserExtensionsPath}. Falling back to default path.`); + devUserExtensionsPath = undefined; + } + } catch (error) { + logger.error(`DEV_USER_EXTENSIONS_PATH does not exist or is not accessible: ${devUserExtensionsPath}. Falling back to default path.`, error as Error); + devUserExtensionsPath = undefined; + } + } + + // Use the validated dev path or fall back to the default path + const userExtensionsPath = devUserExtensionsPath || defaultUserExtensionsPath; this.extensionDiscoveryPaths.set("userExtensionsPath", userExtensionsPath); // The path to the built-in extensions. From a1913aab13a757256a2dff92c2c4749d7e2cd842 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 4 Feb 2026 19:46:04 +0000 Subject: [PATCH 3/7] refactor: improve error handling and specificity for path validation Co-authored-by: yCodeTech <31927084+yCodeTech@users.noreply.github.com> --- src/extensionData.ts | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/src/extensionData.ts b/src/extensionData.ts index d9651dc..3d2b1ae 100644 --- a/src/extensionData.ts +++ b/src/extensionData.ts @@ -115,15 +115,25 @@ export class ExtensionData { devUserExtensionsPath = path.resolve(devUserExtensionsPath.trim()); // Check if the path exists and is a directory - try { - const stats = fs.statSync(devUserExtensionsPath); - if (!stats.isDirectory()) { - logger.error(`DEV_USER_EXTENSIONS_PATH is not a directory: ${devUserExtensionsPath}. Falling back to default path.`); + if (!fs.existsSync(devUserExtensionsPath)) { + logger.error(`DEV_USER_EXTENSIONS_PATH does not exist: ${devUserExtensionsPath}. Falling back to default path.`); + devUserExtensionsPath = undefined; + } else { + try { + const stats = fs.statSync(devUserExtensionsPath); + if (!stats.isDirectory()) { + logger.error(`DEV_USER_EXTENSIONS_PATH is not a directory: ${devUserExtensionsPath}. Falling back to default path.`); + devUserExtensionsPath = undefined; + } + } catch (error) { + const nodeError = error as NodeJS.ErrnoException; + const errorCode = nodeError.code || "UNKNOWN"; + const errorMessage = errorCode === "EACCES" + ? `Permission denied accessing DEV_USER_EXTENSIONS_PATH: ${devUserExtensionsPath}. Falling back to default path.` + : `Error accessing DEV_USER_EXTENSIONS_PATH: ${devUserExtensionsPath} (${errorCode}). Falling back to default path.`; + logger.error(errorMessage, error as Error); devUserExtensionsPath = undefined; } - } catch (error) { - logger.error(`DEV_USER_EXTENSIONS_PATH does not exist or is not accessible: ${devUserExtensionsPath}. Falling back to default path.`, error as Error); - devUserExtensionsPath = undefined; } } From 88864fe31f8e4d0b180d0d3b6a66ca292cd0b1fe Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 5 Feb 2026 02:46:06 +0000 Subject: [PATCH 4/7] refactor: move validation logic to addDevEnvVariables utility function Co-authored-by: yCodeTech <31927084+yCodeTech@users.noreply.github.com> --- src/extensionData.ts | 48 +++++++++----------------------------------- src/utils.ts | 34 +++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 39 deletions(-) diff --git a/src/extensionData.ts b/src/extensionData.ts index 3d2b1ae..ac2a400 100644 --- a/src/extensionData.ts +++ b/src/extensionData.ts @@ -1,12 +1,10 @@ import * as vscode from "vscode"; import * as path from "path"; -import * as fs from "fs"; import isWsl from "is-wsl"; import {IPackageJson} from "package-json-type"; import {readJsonFile} from "./utils"; import {ExtensionMetaData, ExtensionPaths, ExtensionMetaDataValue} from "./interfaces/extensionMetaData"; -import {logger} from "./logger"; export class ExtensionData { /** @@ -96,49 +94,21 @@ export class ExtensionData { * Set the extension discovery paths into the extensionDiscoveryPaths Map. */ private setExtensionDiscoveryPaths() { - // The default path to the user extensions. + // Get the DEV_USER_EXTENSIONS_PATH env variable if it exists. + // This variable is validated and sanitized by addDevEnvVariables() in utils.ts + const devUserExtensionsPath = process.env.DEV_USER_EXTENSIONS_PATH; + + // The path to the user extensions. // // On Windows/Linux/Mac: ~/.vscode[-server|remote]/extensions // On WSL: ~/.vscode-[server|remote]/extensions // // Because the extensionPath is created from __dirname and retrieves where this extension // is located, in extension testing/development mode, this path will point to the local - // development path, not the actual user extensions path. - const defaultUserExtensionsPath = isWsl ? path.join(vscode.env.appRoot, "../../", "extensions") : path.join(this.extensionPath, "../"); - - // Get the DEV_USER_EXTENSIONS_PATH env variable if it exists. - let devUserExtensionsPath = process.env.DEV_USER_EXTENSIONS_PATH; - - // Validate and sanitize DEV_USER_EXTENSIONS_PATH if provided - if (devUserExtensionsPath) { - // Trim whitespace and resolve the path to an absolute path - devUserExtensionsPath = path.resolve(devUserExtensionsPath.trim()); - - // Check if the path exists and is a directory - if (!fs.existsSync(devUserExtensionsPath)) { - logger.error(`DEV_USER_EXTENSIONS_PATH does not exist: ${devUserExtensionsPath}. Falling back to default path.`); - devUserExtensionsPath = undefined; - } else { - try { - const stats = fs.statSync(devUserExtensionsPath); - if (!stats.isDirectory()) { - logger.error(`DEV_USER_EXTENSIONS_PATH is not a directory: ${devUserExtensionsPath}. Falling back to default path.`); - devUserExtensionsPath = undefined; - } - } catch (error) { - const nodeError = error as NodeJS.ErrnoException; - const errorCode = nodeError.code || "UNKNOWN"; - const errorMessage = errorCode === "EACCES" - ? `Permission denied accessing DEV_USER_EXTENSIONS_PATH: ${devUserExtensionsPath}. Falling back to default path.` - : `Error accessing DEV_USER_EXTENSIONS_PATH: ${devUserExtensionsPath} (${errorCode}). Falling back to default path.`; - logger.error(errorMessage, error as Error); - devUserExtensionsPath = undefined; - } - } - } - - // Use the validated dev path or fall back to the default path - const userExtensionsPath = devUserExtensionsPath || defaultUserExtensionsPath; + // development path, not the actual user extensions path. So we use the custom + // DEV_USER_EXTENSIONS_PATH env variable to override it. + const userExtensionsPath = + devUserExtensionsPath || (isWsl ? path.join(vscode.env.appRoot, "../../", "extensions") : path.join(this.extensionPath, "../")); this.extensionDiscoveryPaths.set("userExtensionsPath", userExtensionsPath); // The path to the built-in extensions. diff --git a/src/utils.ts b/src/utils.ts index bdbbdf4..a2da65f 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -241,6 +241,7 @@ export function mergeArraysBy(primaryArray: T[], secondaryArray: T[], key: ke /** * Add development environment variables from a local .env file located in the project root. + * Validates and sanitizes specific environment variables after loading. */ export function addDevEnvVariables() { // Try to load the local .env file from the project root. @@ -249,4 +250,37 @@ export function addDevEnvVariables() { } catch (error) { // Ignore errors if the .env file doesn't exist } + + // Validate DEV_USER_EXTENSIONS_PATH if it was loaded + if (process.env.DEV_USER_EXTENSIONS_PATH) { + let devPath = process.env.DEV_USER_EXTENSIONS_PATH; + + // Trim whitespace and resolve the path to an absolute path + devPath = path.resolve(devPath.trim()); + + // Check if the path exists and is a directory + if (!fs.existsSync(devPath)) { + logger.error(`DEV_USER_EXTENSIONS_PATH does not exist: ${devPath}. Removing from environment.`); + delete process.env.DEV_USER_EXTENSIONS_PATH; + } else { + try { + const stats = fs.statSync(devPath); + if (!stats.isDirectory()) { + logger.error(`DEV_USER_EXTENSIONS_PATH is not a directory: ${devPath}. Removing from environment.`); + delete process.env.DEV_USER_EXTENSIONS_PATH; + } else { + // Update the environment variable with the sanitized (trimmed and resolved) path + process.env.DEV_USER_EXTENSIONS_PATH = devPath; + } + } catch (error) { + const nodeError = error as NodeJS.ErrnoException; + const errorCode = nodeError.code || "UNKNOWN"; + const errorMessage = errorCode === "EACCES" + ? `Permission denied accessing DEV_USER_EXTENSIONS_PATH: ${devPath}. Removing from environment.` + : `Error accessing DEV_USER_EXTENSIONS_PATH: ${devPath} (${errorCode}). Removing from environment.`; + logger.error(errorMessage, error as Error); + delete process.env.DEV_USER_EXTENSIONS_PATH; + } + } + } } From 93d64a429299817cb6ba023dea9760954375ed8a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 5 Feb 2026 02:46:56 +0000 Subject: [PATCH 5/7] refactor: optimize filesystem checks and improve error messages Co-authored-by: yCodeTech <31927084+yCodeTech@users.noreply.github.com> --- src/utils.ts | 43 +++++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/src/utils.ts b/src/utils.ts index a2da65f..49f2b15 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -259,28 +259,31 @@ export function addDevEnvVariables() { devPath = path.resolve(devPath.trim()); // Check if the path exists and is a directory - if (!fs.existsSync(devPath)) { - logger.error(`DEV_USER_EXTENSIONS_PATH does not exist: ${devPath}. Removing from environment.`); - delete process.env.DEV_USER_EXTENSIONS_PATH; - } else { - try { - const stats = fs.statSync(devPath); - if (!stats.isDirectory()) { - logger.error(`DEV_USER_EXTENSIONS_PATH is not a directory: ${devPath}. Removing from environment.`); - delete process.env.DEV_USER_EXTENSIONS_PATH; - } else { - // Update the environment variable with the sanitized (trimmed and resolved) path - process.env.DEV_USER_EXTENSIONS_PATH = devPath; - } - } catch (error) { - const nodeError = error as NodeJS.ErrnoException; - const errorCode = nodeError.code || "UNKNOWN"; - const errorMessage = errorCode === "EACCES" - ? `Permission denied accessing DEV_USER_EXTENSIONS_PATH: ${devPath}. Removing from environment.` - : `Error accessing DEV_USER_EXTENSIONS_PATH: ${devPath} (${errorCode}). Removing from environment.`; - logger.error(errorMessage, error as Error); + try { + const stats = fs.statSync(devPath); + if (!stats.isDirectory()) { + logger.error(`DEV_USER_EXTENSIONS_PATH is not a directory: ${devPath}. Removing from environment.`); delete process.env.DEV_USER_EXTENSIONS_PATH; + } else { + // Update the environment variable with the sanitized (trimmed and resolved) path + process.env.DEV_USER_EXTENSIONS_PATH = devPath; } + } catch (error) { + const nodeError = error as NodeJS.ErrnoException; + const errorCode = nodeError.code || "UNKNOWN"; + + // Provide specific error messages based on the error code + let errorMessage: string; + if (errorCode === "ENOENT") { + errorMessage = `DEV_USER_EXTENSIONS_PATH does not exist: ${devPath}. Removing from environment.`; + } else if (errorCode === "EACCES") { + errorMessage = `Permission denied accessing DEV_USER_EXTENSIONS_PATH: ${devPath}. Removing from environment.`; + } else { + errorMessage = `Error accessing DEV_USER_EXTENSIONS_PATH: ${devPath} (${errorCode}). Removing from environment.`; + } + + logger.error(errorMessage, error as Error); + delete process.env.DEV_USER_EXTENSIONS_PATH; } } } From 64f50b57c14c187fb27365b4952275d66ab0fd8b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 5 Feb 2026 02:57:05 +0000 Subject: [PATCH 6/7] refactor: extract validation into separate function following DOT principle Co-authored-by: yCodeTech <31927084+yCodeTech@users.noreply.github.com> --- src/extensionData.ts | 1 - src/utils.ts | 28 ++++++++++++++++++---------- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/src/extensionData.ts b/src/extensionData.ts index ac2a400..6a37b5e 100644 --- a/src/extensionData.ts +++ b/src/extensionData.ts @@ -95,7 +95,6 @@ export class ExtensionData { */ private setExtensionDiscoveryPaths() { // Get the DEV_USER_EXTENSIONS_PATH env variable if it exists. - // This variable is validated and sanitized by addDevEnvVariables() in utils.ts const devUserExtensionsPath = process.env.DEV_USER_EXTENSIONS_PATH; // The path to the user extensions. diff --git a/src/utils.ts b/src/utils.ts index 49f2b15..e4578f5 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -240,17 +240,10 @@ export function mergeArraysBy(primaryArray: T[], secondaryArray: T[], key: ke } /** - * Add development environment variables from a local .env file located in the project root. - * Validates and sanitizes specific environment variables after loading. + * Validate and sanitize the DEV_USER_EXTENSIONS_PATH environment variable. + * Removes invalid paths from the environment with logged errors. */ -export function addDevEnvVariables() { - // Try to load the local .env file from the project root. - try { - process.loadEnvFile(path.join(__dirname, "../../.env")); - } catch (error) { - // Ignore errors if the .env file doesn't exist - } - +function validateDevEnvVariables() { // Validate DEV_USER_EXTENSIONS_PATH if it was loaded if (process.env.DEV_USER_EXTENSIONS_PATH) { let devPath = process.env.DEV_USER_EXTENSIONS_PATH; @@ -287,3 +280,18 @@ export function addDevEnvVariables() { } } } + +/** + * Add development environment variables from a local .env file located in the project root. + */ +export function addDevEnvVariables() { + // Try to load the local .env file from the project root. + try { + process.loadEnvFile(path.join(__dirname, "../../.env")); + } catch (error) { + // Ignore errors if the .env file doesn't exist + } + + // Validate the loaded environment variables + validateDevEnvVariables(); +} From 25e5e94201446b7edad7c4570cc09dae40880237 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 6 Feb 2026 00:27:10 +0000 Subject: [PATCH 7/7] refactor: reorder functions for better organization Co-authored-by: yCodeTech <31927084+yCodeTech@users.noreply.github.com> --- src/utils.ts | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/utils.ts b/src/utils.ts index e4578f5..d0471b5 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -239,6 +239,21 @@ export function mergeArraysBy(primaryArray: T[], secondaryArray: T[], key: ke return merged; } +/** + * Add development environment variables from a local .env file located in the project root. + */ +export function addDevEnvVariables() { + // Try to load the local .env file from the project root. + try { + process.loadEnvFile(path.join(__dirname, "../../.env")); + } catch (error) { + // Ignore errors if the .env file doesn't exist + } + + // Validate the loaded environment variables + validateDevEnvVariables(); +} + /** * Validate and sanitize the DEV_USER_EXTENSIONS_PATH environment variable. * Removes invalid paths from the environment with logged errors. @@ -280,18 +295,3 @@ function validateDevEnvVariables() { } } } - -/** - * Add development environment variables from a local .env file located in the project root. - */ -export function addDevEnvVariables() { - // Try to load the local .env file from the project root. - try { - process.loadEnvFile(path.join(__dirname, "../../.env")); - } catch (error) { - // Ignore errors if the .env file doesn't exist - } - - // Validate the loaded environment variables - validateDevEnvVariables(); -}