From 90a27b96ca55aefaa64cc669e3870f317af31627 Mon Sep 17 00:00:00 2001 From: "Rossdan Craig rossdan@lastmileai.dev" <> Date: Thu, 22 Feb 2024 17:21:10 -0500 Subject: [PATCH] [vscode][6/n] Setup Env Variables: Add more validation to env path input Added two noteworthy checks that we didn't have before: 1. The filename itself must be ".env" (before it only checked for ending so things like "invalid/filename.env" could be valid) 2. The path must be a subset of the workspace path, to ensure that when we call the `loadenv()` function from Python in AIConfig SDK, it's able to access this `.env` file I also made this into a separate function to keep it cleaner ## Test Plan https://github.com/lastmile-ai/aiconfig/assets/151060367/d77305c4-2cc6-4cb8-a918-b74826ff3714 --- vscode-extension/src/extension.ts | 47 ++++++++++++++++++++++--------- 1 file changed, 34 insertions(+), 13 deletions(-) diff --git a/vscode-extension/src/extension.ts b/vscode-extension/src/extension.ts index b4788aa96..df68ca9fc 100644 --- a/vscode-extension/src/extension.ts +++ b/vscode-extension/src/extension.ts @@ -736,22 +736,14 @@ async function setupEnvironmentVariables(context: vscode.ExtensionContext) { const homedir = require("os").homedir(); // This is cross-platform: https://stackoverflow.com/a/9081436 const defaultEnvPath = path.join(homedir, ".env"); + const workspacePath = vscode.workspace.workspaceFolders + ? vscode.workspace.workspaceFolders[0].uri.fsPath + : null; + const envPath = await vscode.window.showInputBox({ prompt: "Enter the path of your .env file", value: defaultEnvPath, - validateInput: (text) => { - if (!text) { - return "File path is required"; - } else if (!text.endsWith(".env")) { - return "File path must end in .env file"; - } - // TODO: Check that file path is a "/.env" file (linux) or "\.env" (Windows) - - // TODO: Check that env path is contained within workspace hierarchy - // (Ex: can't have .env file in a sibling dir otherwise AIConfig - // loadenv can't read it) - return null; - }, + validateInput: (input) => validateEnvPath(input, workspacePath), }); if (!envPath) { @@ -812,6 +804,35 @@ async function setupEnvironmentVariables(context: vscode.ExtensionContext) { } } +function validateEnvPath( + inputPath: string, + workspacePath: string | null +): string | null { + if (!inputPath) { + return "File path is required"; + } else if (path.basename(inputPath) !== ".env") { + return 'Filename must be ".env"'; + } else if (workspacePath !== null) { + // Loadenv from Python checks each folder from the file/program where it's + // invoked for the presence of an `.env` file. Therefore, the `.env` file + // must be saved either at the top-level directory of the workspace + // directory, or one of it's parent directories. This will ensure that if + // two AIConfig files are contained in separate paths within the workspace + // they'll still be able to access the same `.env` file. + + // Note: If the `inputPath` directory is equal to the `workspacePath`, + // `relativePathFromEnvToWorkspace` will be an empty string + const relativePathFromEnvToWorkspace = path.relative( + path.dirname(inputPath), + workspacePath + ); + if (relativePathFromEnvToWorkspace.startsWith("..")) { + return `File path must either be contained within the VS Code workspace directory ('${workspacePath}') or within a one of it's parent folders`; + } + } + return null; +} + async function shareAIConfig( context: vscode.ExtensionContext, aiconfigEditorManager: AIConfigEditorManager