mirror of https://github.com/openclaw/openclaw.git
202 lines
6.2 KiB
TypeScript
202 lines
6.2 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import type { DiscordExecApprovalConfig } from "../../config/types.discord.js";
|
|
import {
|
|
buildExecApprovalCustomId,
|
|
parseExecApprovalData,
|
|
type ExecApprovalRequest,
|
|
DiscordExecApprovalHandler,
|
|
} from "./exec-approvals.js";
|
|
|
|
describe("buildExecApprovalCustomId", () => {
|
|
it("encodes approval id and action", () => {
|
|
const customId = buildExecApprovalCustomId("abc-123", "allow-once");
|
|
expect(customId).toBe("execapproval:id=abc-123;action=allow-once");
|
|
});
|
|
|
|
it("encodes special characters in approval id", () => {
|
|
const customId = buildExecApprovalCustomId("abc=123;test", "deny");
|
|
expect(customId).toBe("execapproval:id=abc%3D123%3Btest;action=deny");
|
|
});
|
|
});
|
|
|
|
describe("parseExecApprovalData", () => {
|
|
it("parses valid data", () => {
|
|
const result = parseExecApprovalData({ id: "abc-123", action: "allow-once" });
|
|
expect(result).toEqual({ approvalId: "abc-123", action: "allow-once" });
|
|
});
|
|
|
|
it("parses encoded data", () => {
|
|
const result = parseExecApprovalData({
|
|
id: "abc%3D123%3Btest",
|
|
action: "allow-always",
|
|
});
|
|
expect(result).toEqual({ approvalId: "abc=123;test", action: "allow-always" });
|
|
});
|
|
|
|
it("rejects invalid action", () => {
|
|
const result = parseExecApprovalData({ id: "abc-123", action: "invalid" });
|
|
expect(result).toBeNull();
|
|
});
|
|
|
|
it("rejects missing id", () => {
|
|
const result = parseExecApprovalData({ action: "deny" });
|
|
expect(result).toBeNull();
|
|
});
|
|
|
|
it("rejects missing action", () => {
|
|
const result = parseExecApprovalData({ id: "abc-123" });
|
|
expect(result).toBeNull();
|
|
});
|
|
|
|
it("rejects null/undefined input", () => {
|
|
// oxlint-disable-next-line typescript/no-explicit-any
|
|
expect(parseExecApprovalData(null as any)).toBeNull();
|
|
// oxlint-disable-next-line typescript/no-explicit-any
|
|
expect(parseExecApprovalData(undefined as any)).toBeNull();
|
|
});
|
|
|
|
it("accepts all valid actions", () => {
|
|
expect(parseExecApprovalData({ id: "x", action: "allow-once" })?.action).toBe("allow-once");
|
|
expect(parseExecApprovalData({ id: "x", action: "allow-always" })?.action).toBe("allow-always");
|
|
expect(parseExecApprovalData({ id: "x", action: "deny" })?.action).toBe("deny");
|
|
});
|
|
});
|
|
|
|
describe("roundtrip encoding", () => {
|
|
it("encodes and decodes correctly", () => {
|
|
const approvalId = "test-approval-with=special;chars&more";
|
|
const action = "allow-always" as const;
|
|
const customId = buildExecApprovalCustomId(approvalId, action);
|
|
|
|
// Parse the key=value pairs from the custom ID
|
|
const parts = customId.split(";");
|
|
const data: Record<string, string> = {};
|
|
for (const part of parts) {
|
|
const match = part.match(/^([^:]+:)?([^=]+)=(.+)$/);
|
|
if (match) {
|
|
data[match[2]] = match[3];
|
|
}
|
|
}
|
|
|
|
const result = parseExecApprovalData(data);
|
|
expect(result).toEqual({ approvalId, action });
|
|
});
|
|
});
|
|
|
|
describe("DiscordExecApprovalHandler.shouldHandle", () => {
|
|
function createHandler(config: DiscordExecApprovalConfig) {
|
|
return new DiscordExecApprovalHandler({
|
|
token: "test-token",
|
|
accountId: "default",
|
|
config,
|
|
cfg: {},
|
|
});
|
|
}
|
|
|
|
function createRequest(
|
|
overrides: Partial<ExecApprovalRequest["request"]> = {},
|
|
): ExecApprovalRequest {
|
|
return {
|
|
id: "test-id",
|
|
request: {
|
|
command: "echo hello",
|
|
cwd: "/home/user",
|
|
host: "gateway",
|
|
agentId: "test-agent",
|
|
sessionKey: "agent:test-agent:discord:123",
|
|
...overrides,
|
|
},
|
|
createdAtMs: Date.now(),
|
|
expiresAtMs: Date.now() + 60000,
|
|
};
|
|
}
|
|
|
|
it("returns false when disabled", () => {
|
|
const handler = createHandler({ enabled: false, approvers: ["123"] });
|
|
expect(handler.shouldHandle(createRequest())).toBe(false);
|
|
});
|
|
|
|
it("returns false when no approvers", () => {
|
|
const handler = createHandler({ enabled: true, approvers: [] });
|
|
expect(handler.shouldHandle(createRequest())).toBe(false);
|
|
});
|
|
|
|
it("returns true with minimal config", () => {
|
|
const handler = createHandler({ enabled: true, approvers: ["123"] });
|
|
expect(handler.shouldHandle(createRequest())).toBe(true);
|
|
});
|
|
|
|
it("filters by agent ID", () => {
|
|
const handler = createHandler({
|
|
enabled: true,
|
|
approvers: ["123"],
|
|
agentFilter: ["allowed-agent"],
|
|
});
|
|
expect(handler.shouldHandle(createRequest({ agentId: "allowed-agent" }))).toBe(true);
|
|
expect(handler.shouldHandle(createRequest({ agentId: "other-agent" }))).toBe(false);
|
|
expect(handler.shouldHandle(createRequest({ agentId: null }))).toBe(false);
|
|
});
|
|
|
|
it("filters by session key substring", () => {
|
|
const handler = createHandler({
|
|
enabled: true,
|
|
approvers: ["123"],
|
|
sessionFilter: ["discord"],
|
|
});
|
|
expect(handler.shouldHandle(createRequest({ sessionKey: "agent:test:discord:123" }))).toBe(
|
|
true,
|
|
);
|
|
expect(handler.shouldHandle(createRequest({ sessionKey: "agent:test:telegram:123" }))).toBe(
|
|
false,
|
|
);
|
|
expect(handler.shouldHandle(createRequest({ sessionKey: null }))).toBe(false);
|
|
});
|
|
|
|
it("filters by session key regex", () => {
|
|
const handler = createHandler({
|
|
enabled: true,
|
|
approvers: ["123"],
|
|
sessionFilter: ["^agent:.*:discord:"],
|
|
});
|
|
expect(handler.shouldHandle(createRequest({ sessionKey: "agent:test:discord:123" }))).toBe(
|
|
true,
|
|
);
|
|
expect(handler.shouldHandle(createRequest({ sessionKey: "other:test:discord:123" }))).toBe(
|
|
false,
|
|
);
|
|
});
|
|
|
|
it("combines agent and session filters", () => {
|
|
const handler = createHandler({
|
|
enabled: true,
|
|
approvers: ["123"],
|
|
agentFilter: ["my-agent"],
|
|
sessionFilter: ["discord"],
|
|
});
|
|
expect(
|
|
handler.shouldHandle(
|
|
createRequest({
|
|
agentId: "my-agent",
|
|
sessionKey: "agent:my-agent:discord:123",
|
|
}),
|
|
),
|
|
).toBe(true);
|
|
expect(
|
|
handler.shouldHandle(
|
|
createRequest({
|
|
agentId: "other-agent",
|
|
sessionKey: "agent:other:discord:123",
|
|
}),
|
|
),
|
|
).toBe(false);
|
|
expect(
|
|
handler.shouldHandle(
|
|
createRequest({
|
|
agentId: "my-agent",
|
|
sessionKey: "agent:my-agent:telegram:123",
|
|
}),
|
|
),
|
|
).toBe(false);
|
|
});
|
|
});
|