Files
openclaw/src/media/read-capability.test.ts
2026-05-09 08:49:54 +01:00

146 lines
4.3 KiB
TypeScript

import { afterEach, describe, expect, it, vi } from "vitest";
import type { OpenClawConfig } from "../config/types.js";
import { resolveAgentScopedOutboundMediaAccess } from "./read-capability.js";
vi.mock("../channels/plugins/index.js", () => ({
getChannelPlugin: () => undefined,
}));
describe("resolveAgentScopedOutboundMediaAccess", () => {
afterEach(() => {
vi.unstubAllEnvs();
});
it("preserves caller-provided workspaceDir from mediaAccess", () => {
const result = resolveAgentScopedOutboundMediaAccess({
cfg: {} as OpenClawConfig,
mediaAccess: { workspaceDir: "/tmp/media-workspace" },
});
expect(Object.keys(result)).toStrictEqual(["localRoots", "readFile", "workspaceDir"]);
expect(Array.isArray(result.localRoots)).toBe(true);
expect(result.localRoots?.length).toBeGreaterThan(0);
expect(typeof result.readFile).toBe("function");
expect(result.workspaceDir).toBe("/tmp/media-workspace");
});
it("prefers explicit workspaceDir over mediaAccess.workspaceDir", () => {
const result = resolveAgentScopedOutboundMediaAccess({
cfg: {} as OpenClawConfig,
workspaceDir: "/tmp/explicit-workspace",
mediaAccess: { workspaceDir: "/tmp/media-workspace" },
});
expect(Object.keys(result)).toStrictEqual(["localRoots", "readFile", "workspaceDir"]);
expect(Array.isArray(result.localRoots)).toBe(true);
expect(result.localRoots?.length).toBeGreaterThan(0);
expect(typeof result.readFile).toBe("function");
expect(result.workspaceDir).toBe("/tmp/explicit-workspace");
});
it("does not enable host reads when sender group policy denies read", () => {
const cfg: OpenClawConfig = {
tools: {
allow: ["read"],
},
channels: {
requestchat: {
groups: {
ops: {
toolsBySender: {
"id:attacker": {
deny: ["read"],
},
},
},
},
},
},
};
const result = resolveAgentScopedOutboundMediaAccess({
cfg,
sessionKey: "agent:main:requestchat:group:ops",
mediaSources: ["/Users/peter/Pictures/photo.png"],
// Production call sites set messageProvider: undefined when sessionKey is present;
// resolveGroupToolPolicy derives channel from the session key instead.
requesterSenderId: "attacker",
});
expect(result.readFile).toBeUndefined();
expect(result.localRoots).not.toContain("/Users/peter/Pictures");
});
it("keeps host reads enabled when sender group policy allows read", () => {
const cfg: OpenClawConfig = {
tools: {
allow: ["read"],
},
channels: {
requestchat: {
groups: {
ops: {
toolsBySender: {
"id:trusted-user": {
allow: ["read"],
},
},
},
},
},
},
};
const result = resolveAgentScopedOutboundMediaAccess({
cfg,
sessionKey: "agent:main:requestchat:group:ops",
mediaSources: ["/Users/peter/Pictures/photo.png"],
requesterSenderId: "trusted-user",
});
expect(result.readFile).toBeTypeOf("function");
expect(result.localRoots).toContain("/Users/peter/Pictures");
});
it("keeps host reads enabled when no group policy applies", () => {
const result = resolveAgentScopedOutboundMediaAccess({
cfg: {
tools: {
allow: ["read"],
},
} as OpenClawConfig,
messageProvider: "requestchat",
requesterSenderId: "trusted-user",
});
expect(result.readFile).toBeTypeOf("function");
});
it("keeps host reads enabled for DM sender when no group context exists", () => {
const result = resolveAgentScopedOutboundMediaAccess({
cfg: {
tools: {
allow: ["read"],
},
channels: {
requestchat: {
groups: {
ops: {
toolsBySender: {
"id:dm-sender": {
deny: ["read"],
},
},
},
},
},
},
} as OpenClawConfig,
messageProvider: "requestchat",
requesterSenderId: "dm-sender",
});
expect(result.readFile).toBeTypeOf("function");
});
});