mirror of
https://github.com/AutoMaker-Org/automaker.git
synced 2026-02-02 20:43:36 +00:00
This commit replaces direct file system operations with a secure file system adapter to enhance security by enforcing path validation. The changes include:
- Replaced `fs` imports with `secureFs` in various services and utilities.
- Updated file operations in `agent-service`, `auto-mode-service`, `feature-loader`, and `settings-service` to use the secure file system methods.
- Ensured that all file I/O operations are validated against the ALLOWED_ROOT_DIRECTORY.
This refactor aims to prevent unauthorized file access and improve overall security posture.
Tests: All unit tests passing.
🤖 Generated with Claude Code
68 lines
2.0 KiB
TypeScript
68 lines
2.0 KiB
TypeScript
/**
|
|
* File system utilities that handle symlinks safely
|
|
*/
|
|
|
|
import * as secureFs from "./secure-fs.js";
|
|
import path from "path";
|
|
|
|
/**
|
|
* Create a directory, handling symlinks safely to avoid ELOOP errors.
|
|
* If the path already exists as a directory or symlink, returns success.
|
|
*/
|
|
export async function mkdirSafe(dirPath: string): Promise<void> {
|
|
const resolvedPath = path.resolve(dirPath);
|
|
|
|
// Check if path already exists using lstat (doesn't follow symlinks)
|
|
try {
|
|
const stats = await secureFs.lstat(resolvedPath);
|
|
// Path exists - if it's a directory or symlink, consider it success
|
|
if (stats.isDirectory() || stats.isSymbolicLink()) {
|
|
return;
|
|
}
|
|
// It's a file - can't create directory
|
|
throw new Error(`Path exists and is not a directory: ${resolvedPath}`);
|
|
} catch (error: any) {
|
|
// ENOENT means path doesn't exist - we should create it
|
|
if (error.code !== "ENOENT") {
|
|
// Some other error (could be ELOOP in parent path)
|
|
// If it's ELOOP, the path involves symlinks - don't try to create
|
|
if (error.code === "ELOOP") {
|
|
console.warn(`[fs-utils] Symlink loop detected at ${resolvedPath}, skipping mkdir`);
|
|
return;
|
|
}
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
// Path doesn't exist, create it
|
|
try {
|
|
await secureFs.mkdir(resolvedPath, { recursive: true });
|
|
} catch (error: any) {
|
|
// Handle race conditions and symlink issues
|
|
if (error.code === "EEXIST" || error.code === "ELOOP") {
|
|
return;
|
|
}
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Check if a path exists, handling symlinks safely.
|
|
* Returns true if the path exists as a file, directory, or symlink.
|
|
*/
|
|
export async function existsSafe(filePath: string): Promise<boolean> {
|
|
try {
|
|
await secureFs.lstat(filePath);
|
|
return true;
|
|
} catch (error: any) {
|
|
if (error.code === "ENOENT") {
|
|
return false;
|
|
}
|
|
// ELOOP or other errors - path exists but is problematic
|
|
if (error.code === "ELOOP") {
|
|
return true; // Symlink exists, even if looping
|
|
}
|
|
throw error;
|
|
}
|
|
}
|