Files
openclaw/src/agents/sandbox-media-paths.ts
2026-03-15 20:28:19 -07:00

81 lines
2.3 KiB
TypeScript

import path from "node:path";
import { assertSandboxPath } from "./sandbox-paths.js";
import type { SandboxFsBridge } from "./sandbox/fs-bridge.js";
export type SandboxedBridgeMediaPathConfig = {
root: string;
bridge: SandboxFsBridge;
workspaceOnly?: boolean;
};
export function createSandboxBridgeReadFile(params: {
sandbox: Pick<SandboxedBridgeMediaPathConfig, "root" | "bridge">;
}): (filePath: string) => Promise<Buffer> {
return async (filePath: string) =>
await params.sandbox.bridge.readFile({
filePath,
cwd: params.sandbox.root,
});
}
export async function resolveSandboxedBridgeMediaPath(params: {
sandbox: SandboxedBridgeMediaPathConfig;
mediaPath: string;
inboundFallbackDir?: string;
}): Promise<{ resolved: string; rewrittenFrom?: string }> {
const normalizeFileUrl = (rawPath: string) =>
rawPath.startsWith("file://") ? rawPath.slice("file://".length) : rawPath;
const filePath = normalizeFileUrl(params.mediaPath);
const enforceWorkspaceBoundary = async (hostPath: string) => {
if (!params.sandbox.workspaceOnly) {
return;
}
await assertSandboxPath({
filePath: hostPath,
cwd: params.sandbox.root,
root: params.sandbox.root,
});
};
const resolveDirect = () =>
params.sandbox.bridge.resolvePath({
filePath,
cwd: params.sandbox.root,
});
try {
const resolved = resolveDirect();
if (resolved.hostPath) {
await enforceWorkspaceBoundary(resolved.hostPath);
}
return { resolved: resolved.hostPath ?? resolved.containerPath };
} catch (err) {
const fallbackDir = params.inboundFallbackDir?.trim();
if (!fallbackDir) {
throw err;
}
const fallbackPath = path.join(fallbackDir, path.basename(filePath));
try {
const stat = await params.sandbox.bridge.stat({
filePath: fallbackPath,
cwd: params.sandbox.root,
});
if (!stat) {
throw err;
}
} catch {
throw err;
}
const resolvedFallback = params.sandbox.bridge.resolvePath({
filePath: fallbackPath,
cwd: params.sandbox.root,
});
if (resolvedFallback.hostPath) {
await enforceWorkspaceBoundary(resolvedFallback.hostPath);
}
return {
resolved: resolvedFallback.hostPath ?? resolvedFallback.containerPath,
rewrittenFrom: filePath,
};
}
}