mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-27 03:37:50 +00:00
146 lines
4.3 KiB
TypeScript
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");
|
|
});
|
|
});
|