mirror of
https://github.com/AutoMaker-Org/automaker.git
synced 2026-02-04 21:23:07 +00:00
refactor: remove WORKSPACE_DIR, use only ALLOWED_ROOT_DIRECTORY
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 <noreply@anthropic.com>
This commit is contained in:
@@ -47,7 +47,7 @@ export function initAllowedPaths(): void {
|
|||||||
allowedPaths.add(dataDirectory);
|
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;
|
const dirs = process.env.ALLOWED_PROJECT_DIRS;
|
||||||
if (dirs) {
|
if (dirs) {
|
||||||
for (const dir of dirs.split(",")) {
|
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:
|
* Returns true if:
|
||||||
* - Path is within ALLOWED_ROOT_DIRECTORY, OR
|
* - 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
|
* - Path is within DATA_DIR (appData exception), OR
|
||||||
* - No restrictions are configured (backward compatibility)
|
* - No restrictions are configured (backward compatibility)
|
||||||
*/
|
*/
|
||||||
@@ -99,7 +93,7 @@ export function isPathAllowed(filePath: string): boolean {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check legacy allowed paths (ALLOWED_PROJECT_DIRS, WORKSPACE_DIR)
|
// Check legacy allowed paths (ALLOWED_PROJECT_DIRS)
|
||||||
for (const allowedPath of allowedPaths) {
|
for (const allowedPath of allowedPaths) {
|
||||||
if (isPathWithinDirectory(resolvedPath, allowedPath)) {
|
if (isPathWithinDirectory(resolvedPath, allowedPath)) {
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -11,11 +11,9 @@ import { getErrorMessage, logError } from "../common.js";
|
|||||||
export function createConfigHandler() {
|
export function createConfigHandler() {
|
||||||
return async (_req: Request, res: Response): Promise<void> => {
|
return async (_req: Request, res: Response): Promise<void> => {
|
||||||
try {
|
try {
|
||||||
// Prefer ALLOWED_ROOT_DIRECTORY, fall back to WORKSPACE_DIR for backward compatibility
|
|
||||||
const allowedRootDirectory = getAllowedRootDirectory();
|
const allowedRootDirectory = getAllowedRootDirectory();
|
||||||
const workspaceDir = process.env.WORKSPACE_DIR || allowedRootDirectory;
|
|
||||||
|
|
||||||
if (!workspaceDir) {
|
if (!allowedRootDirectory) {
|
||||||
res.json({
|
res.json({
|
||||||
success: true,
|
success: true,
|
||||||
configured: false,
|
configured: false,
|
||||||
@@ -25,13 +23,13 @@ export function createConfigHandler() {
|
|||||||
|
|
||||||
// Check if the directory exists
|
// Check if the directory exists
|
||||||
try {
|
try {
|
||||||
const resolvedWorkspaceDir = path.resolve(workspaceDir);
|
const resolvedWorkspaceDir = path.resolve(allowedRootDirectory);
|
||||||
const stats = await fs.stat(resolvedWorkspaceDir);
|
const stats = await fs.stat(resolvedWorkspaceDir);
|
||||||
if (!stats.isDirectory()) {
|
if (!stats.isDirectory()) {
|
||||||
res.json({
|
res.json({
|
||||||
success: true,
|
success: true,
|
||||||
configured: false,
|
configured: false,
|
||||||
error: "Configured workspace directory is not a valid directory",
|
error: "ALLOWED_ROOT_DIRECTORY is not a valid directory",
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -48,7 +46,7 @@ export function createConfigHandler() {
|
|||||||
res.json({
|
res.json({
|
||||||
success: true,
|
success: true,
|
||||||
configured: false,
|
configured: false,
|
||||||
error: "Configured workspace directory path does not exist",
|
error: "ALLOWED_ROOT_DIRECTORY path does not exist",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@@ -11,19 +11,17 @@ import { getErrorMessage, logError } from "../common.js";
|
|||||||
export function createDirectoriesHandler() {
|
export function createDirectoriesHandler() {
|
||||||
return async (_req: Request, res: Response): Promise<void> => {
|
return async (_req: Request, res: Response): Promise<void> => {
|
||||||
try {
|
try {
|
||||||
// Prefer ALLOWED_ROOT_DIRECTORY, fall back to WORKSPACE_DIR for backward compatibility
|
|
||||||
const allowedRootDirectory = getAllowedRootDirectory();
|
const allowedRootDirectory = getAllowedRootDirectory();
|
||||||
const workspaceDir = process.env.WORKSPACE_DIR || allowedRootDirectory;
|
|
||||||
|
|
||||||
if (!workspaceDir) {
|
if (!allowedRootDirectory) {
|
||||||
res.status(400).json({
|
res.status(400).json({
|
||||||
success: false,
|
success: false,
|
||||||
error: "Workspace directory is not configured (set ALLOWED_ROOT_DIRECTORY or WORKSPACE_DIR)",
|
error: "ALLOWED_ROOT_DIRECTORY is not configured",
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const resolvedWorkspaceDir = path.resolve(workspaceDir);
|
const resolvedWorkspaceDir = path.resolve(allowedRootDirectory);
|
||||||
|
|
||||||
// Check if directory exists
|
// Check if directory exists
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -53,24 +53,10 @@ describe("security.ts", () => {
|
|||||||
expect(allowed).toContain(path.resolve("/data/dir"));
|
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 () => {
|
it("should handle empty ALLOWED_PROJECT_DIRS", async () => {
|
||||||
process.env.ALLOWED_PROJECT_DIRS = "";
|
process.env.ALLOWED_PROJECT_DIRS = "";
|
||||||
process.env.DATA_DIR = "/data";
|
process.env.DATA_DIR = "/data";
|
||||||
delete process.env.WORKSPACE_DIR;
|
delete process.env.ALLOWED_ROOT_DIRECTORY;
|
||||||
|
|
||||||
const { initAllowedPaths, getAllowedPaths } = await import(
|
const { initAllowedPaths, getAllowedPaths } = await import(
|
||||||
"@/lib/security.js"
|
"@/lib/security.js"
|
||||||
@@ -85,7 +71,7 @@ describe("security.ts", () => {
|
|||||||
it("should skip empty entries in comma list", async () => {
|
it("should skip empty entries in comma list", async () => {
|
||||||
process.env.ALLOWED_PROJECT_DIRS = "/path1,,/path2, ,/path3";
|
process.env.ALLOWED_PROJECT_DIRS = "/path1,,/path2, ,/path3";
|
||||||
process.env.DATA_DIR = "";
|
process.env.DATA_DIR = "";
|
||||||
delete process.env.WORKSPACE_DIR;
|
delete process.env.ALLOWED_ROOT_DIRECTORY;
|
||||||
|
|
||||||
const { initAllowedPaths, getAllowedPaths } = await import(
|
const { initAllowedPaths, getAllowedPaths } = await import(
|
||||||
"@/lib/security.js"
|
"@/lib/security.js"
|
||||||
@@ -152,7 +138,6 @@ describe("security.ts", () => {
|
|||||||
it("should allow all paths when no restrictions are configured", async () => {
|
it("should allow all paths when no restrictions are configured", async () => {
|
||||||
delete process.env.ALLOWED_PROJECT_DIRS;
|
delete process.env.ALLOWED_PROJECT_DIRS;
|
||||||
delete process.env.DATA_DIR;
|
delete process.env.DATA_DIR;
|
||||||
delete process.env.WORKSPACE_DIR;
|
|
||||||
delete process.env.ALLOWED_ROOT_DIRECTORY;
|
delete process.env.ALLOWED_ROOT_DIRECTORY;
|
||||||
|
|
||||||
const { initAllowedPaths, isPathAllowed } = await import(
|
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 () => {
|
it("should not throw error for any path when no restrictions are configured", async () => {
|
||||||
delete process.env.ALLOWED_PROJECT_DIRS;
|
delete process.env.ALLOWED_PROJECT_DIRS;
|
||||||
delete process.env.DATA_DIR;
|
delete process.env.DATA_DIR;
|
||||||
delete process.env.WORKSPACE_DIR;
|
|
||||||
delete process.env.ALLOWED_ROOT_DIRECTORY;
|
delete process.env.ALLOWED_ROOT_DIRECTORY;
|
||||||
|
|
||||||
const { initAllowedPaths, validatePath } = await import(
|
const { initAllowedPaths, validatePath } = await import(
|
||||||
|
|||||||
@@ -170,14 +170,14 @@ async function startServer(): Promise<void> {
|
|||||||
? path.join(process.resourcesPath, "server", "node_modules")
|
? path.join(process.resourcesPath, "server", "node_modules")
|
||||||
: path.join(__dirname, "../../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 {
|
try {
|
||||||
fs.mkdirSync(defaultWorkspaceDir, { recursive: true });
|
fs.mkdirSync(defaultRootDirectory, { recursive: true });
|
||||||
console.log("[Electron] Created workspace directory:", defaultWorkspaceDir);
|
console.log("[Electron] Created ALLOWED_ROOT_DIRECTORY:", defaultRootDirectory);
|
||||||
} catch (error) {
|
} 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<void> {
|
|||||||
PORT: SERVER_PORT.toString(),
|
PORT: SERVER_PORT.toString(),
|
||||||
DATA_DIR: app.getPath("userData"),
|
DATA_DIR: app.getPath("userData"),
|
||||||
NODE_PATH: serverNodeModules,
|
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...");
|
console.log("[Electron] Starting backend server...");
|
||||||
|
|||||||
Reference in New Issue
Block a user