security(zalouser): scope pairing-store auth to accountId

This commit is contained in:
bmendonca3
2026-02-25 09:20:55 -07:00
committed by Peter Steinberger
parent 4b4ea5df8b
commit 6aa20e91d9

View File

@@ -0,0 +1,99 @@
import type { OpenClawConfig, PluginRuntime, RuntimeEnv } from "openclaw/plugin-sdk";
import { describe, expect, it, vi } from "vitest";
import { __testing } from "./monitor.js";
import { setZalouserRuntime } from "./runtime.js";
import type { ResolvedZalouserAccount, ZcaMessage } from "./types.js";
const sendMessageZalouserMock = vi.hoisted(() => vi.fn(async () => {}));
vi.mock("./send.js", () => ({
sendMessageZalouser: sendMessageZalouserMock,
}));
describe("zalouser monitor pairing account scoping", () => {
it("scopes DM pairing-store reads and pairing requests to accountId", async () => {
const readAllowFromStore = vi.fn(
async (_channel: string, _env?: NodeJS.ProcessEnv, accountId?: string) =>
accountId === "beta" ? [] : ["attacker"],
);
const upsertPairingRequest = vi.fn(async () => ({ code: "PAIRME88", created: true }));
setZalouserRuntime({
logging: {
shouldLogVerbose: () => false,
},
channel: {
pairing: {
readAllowFromStore,
upsertPairingRequest,
buildPairingReply: vi.fn(() => "pairing reply"),
},
commands: {
shouldComputeCommandAuthorized: vi.fn(() => false),
resolveCommandAuthorizedFromAuthorizers: vi.fn(() => false),
isControlCommandMessage: vi.fn(() => false),
},
},
} as unknown as PluginRuntime);
const account: ResolvedZalouserAccount = {
accountId: "beta",
enabled: true,
profile: "beta",
authenticated: true,
config: {
dmPolicy: "pairing",
allowFrom: [],
},
};
const config: OpenClawConfig = {
channels: {
zalouser: {
accounts: {
alpha: { dmPolicy: "pairing", allowFrom: [] },
beta: { dmPolicy: "pairing", allowFrom: [] },
},
},
},
};
const message: ZcaMessage = {
threadId: "chat-1",
msgId: "msg-1",
type: 1,
content: "hello",
timestamp: Math.floor(Date.now() / 1000),
metadata: {
isGroup: false,
fromId: "attacker",
senderName: "Attacker",
},
};
const runtime: RuntimeEnv = {
log: vi.fn(),
error: vi.fn(),
exit: ((code: number): never => {
throw new Error(`exit ${code}`);
}) as RuntimeEnv["exit"],
};
await __testing.processMessage({
message,
account,
config,
runtime,
});
expect(readAllowFromStore).toHaveBeenCalledWith("zalouser", undefined, "beta");
expect(upsertPairingRequest).toHaveBeenCalledWith(
expect.objectContaining({
channel: "zalouser",
id: "attacker",
accountId: "beta",
}),
);
expect(sendMessageZalouserMock).toHaveBeenCalled();
});
});