fix: add workspace media-root regression coverage

This commit is contained in:
Gustavo Madeira Santana
2026-02-15 10:13:16 -05:00
parent 36ca0e5c13
commit 042d8d79fc
2 changed files with 36 additions and 0 deletions

View File

@@ -125,6 +125,7 @@ Docs: https://docs.openclaw.ai
- Sandbox/Prompts: show the sandbox container workdir as the prompt working directory and clarify host-path usage for file tools, preventing host-path `exec` failures in sandbox sessions. (#16790) Thanks @carrotRakko.
- Media/Security: allow local media reads from OpenClaw state `workspace/` and `sandboxes/` roots by default so generated workspace media can be delivered without unsafe global path bypasses. (#15541) Thanks @lanceji.
- Media/Security: harden local media allowlist bypasses by requiring an explicit `readFile` override when callers mark paths as validated, and reject filesystem-root `localRoots` entries. (#16739)
- Media/Security: allow local media reads from default per-agent state workspaces (`workspace-<agentId>`) so non-default agents can send workspace-local attachments. (#17136) Thanks @MisterGuy420.
- Discord/Security: harden voice message media loading (SSRF + allowed-local-root checks) so tool-supplied paths/URLs cannot be used to probe internal URLs or read arbitrary local files.
- Security/BlueBubbles: require explicit `mediaLocalRoots` allowlists for local outbound media path reads to prevent local file disclosure. (#16322) Thanks @mbelinky.
- Security/BlueBubbles: reject ambiguous shared-path webhook routing when multiple webhook targets match the same guid/password.

View File

@@ -1,3 +1,4 @@
import fsSync, { type Dirent } from "node:fs";
import fs from "node:fs/promises";
import os from "node:os";
import path from "node:path";
@@ -371,4 +372,38 @@ describe("local media root guard", () => {
}),
);
});
it("allows default OpenClaw state per-agent workspace-* roots", async () => {
const { STATE_DIR } = await import("../config/paths.js");
const readFile = vi.fn(async () => Buffer.from("generated-media"));
const readdirSpy = vi.spyOn(fsSync, "readdirSync").mockReturnValue([
{
name: "workspace-clawdy",
isDirectory: () => true,
} as unknown as Dirent,
{
name: "workspace-main",
isDirectory: () => true,
} as unknown as Dirent,
{
name: "workspace-file",
isDirectory: () => false,
} as unknown as Dirent,
]);
try {
await expect(
loadWebMedia(path.join(STATE_DIR, "workspace-clawdy", "tmp", "render.bin"), {
maxBytes: 1024 * 1024,
readFile,
}),
).resolves.toEqual(
expect.objectContaining({
kind: "unknown",
}),
);
} finally {
readdirSpy.mockRestore();
}
});
});