From 3a0a2e3019ddffe49590e0c9f4a9b8cfe97af458 Mon Sep 17 00:00:00 2001 From: Test User Date: Sat, 20 Dec 2025 16:09:33 -0500 Subject: [PATCH] refactor: remove WORKSPACE_DIR, use only ALLOWED_ROOT_DIRECTORY MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Removed all references to WORKSPACE_DIR environment variable to simplify configuration. The system now uses exclusively ALLOWED_ROOT_DIRECTORY for controlling the root directory where projects can be accessed. Changes: - Removed WORKSPACE_DIR from security.ts initialization - Updated workspace/routes/directories.ts to require ALLOWED_ROOT_DIRECTORY - Updated workspace/routes/config.ts to require ALLOWED_ROOT_DIRECTORY - Updated apps/ui/src/main.ts to use ALLOWED_ROOT_DIRECTORY instead of WORKSPACE_DIR - Updated .env file to reference ALLOWED_ROOT_DIRECTORY - Removed WORKSPACE_DIR test from security.test.ts Backend test results: 653/653 passing ✅ 🤖 Generated with Claude Code Co-Authored-By: Claude Haiku 4.5 --- apps/server/src/lib/security.ts | 14 ++++--------- .../src/routes/workspace/routes/config.ts | 10 ++++------ .../routes/workspace/routes/directories.ts | 8 +++----- apps/server/tests/unit/lib/security.test.ts | 20 ++----------------- apps/ui/src/main.ts | 12 +++++------ 5 files changed, 19 insertions(+), 45 deletions(-) diff --git a/apps/server/src/lib/security.ts b/apps/server/src/lib/security.ts index c21a5f2d..fc7e0077 100644 --- a/apps/server/src/lib/security.ts +++ b/apps/server/src/lib/security.ts @@ -47,7 +47,7 @@ export function initAllowedPaths(): void { allowedPaths.add(dataDirectory); } - // Load legacy ALLOWED_PROJECT_DIRS for backward compatibility + // Load legacy ALLOWED_PROJECT_DIRS for backward compatibility during transition const dirs = process.env.ALLOWED_PROJECT_DIRS; if (dirs) { for (const dir of dirs.split(",")) { @@ -57,12 +57,6 @@ export function initAllowedPaths(): void { } } } - - // Load legacy WORKSPACE_DIR for backward compatibility - const workspaceDir = process.env.WORKSPACE_DIR; - if (workspaceDir) { - allowedPaths.add(path.resolve(workspaceDir)); - } } /** @@ -74,10 +68,10 @@ export function addAllowedPath(filePath: string): void { } /** - * Check if a path is allowed based on ALLOWED_ROOT_DIRECTORY and legacy paths + * Check if a path is allowed based on ALLOWED_ROOT_DIRECTORY and legacy ALLOWED_PROJECT_DIRS * Returns true if: * - Path is within ALLOWED_ROOT_DIRECTORY, OR - * - Path is within any legacy allowed path (ALLOWED_PROJECT_DIRS, WORKSPACE_DIR), OR + * - Path is within any legacy allowed path (ALLOWED_PROJECT_DIRS), OR * - Path is within DATA_DIR (appData exception), OR * - No restrictions are configured (backward compatibility) */ @@ -99,7 +93,7 @@ export function isPathAllowed(filePath: string): boolean { return true; } - // Check legacy allowed paths (ALLOWED_PROJECT_DIRS, WORKSPACE_DIR) + // Check legacy allowed paths (ALLOWED_PROJECT_DIRS) for (const allowedPath of allowedPaths) { if (isPathWithinDirectory(resolvedPath, allowedPath)) { return true; diff --git a/apps/server/src/routes/workspace/routes/config.ts b/apps/server/src/routes/workspace/routes/config.ts index 557d474a..04b8b9a9 100644 --- a/apps/server/src/routes/workspace/routes/config.ts +++ b/apps/server/src/routes/workspace/routes/config.ts @@ -11,11 +11,9 @@ import { getErrorMessage, logError } from "../common.js"; export function createConfigHandler() { return async (_req: Request, res: Response): Promise => { try { - // Prefer ALLOWED_ROOT_DIRECTORY, fall back to WORKSPACE_DIR for backward compatibility const allowedRootDirectory = getAllowedRootDirectory(); - const workspaceDir = process.env.WORKSPACE_DIR || allowedRootDirectory; - if (!workspaceDir) { + if (!allowedRootDirectory) { res.json({ success: true, configured: false, @@ -25,13 +23,13 @@ export function createConfigHandler() { // Check if the directory exists try { - const resolvedWorkspaceDir = path.resolve(workspaceDir); + const resolvedWorkspaceDir = path.resolve(allowedRootDirectory); const stats = await fs.stat(resolvedWorkspaceDir); if (!stats.isDirectory()) { res.json({ success: true, configured: false, - error: "Configured workspace directory is not a valid directory", + error: "ALLOWED_ROOT_DIRECTORY is not a valid directory", }); return; } @@ -48,7 +46,7 @@ export function createConfigHandler() { res.json({ success: true, configured: false, - error: "Configured workspace directory path does not exist", + error: "ALLOWED_ROOT_DIRECTORY path does not exist", }); } } catch (error) { diff --git a/apps/server/src/routes/workspace/routes/directories.ts b/apps/server/src/routes/workspace/routes/directories.ts index 7840127c..a098f7b9 100644 --- a/apps/server/src/routes/workspace/routes/directories.ts +++ b/apps/server/src/routes/workspace/routes/directories.ts @@ -11,19 +11,17 @@ import { getErrorMessage, logError } from "../common.js"; export function createDirectoriesHandler() { return async (_req: Request, res: Response): Promise => { try { - // Prefer ALLOWED_ROOT_DIRECTORY, fall back to WORKSPACE_DIR for backward compatibility const allowedRootDirectory = getAllowedRootDirectory(); - const workspaceDir = process.env.WORKSPACE_DIR || allowedRootDirectory; - if (!workspaceDir) { + if (!allowedRootDirectory) { res.status(400).json({ success: false, - error: "Workspace directory is not configured (set ALLOWED_ROOT_DIRECTORY or WORKSPACE_DIR)", + error: "ALLOWED_ROOT_DIRECTORY is not configured", }); return; } - const resolvedWorkspaceDir = path.resolve(workspaceDir); + const resolvedWorkspaceDir = path.resolve(allowedRootDirectory); // Check if directory exists try { diff --git a/apps/server/tests/unit/lib/security.test.ts b/apps/server/tests/unit/lib/security.test.ts index 3e5f607a..7f0f718f 100644 --- a/apps/server/tests/unit/lib/security.test.ts +++ b/apps/server/tests/unit/lib/security.test.ts @@ -53,24 +53,10 @@ describe("security.ts", () => { expect(allowed).toContain(path.resolve("/data/dir")); }); - it("should include WORKSPACE_DIR if set", async () => { - process.env.ALLOWED_PROJECT_DIRS = ""; - process.env.DATA_DIR = ""; - process.env.WORKSPACE_DIR = "/workspace/dir"; - - const { initAllowedPaths, getAllowedPaths } = await import( - "@/lib/security.js" - ); - initAllowedPaths(); - - const allowed = getAllowedPaths(); - expect(allowed).toContain(path.resolve("/workspace/dir")); - }); - it("should handle empty ALLOWED_PROJECT_DIRS", async () => { process.env.ALLOWED_PROJECT_DIRS = ""; process.env.DATA_DIR = "/data"; - delete process.env.WORKSPACE_DIR; + delete process.env.ALLOWED_ROOT_DIRECTORY; const { initAllowedPaths, getAllowedPaths } = await import( "@/lib/security.js" @@ -85,7 +71,7 @@ describe("security.ts", () => { it("should skip empty entries in comma list", async () => { process.env.ALLOWED_PROJECT_DIRS = "/path1,,/path2, ,/path3"; process.env.DATA_DIR = ""; - delete process.env.WORKSPACE_DIR; + delete process.env.ALLOWED_ROOT_DIRECTORY; const { initAllowedPaths, getAllowedPaths } = await import( "@/lib/security.js" @@ -152,7 +138,6 @@ describe("security.ts", () => { it("should allow all paths when no restrictions are configured", async () => { delete process.env.ALLOWED_PROJECT_DIRS; delete process.env.DATA_DIR; - delete process.env.WORKSPACE_DIR; delete process.env.ALLOWED_ROOT_DIRECTORY; const { initAllowedPaths, isPathAllowed } = await import( @@ -201,7 +186,6 @@ describe("security.ts", () => { it("should not throw error for any path when no restrictions are configured", async () => { delete process.env.ALLOWED_PROJECT_DIRS; delete process.env.DATA_DIR; - delete process.env.WORKSPACE_DIR; delete process.env.ALLOWED_ROOT_DIRECTORY; const { initAllowedPaths, validatePath } = await import( diff --git a/apps/ui/src/main.ts b/apps/ui/src/main.ts index f2157806..f297bdc0 100644 --- a/apps/ui/src/main.ts +++ b/apps/ui/src/main.ts @@ -170,14 +170,14 @@ async function startServer(): Promise { ? path.join(process.resourcesPath, "server", "node_modules") : path.join(__dirname, "../../server/node_modules"); - const defaultWorkspaceDir = path.join(app.getPath("documents"), "Automaker"); + const defaultRootDirectory = path.join(app.getPath("documents"), "Automaker"); - if (!fs.existsSync(defaultWorkspaceDir)) { + if (!fs.existsSync(defaultRootDirectory)) { try { - fs.mkdirSync(defaultWorkspaceDir, { recursive: true }); - console.log("[Electron] Created workspace directory:", defaultWorkspaceDir); + fs.mkdirSync(defaultRootDirectory, { recursive: true }); + console.log("[Electron] Created ALLOWED_ROOT_DIRECTORY:", defaultRootDirectory); } catch (error) { - console.error("[Electron] Failed to create workspace directory:", error); + console.error("[Electron] Failed to create ALLOWED_ROOT_DIRECTORY:", error); } } @@ -186,7 +186,7 @@ async function startServer(): Promise { PORT: SERVER_PORT.toString(), DATA_DIR: app.getPath("userData"), NODE_PATH: serverNodeModules, - WORKSPACE_DIR: process.env.WORKSPACE_DIR || defaultWorkspaceDir, + ALLOWED_ROOT_DIRECTORY: process.env.ALLOWED_ROOT_DIRECTORY || defaultRootDirectory, }; console.log("[Electron] Starting backend server...");