Spracherkennung für: .ts vermutete Sprache: Unknown {[0] [0] [0]} [Methode: Schwerpunktbildung, einfache Gewichte, sechs Dimensionen]
import fs from "node:fs/promises";
import path from "node:path";
import { describe, expect, it } from "vitest";
import {
createSandbox,
createSandboxFsBridge,
createSeededSandboxFsBridge,
getScriptsFromCalls,
installFsBridgeTestHarness,
mockedExecDockerRaw,
mockedOpenBoundaryFile,
withTempDir,
} from "./fs-bridge.test-helpers.js";
describe("sandbox fs bridge shell compatibility", () => {
installFsBridgeTestHarness();
it("uses POSIX-safe shell prologue in all bridge commands", async () => {
await withTempDir("openclaw-fs-bridge-shell-", async (stateDir) => {
const workspaceDir = path.join(stateDir, "workspace");
await fs.mkdir(workspaceDir, { recursive: true });
await fs.writeFile(path.join(workspaceDir, "a.txt"), "hello");
await fs.writeFile(path.join(workspaceDir, "b.txt"), "bye");
const bridge = createSandboxFsBridge({
sandbox: createSandbox({
workspaceDir,
agentWorkspaceDir: workspaceDir,
}),
});
await bridge.readFile({ filePath: "a.txt" });
await bridge.writeFile({ filePath: "b.txt", data: "hello" });
await bridge.mkdirp({ filePath: "nested" });
await bridge.remove({ filePath: "b.txt" });
await bridge.rename({ from: "a.txt", to: "c.txt" });
await bridge.stat({ filePath: "c.txt" });
expect(mockedExecDockerRaw).toHaveBeenCalled();
const scripts = getScriptsFromCalls();
const executables = mockedExecDockerRaw.mock.calls.map(([args]) => args[3] ?? "");
expect(executables.every((shell) => shell === "sh")).toBe(true);
expect(scripts.every((script) => /set -eu[;\n]/.test(script))).toBe(true);
expect(scripts.some((script) => script.includes("pipefail"))).toBe(false);
});
});
it("path canonicalization recheck script is valid POSIX sh", async () => {
const bridge = createSandboxFsBridge({ sandbox: createSandbox() });
await bridge.writeFile({ filePath: "b.txt", data: "hello" });
const scripts = getScriptsFromCalls();
const canonicalScript = scripts.find((script) => script.includes("allow_final"));
expect(canonicalScript).toBeDefined();
expect(canonicalScript).not.toMatch(/\bdo;/);
expect(canonicalScript).toMatch(/\bdo\n\s*parent=/);
});
it("reads inbound media-style filenames with triple-dash ids", async () => {
await withTempDir("openclaw-fs-bridge-read-", async (stateDir) => {
const workspaceDir = path.join(stateDir, "workspace");
const inboundPath = "media/inbound/file_1095---f00a04a2-99a0-4d98-99b0-dfe61c5a4198.ogg";
await fs.mkdir(path.join(workspaceDir, "media", "inbound"), { recursive: true });
await fs.writeFile(path.join(workspaceDir, inboundPath), "voice");
const bridge = createSandboxFsBridge({
sandbox: createSandbox({
workspaceDir,
agentWorkspaceDir: workspaceDir,
}),
});
await expect(bridge.readFile({ filePath: inboundPath })).resolves.toEqual(
Buffer.from("voice"),
);
expect(mockedExecDockerRaw).not.toHaveBeenCalled();
});
});
it("resolves dash-leading basenames into absolute container paths", async () => {
await withTempDir("openclaw-fs-bridge-read-", async (stateDir) => {
const workspaceDir = path.join(stateDir, "workspace");
await fs.mkdir(workspaceDir, { recursive: true });
await fs.writeFile(path.join(workspaceDir, "--leading.txt"), "dash");
const bridge = createSandboxFsBridge({
sandbox: createSandbox({
workspaceDir,
agentWorkspaceDir: workspaceDir,
}),
});
await expect(bridge.readFile({ filePath: "--leading.txt" })).resolves.toEqual(
Buffer.from("dash"),
);
expect(mockedExecDockerRaw).not.toHaveBeenCalled();
});
});
it("resolves bind-mounted absolute container paths for reads", async () => {
await withTempDir("openclaw-fs-bridge-bind-read-", async (stateDir) => {
const workspaceDir = path.join(stateDir, "workspace");
const bindRoot = path.join(stateDir, "workspace-two");
await fs.mkdir(workspaceDir, { recursive: true });
await fs.mkdir(bindRoot, { recursive: true });
await fs.writeFile(path.join(bindRoot, "README.md"), "bind-read");
const sandbox = createSandbox({
workspaceDir,
agentWorkspaceDir: workspaceDir,
docker: {
...createSandbox().docker,
binds: [`${bindRoot}:/workspace-two:ro`],
},
});
const bridge = createSandboxFsBridge({ sandbox });
await expect(bridge.readFile({ filePath: "/workspace-two/README.md" })).resolves.toEqual(
Buffer.from("bind-read"),
);
expect(mockedExecDockerRaw).not.toHaveBeenCalled();
});
});
it("writes via temp file + atomic rename (never direct truncation)", async () => {
const bridge = createSandboxFsBridge({ sandbox: createSandbox() });
await bridge.writeFile({ filePath: "b.txt", data: "hello" });
const scripts = getScriptsFromCalls();
expect(scripts.some((script) => script.includes("python3 - \"$@\" <<'PY'"))).toBe(false);
expect(
scripts.some((script) => script.includes('exec "$python_cmd" -c "$python_script" "$@"')),
).toBe(true);
expect(scripts.some((script) => script.includes('cat >"$1"'))).toBe(false);
expect(scripts.some((script) => script.includes('cat >"$tmp"'))).toBe(false);
expect(scripts.some((script) => script.includes("os.replace("))).toBe(true);
});
it("routes mkdirp, remove, and rename through the pinned mutation helper", async () => {
await withTempDir("openclaw-fs-bridge-shell-write-", async (stateDir) => {
const { bridge } = await createSeededSandboxFsBridge(stateDir, {
rootFileName: "a.txt",
});
await bridge.mkdirp({ filePath: "nested" });
await bridge.remove({ filePath: "nested/file.txt" });
await bridge.rename({ from: "a.txt", to: "nested/b.txt" });
const scripts = getScriptsFromCalls();
expect(scripts.filter((script) => script.includes("operation = sys.argv[1]")).length).toBe(3);
expect(scripts.some((script) => script.includes('mkdir -p -- "$2"'))).toBe(false);
expect(scripts.some((script) => script.includes('rm -f -- "$2"'))).toBe(false);
expect(scripts.some((script) => script.includes('mv -- "$3" "$2/$4"'))).toBe(false);
});
});
it("re-validates target before the pinned write helper runs", async () => {
mockedOpenBoundaryFile
.mockImplementationOnce(async () => ({ ok: false, reason: "path" }))
.mockImplementationOnce(async () => ({
ok: false,
reason: "validation",
error: new Error("Hardlinked path is not allowed"),
}));
const bridge = createSandboxFsBridge({ sandbox: createSandbox() });
await expect(bridge.writeFile({ filePath: "b.txt", data: "hello" })).rejects.toThrow(
/hardlinked path/i,
);
const scripts = getScriptsFromCalls();
expect(scripts.some((script) => script.includes("os.replace("))).toBe(false);
});
});
¤ Dauer der Verarbeitung: 0.16 Sekunden
(vorverarbeitet am 2026-04-27)
¤
*© Formatika GbR, Deutschland
|
|