Skip to content

Commit a62d55b

Browse files
committed
test(discord): cover DM command decision flow
1 parent 75596e9 commit a62d55b

File tree

2 files changed

+130
-0
lines changed

2 files changed

+130
-0
lines changed

src/discord/monitor/dm-command-auth.test.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,22 @@ describe("resolveDiscordDmCommandAccess", () => {
3838
expect(result.commandAuthorized).toBe(true);
3939
});
4040

41+
it("keeps command auth enabled for open DMs when configured allowlist does not match", async () => {
42+
const result = await resolveDiscordDmCommandAccess({
43+
accountId: "default",
44+
dmPolicy: "open",
45+
configuredAllowFrom: ["discord:999"],
46+
sender,
47+
allowNameMatching: false,
48+
useAccessGroups: true,
49+
readStoreAllowFrom: async () => [],
50+
});
51+
52+
expect(result.decision).toBe("allow");
53+
expect(result.allowMatch.allowed).toBe(false);
54+
expect(result.commandAuthorized).toBe(true);
55+
});
56+
4157
it("returns pairing decision and unauthorized command auth for unknown senders", async () => {
4258
const result = await resolveDiscordDmCommandAccess({
4359
accountId: "default",
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
import { describe, expect, it, vi } from "vitest";
2+
import type { DiscordDmCommandAccess } from "./dm-command-auth.js";
3+
import { handleDiscordDmCommandDecision } from "./dm-command-decision.js";
4+
5+
function buildDmAccess(overrides: Partial<DiscordDmCommandAccess>): DiscordDmCommandAccess {
6+
return {
7+
decision: "allow",
8+
reason: "ok",
9+
commandAuthorized: true,
10+
allowMatch: { allowed: true, matchKey: "123", matchSource: "id" },
11+
...overrides,
12+
};
13+
}
14+
15+
describe("handleDiscordDmCommandDecision", () => {
16+
it("returns true for allowed DM access", async () => {
17+
const onPairingCreated = vi.fn(async () => {});
18+
const onUnauthorized = vi.fn(async () => {});
19+
const upsertPairingRequest = vi.fn(async () => ({ code: "PAIR-1", created: true }));
20+
21+
const allowed = await handleDiscordDmCommandDecision({
22+
dmAccess: buildDmAccess({ decision: "allow" }),
23+
accountId: "default",
24+
sender: { id: "123", tag: "alice#0001", name: "alice" },
25+
onPairingCreated,
26+
onUnauthorized,
27+
upsertPairingRequest,
28+
});
29+
30+
expect(allowed).toBe(true);
31+
expect(upsertPairingRequest).not.toHaveBeenCalled();
32+
expect(onPairingCreated).not.toHaveBeenCalled();
33+
expect(onUnauthorized).not.toHaveBeenCalled();
34+
});
35+
36+
it("creates pairing reply for new pairing requests", async () => {
37+
const onPairingCreated = vi.fn(async () => {});
38+
const onUnauthorized = vi.fn(async () => {});
39+
const upsertPairingRequest = vi.fn(async () => ({ code: "PAIR-1", created: true }));
40+
41+
const allowed = await handleDiscordDmCommandDecision({
42+
dmAccess: buildDmAccess({
43+
decision: "pairing",
44+
commandAuthorized: false,
45+
allowMatch: { allowed: false },
46+
}),
47+
accountId: "default",
48+
sender: { id: "123", tag: "alice#0001", name: "alice" },
49+
onPairingCreated,
50+
onUnauthorized,
51+
upsertPairingRequest,
52+
});
53+
54+
expect(allowed).toBe(false);
55+
expect(upsertPairingRequest).toHaveBeenCalledWith({
56+
channel: "discord",
57+
id: "123",
58+
accountId: "default",
59+
meta: {
60+
tag: "alice#0001",
61+
name: "alice",
62+
},
63+
});
64+
expect(onPairingCreated).toHaveBeenCalledWith("PAIR-1");
65+
expect(onUnauthorized).not.toHaveBeenCalled();
66+
});
67+
68+
it("skips pairing reply when pairing request already exists", async () => {
69+
const onPairingCreated = vi.fn(async () => {});
70+
const onUnauthorized = vi.fn(async () => {});
71+
const upsertPairingRequest = vi.fn(async () => ({ code: "PAIR-1", created: false }));
72+
73+
const allowed = await handleDiscordDmCommandDecision({
74+
dmAccess: buildDmAccess({
75+
decision: "pairing",
76+
commandAuthorized: false,
77+
allowMatch: { allowed: false },
78+
}),
79+
accountId: "default",
80+
sender: { id: "123", tag: "alice#0001", name: "alice" },
81+
onPairingCreated,
82+
onUnauthorized,
83+
upsertPairingRequest,
84+
});
85+
86+
expect(allowed).toBe(false);
87+
expect(onPairingCreated).not.toHaveBeenCalled();
88+
expect(onUnauthorized).not.toHaveBeenCalled();
89+
});
90+
91+
it("runs unauthorized handler for blocked DM access", async () => {
92+
const onPairingCreated = vi.fn(async () => {});
93+
const onUnauthorized = vi.fn(async () => {});
94+
const upsertPairingRequest = vi.fn(async () => ({ code: "PAIR-1", created: true }));
95+
96+
const allowed = await handleDiscordDmCommandDecision({
97+
dmAccess: buildDmAccess({
98+
decision: "block",
99+
commandAuthorized: false,
100+
allowMatch: { allowed: false },
101+
}),
102+
accountId: "default",
103+
sender: { id: "123", tag: "alice#0001", name: "alice" },
104+
onPairingCreated,
105+
onUnauthorized,
106+
upsertPairingRequest,
107+
});
108+
109+
expect(allowed).toBe(false);
110+
expect(onUnauthorized).toHaveBeenCalledTimes(1);
111+
expect(upsertPairingRequest).not.toHaveBeenCalled();
112+
expect(onPairingCreated).not.toHaveBeenCalled();
113+
});
114+
});

0 commit comments

Comments
 (0)