











@@ -0,0 +1,146 @@
1+import { describe, expect, it } from "vitest";
2+import { getIMessageApprovalApprovers, imessageApprovalAuth } from "./approval-auth.js";
3+4+describe("imessageApprovalAuth", () => {
5+it("authorizes individual handles and ignores group/chat target entries", () => {
6+expect(
7+imessageApprovalAuth.authorizeActorAction({
8+cfg: { channels: { imessage: { allowFrom: ["+1 (555) 123-0000"] } } },
9+senderId: "+15551230000",
10+action: "approve",
11+approvalKind: "exec",
12+}),
13+).toEqual({ authorized: true });
14+15+expect(
16+getIMessageApprovalApprovers({
17+cfg: {
18+channels: {
19+imessage: {
20+allowFrom: ["chat_guid:iMessage;+;chat123", "chat_id:42"],
21+},
22+},
23+},
24+}),
25+).toEqual([]);
26+27+expect(
28+imessageApprovalAuth.authorizeActorAction({
29+cfg: { channels: { imessage: { allowFrom: ["+15551230000"] } } },
30+senderId: "+15551239999",
31+action: "approve",
32+approvalKind: "exec",
33+}),
34+).toEqual({
35+authorized: false,
36+reason: "❌ You are not authorized to approve exec requests on iMessage.",
37+});
38+});
39+40+it("authorizes lowercase-normalized email senders against canonical allowFrom", () => {
41+expect(
42+imessageApprovalAuth.authorizeActorAction({
43+cfg: { channels: { imessage: { allowFrom: ["Owner@Example.com"] } } },
44+senderId: "owner@example.com",
45+action: "approve",
46+approvalKind: "plugin",
47+}),
48+).toEqual({ authorized: true });
49+});
50+51+it("falls back to implicit same-chat authorization when no allowFrom is configured", () => {
52+expect(
53+getIMessageApprovalApprovers({
54+cfg: { channels: { imessage: { allowFrom: [] } } },
55+}),
56+).toEqual([]);
57+58+expect(
59+imessageApprovalAuth.authorizeActorAction({
60+cfg: { channels: { imessage: { allowFrom: [] } } },
61+senderId: "+15551230000",
62+action: "approve",
63+approvalKind: "exec",
64+}),
65+).toEqual({ authorized: true });
66+});
67+68+it("supports explicit wildcard approval approvers", () => {
69+expect(
70+imessageApprovalAuth.authorizeActorAction({
71+cfg: { channels: { imessage: { allowFrom: ["*"] } } },
72+senderId: "+15551230000",
73+action: "approve",
74+approvalKind: "plugin",
75+}),
76+).toEqual({ authorized: true });
77+});
78+79+it("strips imessage:/sms:/auto: service prefixes when normalizing approver entries", () => {
80+// The resolved approver list itself must contain the bare normalized
81+// handle — a previous bug rejected service-prefixed entries entirely,
82+// which silently fell back to the empty-approvers implicit-same-chat
83+// authorization and masked the regression. Assert the explicit list here
84+// so reaction resolution (which requires a non-empty approver list) works
85+// for service-prefixed allowFrom values too.
86+expect(
87+getIMessageApprovalApprovers({
88+cfg: { channels: { imessage: { allowFrom: ["imessage:+15551230000"] } } },
89+}),
90+).toEqual(["+15551230000"]);
91+expect(
92+getIMessageApprovalApprovers({
93+cfg: { channels: { imessage: { allowFrom: ["sms:+15551230001"] } } },
94+}),
95+).toEqual(["+15551230001"]);
96+expect(
97+getIMessageApprovalApprovers({
98+cfg: { channels: { imessage: { allowFrom: ["auto:Owner@Example.com"] } } },
99+}),
100+).toEqual(["owner@example.com"]);
101+102+// A sender that matches the normalized handle is explicitly authorized
103+// (not via the implicit same-chat fallback).
104+expect(
105+imessageApprovalAuth.authorizeActorAction({
106+cfg: { channels: { imessage: { allowFrom: ["imessage:+15551230000"] } } },
107+senderId: "+15551230000",
108+action: "approve",
109+approvalKind: "exec",
110+}),
111+).toEqual({ authorized: true });
112+113+// And a NON-matching sender is rejected — proving the entry was added
114+// to the approver list rather than collapsing to empty.
115+expect(
116+imessageApprovalAuth.authorizeActorAction({
117+cfg: { channels: { imessage: { allowFrom: ["imessage:+15551230000"] } } },
118+senderId: "+15559999999",
119+action: "approve",
120+approvalKind: "exec",
121+}),
122+).toEqual({
123+authorized: false,
124+reason: "❌ You are not authorized to approve exec requests on iMessage.",
125+});
126+});
127+128+it("rejects chat_id / chat_guid / chat_identifier as approver entries even with service prefixes", () => {
129+expect(
130+getIMessageApprovalApprovers({
131+cfg: {
132+channels: {
133+imessage: {
134+allowFrom: [
135+"chat_id:42",
136+"chat_guid:iMessage;+;chat42",
137+"chat_identifier:chat42@example.com",
138+"imessage:chat_id:43",
139+],
140+},
141+},
142+},
143+}),
144+).toEqual([]);
145+});
146+});
이 콘텐츠는 인셔셔RSS(RSS 리더)가 자동으로 집계한 것으로 읽기 참고용입니다. 원문 출처 — 저작권은 원저작자에게 있습니다.