import { spawn } from "child_process"; import { safeResolve } from "./safePaths"; export function safeExecuteCommand(repoRoot: string, command: string, args: string[], allowedCommands: Record): Promise<{ stdout: string; stderr: string; exitCode: number }> { return new Promise((resolve, reject) => { const rules = allowedCommands[command]; if (!rules) return reject(new Error("Command not allowed")); const isAllowed = rules.some((rule) => { const prefixMatches = rule.args.length <= args.length && rule.args.every((value, index) => args[index] === value); if (!prefixMatches) return false; return rule.allowExtraArgs ? true : rule.args.length === args.length; }); if (!isAllowed) return reject(new Error("Command arguments not allowed")); const resolvedRepoRoot = safeResolve(repoRoot, ""); const child = spawn(command, args, { cwd: resolvedRepoRoot, shell: false }); let stdout = ""; let stderr = ""; child.stdout.on("data", (data) => { stdout += data.toString(); }); child.stderr.on("data", (data) => { stderr += data.toString(); }); child.on("error", reject); child.on("close", (code) => { resolve({ stdout, stderr, exitCode: code }); }); }); }