mirror of https://github.com/openclaw/openclaw.git
test(googlechat): cover inbound access policy
This commit is contained in:
parent
fe867c2467
commit
2df229cf8d
|
|
@ -0,0 +1,233 @@
|
|||
import { describe, expect, it, vi } from "vitest";
|
||||
|
||||
const createChannelPairingController = vi.hoisted(() => vi.fn());
|
||||
const evaluateGroupRouteAccessForPolicy = vi.hoisted(() => vi.fn());
|
||||
const isDangerousNameMatchingEnabled = vi.hoisted(() => vi.fn());
|
||||
const resolveAllowlistProviderRuntimeGroupPolicy = vi.hoisted(() => vi.fn());
|
||||
const resolveDefaultGroupPolicy = vi.hoisted(() => vi.fn());
|
||||
const resolveDmGroupAccessWithLists = vi.hoisted(() => vi.fn());
|
||||
const resolveMentionGatingWithBypass = vi.hoisted(() => vi.fn());
|
||||
const resolveSenderScopedGroupPolicy = vi.hoisted(() => vi.fn());
|
||||
const warnMissingProviderGroupPolicyFallbackOnce = vi.hoisted(() => vi.fn());
|
||||
const sendGoogleChatMessage = vi.hoisted(() => vi.fn());
|
||||
|
||||
vi.mock("../runtime-api.js", () => ({
|
||||
GROUP_POLICY_BLOCKED_LABEL: { space: "space" },
|
||||
createChannelPairingController,
|
||||
evaluateGroupRouteAccessForPolicy,
|
||||
isDangerousNameMatchingEnabled,
|
||||
resolveAllowlistProviderRuntimeGroupPolicy,
|
||||
resolveDefaultGroupPolicy,
|
||||
resolveDmGroupAccessWithLists,
|
||||
resolveMentionGatingWithBypass,
|
||||
resolveSenderScopedGroupPolicy,
|
||||
warnMissingProviderGroupPolicyFallbackOnce,
|
||||
}));
|
||||
|
||||
vi.mock("./api.js", () => ({
|
||||
sendGoogleChatMessage,
|
||||
}));
|
||||
|
||||
function createCore() {
|
||||
return {
|
||||
channel: {
|
||||
commands: {
|
||||
shouldComputeCommandAuthorized: vi.fn(() => false),
|
||||
resolveCommandAuthorizedFromAuthorizers: vi.fn(() => false),
|
||||
shouldHandleTextCommands: vi.fn(() => false),
|
||||
isControlCommandMessage: vi.fn(() => false),
|
||||
},
|
||||
text: {
|
||||
hasControlCommand: vi.fn(() => false),
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function primeCommonDefaults() {
|
||||
isDangerousNameMatchingEnabled.mockReturnValue(false);
|
||||
resolveDefaultGroupPolicy.mockReturnValue("allowlist");
|
||||
resolveAllowlistProviderRuntimeGroupPolicy.mockReturnValue({
|
||||
groupPolicy: "allowlist",
|
||||
providerMissingFallbackApplied: false,
|
||||
});
|
||||
resolveSenderScopedGroupPolicy.mockImplementation(({ groupPolicy }) => groupPolicy);
|
||||
evaluateGroupRouteAccessForPolicy.mockReturnValue({
|
||||
allowed: true,
|
||||
});
|
||||
warnMissingProviderGroupPolicyFallbackOnce.mockReturnValue(undefined);
|
||||
}
|
||||
|
||||
describe("googlechat inbound access policy", () => {
|
||||
it("issues a pairing challenge for unauthorized DMs in pairing mode", async () => {
|
||||
primeCommonDefaults();
|
||||
const issueChallenge = vi.fn(async ({ onCreated, sendPairingReply }) => {
|
||||
onCreated?.();
|
||||
await sendPairingReply("pairing text");
|
||||
});
|
||||
createChannelPairingController.mockReturnValue({
|
||||
readAllowFromStore: vi.fn(async () => []),
|
||||
issueChallenge,
|
||||
});
|
||||
resolveDmGroupAccessWithLists.mockReturnValue({
|
||||
decision: "pairing",
|
||||
reason: "pairing_required",
|
||||
effectiveAllowFrom: [],
|
||||
effectiveGroupAllowFrom: [],
|
||||
});
|
||||
sendGoogleChatMessage.mockResolvedValue({ ok: true });
|
||||
|
||||
const { applyGoogleChatInboundAccessPolicy } = await import("./monitor-access.js");
|
||||
const statusSink = vi.fn();
|
||||
const logVerbose = vi.fn();
|
||||
|
||||
await expect(
|
||||
applyGoogleChatInboundAccessPolicy({
|
||||
account: {
|
||||
accountId: "default",
|
||||
config: {
|
||||
dm: { policy: "pairing" },
|
||||
},
|
||||
} as never,
|
||||
config: {
|
||||
channels: { googlechat: {} },
|
||||
} as never,
|
||||
core: createCore() as never,
|
||||
space: { name: "spaces/AAA", displayName: "DM" } as never,
|
||||
message: { annotations: [] } as never,
|
||||
isGroup: false,
|
||||
senderId: "users/abc",
|
||||
senderName: "Alice",
|
||||
senderEmail: "alice@example.com",
|
||||
rawBody: "hello",
|
||||
statusSink,
|
||||
logVerbose,
|
||||
}),
|
||||
).resolves.toEqual({ ok: false });
|
||||
|
||||
expect(issueChallenge).toHaveBeenCalledTimes(1);
|
||||
expect(sendGoogleChatMessage).toHaveBeenCalledWith({
|
||||
account: expect.anything(),
|
||||
space: "spaces/AAA",
|
||||
text: "pairing text",
|
||||
});
|
||||
expect(statusSink).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
lastOutboundAt: expect.any(Number),
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it("allows group traffic when sender and mention gates pass", async () => {
|
||||
primeCommonDefaults();
|
||||
createChannelPairingController.mockReturnValue({
|
||||
readAllowFromStore: vi.fn(async () => []),
|
||||
issueChallenge: vi.fn(),
|
||||
});
|
||||
resolveDmGroupAccessWithLists.mockReturnValue({
|
||||
decision: "allow",
|
||||
effectiveAllowFrom: [],
|
||||
effectiveGroupAllowFrom: ["users/alice"],
|
||||
});
|
||||
resolveMentionGatingWithBypass.mockReturnValue({
|
||||
shouldSkip: false,
|
||||
effectiveWasMentioned: true,
|
||||
});
|
||||
const core = createCore();
|
||||
core.channel.commands.shouldComputeCommandAuthorized.mockReturnValue(true);
|
||||
core.channel.commands.resolveCommandAuthorizedFromAuthorizers.mockReturnValue(true);
|
||||
|
||||
const { applyGoogleChatInboundAccessPolicy } = await import("./monitor-access.js");
|
||||
|
||||
await expect(
|
||||
applyGoogleChatInboundAccessPolicy({
|
||||
account: {
|
||||
accountId: "default",
|
||||
config: {
|
||||
botUser: "users/app-bot",
|
||||
groups: {
|
||||
"spaces/AAA": {
|
||||
users: ["users/alice"],
|
||||
requireMention: true,
|
||||
systemPrompt: " group prompt ",
|
||||
},
|
||||
},
|
||||
},
|
||||
} as never,
|
||||
config: {
|
||||
channels: { googlechat: {} },
|
||||
commands: { useAccessGroups: true },
|
||||
} as never,
|
||||
core: core as never,
|
||||
space: { name: "spaces/AAA", displayName: "Team Room" } as never,
|
||||
message: {
|
||||
annotations: [
|
||||
{
|
||||
type: "USER_MENTION",
|
||||
userMention: { user: { name: "users/app-bot" } },
|
||||
},
|
||||
],
|
||||
} as never,
|
||||
isGroup: true,
|
||||
senderId: "users/alice",
|
||||
senderName: "Alice",
|
||||
senderEmail: "alice@example.com",
|
||||
rawBody: "hello team",
|
||||
logVerbose: vi.fn(),
|
||||
}),
|
||||
).resolves.toEqual({
|
||||
ok: true,
|
||||
commandAuthorized: true,
|
||||
effectiveWasMentioned: true,
|
||||
groupSystemPrompt: "group prompt",
|
||||
});
|
||||
});
|
||||
|
||||
it("drops unauthorized group control commands", async () => {
|
||||
primeCommonDefaults();
|
||||
createChannelPairingController.mockReturnValue({
|
||||
readAllowFromStore: vi.fn(async () => []),
|
||||
issueChallenge: vi.fn(),
|
||||
});
|
||||
resolveDmGroupAccessWithLists.mockReturnValue({
|
||||
decision: "allow",
|
||||
effectiveAllowFrom: [],
|
||||
effectiveGroupAllowFrom: [],
|
||||
});
|
||||
resolveMentionGatingWithBypass.mockReturnValue({
|
||||
shouldSkip: false,
|
||||
effectiveWasMentioned: false,
|
||||
});
|
||||
const core = createCore();
|
||||
core.channel.commands.shouldComputeCommandAuthorized.mockReturnValue(true);
|
||||
core.channel.commands.resolveCommandAuthorizedFromAuthorizers.mockReturnValue(false);
|
||||
core.channel.commands.isControlCommandMessage.mockReturnValue(true);
|
||||
const logVerbose = vi.fn();
|
||||
|
||||
const { applyGoogleChatInboundAccessPolicy } = await import("./monitor-access.js");
|
||||
|
||||
await expect(
|
||||
applyGoogleChatInboundAccessPolicy({
|
||||
account: {
|
||||
accountId: "default",
|
||||
config: {},
|
||||
} as never,
|
||||
config: {
|
||||
channels: { googlechat: {} },
|
||||
commands: { useAccessGroups: true },
|
||||
} as never,
|
||||
core: core as never,
|
||||
space: { name: "spaces/AAA", displayName: "Team Room" } as never,
|
||||
message: { annotations: [] } as never,
|
||||
isGroup: true,
|
||||
senderId: "users/alice",
|
||||
senderName: "Alice",
|
||||
senderEmail: "alice@example.com",
|
||||
rawBody: "/admin",
|
||||
logVerbose,
|
||||
}),
|
||||
).resolves.toEqual({ ok: false });
|
||||
|
||||
expect(logVerbose).toHaveBeenCalledWith("googlechat: drop control command from users/alice");
|
||||
});
|
||||
});
|
||||
Loading…
Reference in New Issue