mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-08 08:41:23 +00:00
fix(agents): map container workdir paths in workspace guard
Co-authored-by: Explorer1092 <32663226+Explorer1092@users.noreply.github.com>
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
import path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import type { AgentToolResult } from "@mariozechner/pi-agent-core";
|
||||
import { createEditTool, createReadTool, createWriteTool } from "@mariozechner/pi-coding-agent";
|
||||
import { detectMime } from "../media/mime.js";
|
||||
@@ -548,6 +550,57 @@ export function wrapToolParamNormalization(
|
||||
}
|
||||
|
||||
export function wrapToolWorkspaceRootGuard(tool: AnyAgentTool, root: string): AnyAgentTool {
|
||||
return wrapToolWorkspaceRootGuardWithOptions(tool, root);
|
||||
}
|
||||
|
||||
function mapContainerPathToWorkspaceRoot(params: {
|
||||
filePath: string;
|
||||
root: string;
|
||||
containerWorkdir?: string;
|
||||
}): string {
|
||||
const containerWorkdir = params.containerWorkdir?.trim();
|
||||
if (!containerWorkdir) {
|
||||
return params.filePath;
|
||||
}
|
||||
const normalizedWorkdir = containerWorkdir.replace(/\\/g, "/").replace(/\/+$/, "");
|
||||
if (!normalizedWorkdir.startsWith("/")) {
|
||||
return params.filePath;
|
||||
}
|
||||
if (!normalizedWorkdir) {
|
||||
return params.filePath;
|
||||
}
|
||||
|
||||
let candidate = params.filePath;
|
||||
if (/^file:\/\//i.test(candidate)) {
|
||||
try {
|
||||
candidate = fileURLToPath(candidate);
|
||||
} catch {
|
||||
return params.filePath;
|
||||
}
|
||||
}
|
||||
|
||||
const normalizedCandidate = candidate.replace(/\\/g, "/");
|
||||
if (normalizedCandidate === normalizedWorkdir) {
|
||||
return path.resolve(params.root);
|
||||
}
|
||||
const prefix = `${normalizedWorkdir}/`;
|
||||
if (!normalizedCandidate.startsWith(prefix)) {
|
||||
return candidate;
|
||||
}
|
||||
const relative = normalizedCandidate.slice(prefix.length);
|
||||
if (!relative) {
|
||||
return path.resolve(params.root);
|
||||
}
|
||||
return path.resolve(params.root, ...relative.split("/").filter(Boolean));
|
||||
}
|
||||
|
||||
export function wrapToolWorkspaceRootGuardWithOptions(
|
||||
tool: AnyAgentTool,
|
||||
root: string,
|
||||
options?: {
|
||||
containerWorkdir?: string;
|
||||
},
|
||||
): AnyAgentTool {
|
||||
return {
|
||||
...tool,
|
||||
execute: async (toolCallId, args, signal, onUpdate) => {
|
||||
@@ -557,7 +610,12 @@ export function wrapToolWorkspaceRootGuard(tool: AnyAgentTool, root: string): An
|
||||
(args && typeof args === "object" ? (args as Record<string, unknown>) : undefined);
|
||||
const filePath = record?.path;
|
||||
if (typeof filePath === "string" && filePath.trim()) {
|
||||
await assertSandboxPath({ filePath, cwd: root, root });
|
||||
const sandboxPath = mapContainerPathToWorkspaceRoot({
|
||||
filePath,
|
||||
root,
|
||||
containerWorkdir: options?.containerWorkdir,
|
||||
});
|
||||
await assertSandboxPath({ filePath: sandboxPath, cwd: root, root });
|
||||
}
|
||||
return tool.execute(toolCallId, normalized ?? args, signal, onUpdate);
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user