mirror of
https://github.com/AutoMaker-Org/automaker.git
synced 2026-01-31 06:42:03 +00:00
refactor: replace fs with secureFs for improved file handling
This commit updates various modules to utilize the secure file system operations from the secureFs module instead of the native fs module. Key changes include: - Replaced fs imports with secureFs in multiple route handlers and services to enhance security and consistency in file operations. - Added centralized validation for working directories in the sdk-options module to ensure all AI model invocations are secure. These changes aim to improve the security and maintainability of file handling across the application.
This commit is contained in:
@@ -3,15 +3,15 @@
|
||||
*/
|
||||
|
||||
import { createLogger } from '@automaker/utils';
|
||||
import fs from "fs/promises";
|
||||
import path from "path";
|
||||
import { exec } from "child_process";
|
||||
import { promisify } from "util";
|
||||
import { secureFs } from '@automaker/platform';
|
||||
import path from 'path';
|
||||
import { exec } from 'child_process';
|
||||
import { promisify } from 'util';
|
||||
import { BINARY_EXTENSIONS, type FileStatus } from './types.js';
|
||||
import { isGitRepo, parseGitStatus } from './status.js';
|
||||
|
||||
const execAsync = promisify(exec);
|
||||
const logger = createLogger("GitUtils");
|
||||
const logger = createLogger('GitUtils');
|
||||
|
||||
// Max file size for generating synthetic diffs (1MB)
|
||||
const MAX_SYNTHETIC_DIFF_SIZE = 1024 * 1024;
|
||||
@@ -45,7 +45,7 @@ Binary file ${relativePath} added
|
||||
}
|
||||
|
||||
// Get file stats to check size
|
||||
const stats = await fs.stat(fullPath);
|
||||
const stats = await secureFs.stat(fullPath);
|
||||
if (stats.size > MAX_SYNTHETIC_DIFF_SIZE) {
|
||||
const sizeKB = Math.round(stats.size / 1024);
|
||||
return `diff --git a/${relativePath} b/${relativePath}
|
||||
@@ -59,18 +59,18 @@ index 0000000..0000000
|
||||
}
|
||||
|
||||
// Read file content
|
||||
const content = await fs.readFile(fullPath, "utf-8");
|
||||
const hasTrailingNewline = content.endsWith("\n");
|
||||
const lines = content.split("\n");
|
||||
const content = (await secureFs.readFile(fullPath, 'utf-8')) as string;
|
||||
const hasTrailingNewline = content.endsWith('\n');
|
||||
const lines = content.split('\n');
|
||||
|
||||
// Remove trailing empty line if the file ends with newline
|
||||
if (lines.length > 0 && lines.at(-1) === "") {
|
||||
if (lines.length > 0 && lines.at(-1) === '') {
|
||||
lines.pop();
|
||||
}
|
||||
|
||||
// Generate diff format
|
||||
const lineCount = lines.length;
|
||||
const addedLines = lines.map(line => `+${line}`).join("\n");
|
||||
const addedLines = lines.map((line) => `+${line}`).join('\n');
|
||||
|
||||
let diff = `diff --git a/${relativePath} b/${relativePath}
|
||||
new file mode 100644
|
||||
@@ -82,10 +82,10 @@ ${addedLines}`;
|
||||
|
||||
// Add "No newline at end of file" indicator if needed
|
||||
if (!hasTrailingNewline && content.length > 0) {
|
||||
diff += "\n\\ No newline at end of file";
|
||||
diff += '\n\\ No newline at end of file';
|
||||
}
|
||||
|
||||
return diff + "\n";
|
||||
return diff + '\n';
|
||||
} catch (error) {
|
||||
// Log the error for debugging
|
||||
logger.error(`Failed to generate synthetic diff for ${fullPath}:`, error);
|
||||
@@ -110,7 +110,7 @@ export async function appendUntrackedFileDiffs(
|
||||
files: Array<{ status: string; path: string }>
|
||||
): Promise<string> {
|
||||
// Find untracked files (status "?")
|
||||
const untrackedFiles = files.filter(f => f.status === "?");
|
||||
const untrackedFiles = files.filter((f) => f.status === '?');
|
||||
|
||||
if (untrackedFiles.length === 0) {
|
||||
return existingDiff;
|
||||
@@ -118,11 +118,11 @@ export async function appendUntrackedFileDiffs(
|
||||
|
||||
// Generate synthetic diffs for each untracked file
|
||||
const syntheticDiffs = await Promise.all(
|
||||
untrackedFiles.map(f => generateSyntheticDiffForNewFile(basePath, f.path))
|
||||
untrackedFiles.map((f) => generateSyntheticDiffForNewFile(basePath, f.path))
|
||||
);
|
||||
|
||||
// Combine existing diff with synthetic diffs
|
||||
const combinedDiff = existingDiff + syntheticDiffs.join("");
|
||||
const combinedDiff = existingDiff + syntheticDiffs.join('');
|
||||
|
||||
return combinedDiff;
|
||||
}
|
||||
@@ -133,25 +133,39 @@ export async function appendUntrackedFileDiffs(
|
||||
*/
|
||||
export async function listAllFilesInDirectory(
|
||||
basePath: string,
|
||||
relativePath: string = ""
|
||||
relativePath: string = ''
|
||||
): Promise<string[]> {
|
||||
const files: string[] = [];
|
||||
const fullPath = path.join(basePath, relativePath);
|
||||
|
||||
// Directories to skip
|
||||
const skipDirs = new Set([
|
||||
"node_modules", ".git", ".automaker", "dist", "build",
|
||||
".next", ".nuxt", "__pycache__", ".cache", "coverage",
|
||||
".venv", "venv", "target", "vendor", ".gradle",
|
||||
"out", "tmp", ".tmp"
|
||||
'node_modules',
|
||||
'.git',
|
||||
'.automaker',
|
||||
'dist',
|
||||
'build',
|
||||
'.next',
|
||||
'.nuxt',
|
||||
'__pycache__',
|
||||
'.cache',
|
||||
'coverage',
|
||||
'.venv',
|
||||
'venv',
|
||||
'target',
|
||||
'vendor',
|
||||
'.gradle',
|
||||
'out',
|
||||
'tmp',
|
||||
'.tmp',
|
||||
]);
|
||||
|
||||
try {
|
||||
const entries = await fs.readdir(fullPath, { withFileTypes: true });
|
||||
const entries = await secureFs.readdir(fullPath, { withFileTypes: true });
|
||||
|
||||
for (const entry of entries) {
|
||||
// Skip hidden files/folders (except we want to allow some)
|
||||
if (entry.name.startsWith(".") && entry.name !== ".env") {
|
||||
if (entry.name.startsWith('.') && entry.name !== '.env') {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -183,19 +197,19 @@ export async function generateDiffsForNonGitDirectory(
|
||||
): Promise<{ diff: string; files: FileStatus[] }> {
|
||||
const allFiles = await listAllFilesInDirectory(basePath);
|
||||
|
||||
const files: FileStatus[] = allFiles.map(filePath => ({
|
||||
status: "?",
|
||||
const files: FileStatus[] = allFiles.map((filePath) => ({
|
||||
status: '?',
|
||||
path: filePath,
|
||||
statusText: "New",
|
||||
statusText: 'New',
|
||||
}));
|
||||
|
||||
// Generate synthetic diffs for all files
|
||||
const syntheticDiffs = await Promise.all(
|
||||
files.map(f => generateSyntheticDiffForNewFile(basePath, f.path))
|
||||
files.map((f) => generateSyntheticDiffForNewFile(basePath, f.path))
|
||||
);
|
||||
|
||||
return {
|
||||
diff: syntheticDiffs.join(""),
|
||||
diff: syntheticDiffs.join(''),
|
||||
files,
|
||||
};
|
||||
}
|
||||
@@ -221,11 +235,11 @@ export async function getGitRepositoryDiffs(
|
||||
}
|
||||
|
||||
// Get git diff and status
|
||||
const { stdout: diff } = await execAsync("git diff HEAD", {
|
||||
const { stdout: diff } = await execAsync('git diff HEAD', {
|
||||
cwd: repoPath,
|
||||
maxBuffer: 10 * 1024 * 1024,
|
||||
});
|
||||
const { stdout: status } = await execAsync("git status --porcelain", {
|
||||
const { stdout: status } = await execAsync('git status --porcelain', {
|
||||
cwd: repoPath,
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user