mirror of https://github.com/openclaw/openclaw.git
fix: honor Feishu comment user_id allowlists
This commit is contained in:
parent
6d3c59bd79
commit
a9dfeb0d62
|
|
@ -9,6 +9,7 @@ Docs: https://docs.openclaw.ai
|
|||
- Agents/compaction: resolve `agents.defaults.compaction.model` consistently for manual `/compact` and other context-engine compaction paths, so engine-owned compaction uses the configured override model across runtime entrypoints. (#56710) Thanks @oliviareid-svg
|
||||
- Channels/session routing: move provider-specific session conversation grammar into plugin-owned session-key surfaces, preserving Telegram topic routing and Feishu scoped inheritance across bootstrap, model override, restart, and tool-policy paths.
|
||||
- WhatsApp/reactions: add `reactionLevel` guidance for agent reactions. Thanks @mcaxtr.
|
||||
- Feishu/comments: add a dedicated Drive comment-event flow with comment-thread context resolution, in-thread replies, and `feishu_drive` comment actions for document collaboration workflows. (#58497) thanks @wittam-01.
|
||||
|
||||
### Fixes
|
||||
|
||||
|
|
|
|||
|
|
@ -67,6 +67,7 @@ describe("handleFeishuCommentEvent", () => {
|
|||
fileToken: "doc_token_1",
|
||||
fileType: "docx",
|
||||
senderId: "ou_sender",
|
||||
senderUserId: "on_sender_user",
|
||||
timestamp: "1774951528000",
|
||||
isMentioned: true,
|
||||
documentTitle: "Project review",
|
||||
|
|
@ -146,6 +147,58 @@ describe("handleFeishuCommentEvent", () => {
|
|||
expect(dispatchReplyFromConfig).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("allows comment senders matched by user_id allowlist entries", async () => {
|
||||
const runtime = createPluginRuntimeMock({
|
||||
channel: {
|
||||
pairing: {
|
||||
readAllowFromStore: vi.fn(async () => []),
|
||||
},
|
||||
routing: {
|
||||
resolveAgentRoute: vi.fn(() => buildResolvedRoute()),
|
||||
},
|
||||
reply: {
|
||||
dispatchReplyFromConfig: vi.fn(async () => ({
|
||||
queuedFinal: true,
|
||||
counts: { tool: 0, block: 0, final: 1 },
|
||||
})),
|
||||
withReplyDispatcher: vi.fn(async ({ run, onSettled }) => {
|
||||
try {
|
||||
return await run();
|
||||
} finally {
|
||||
await onSettled?.();
|
||||
}
|
||||
}),
|
||||
},
|
||||
},
|
||||
});
|
||||
setFeishuRuntime(runtime);
|
||||
|
||||
await handleFeishuCommentEvent({
|
||||
cfg: buildConfig({
|
||||
channels: {
|
||||
feishu: {
|
||||
enabled: true,
|
||||
dmPolicy: "allowlist",
|
||||
allowFrom: ["on_sender_user"],
|
||||
},
|
||||
},
|
||||
}),
|
||||
accountId: "default",
|
||||
event: { event_id: "evt_1" },
|
||||
botOpenId: "ou_bot",
|
||||
runtime: {
|
||||
log: vi.fn(),
|
||||
error: vi.fn(),
|
||||
} as never,
|
||||
});
|
||||
|
||||
const dispatchReplyFromConfig = runtime.channel.reply.dispatchReplyFromConfig as ReturnType<
|
||||
typeof vi.fn
|
||||
>;
|
||||
expect(dispatchReplyFromConfig).toHaveBeenCalledTimes(1);
|
||||
expect(replyCommentMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("issues a pairing challenge in the comment thread when dmPolicy=pairing", async () => {
|
||||
const runtime = createPluginRuntimeMock({
|
||||
channel: {
|
||||
|
|
|
|||
|
|
@ -93,6 +93,7 @@ export async function handleFeishuCommentEvent(
|
|||
const senderAllowed = resolveFeishuAllowlistMatch({
|
||||
allowFrom: effectiveDmAllowFrom,
|
||||
senderId: turn.senderId,
|
||||
senderIds: [turn.senderUserId],
|
||||
}).allowed;
|
||||
if (dmPolicy !== "open" && !senderAllowed) {
|
||||
if (dmPolicy === "pairing") {
|
||||
|
|
|
|||
|
|
@ -262,6 +262,29 @@ describe("resolveDriveCommentEventTurn", () => {
|
|||
expect(turn?.prompt).toContain("The system will automatically reply with your final answer");
|
||||
});
|
||||
|
||||
it("preserves sender user_id for downstream allowlist checks", async () => {
|
||||
const client = makeOpenApiClient({ includeTargetReplyInBatch: true });
|
||||
|
||||
const turn = await resolveDriveCommentEventTurn({
|
||||
cfg: buildMonitorConfig(),
|
||||
accountId: "default",
|
||||
event: makeDriveCommentEvent({
|
||||
notice_meta: {
|
||||
...makeDriveCommentEvent().notice_meta,
|
||||
from_user_id: {
|
||||
open_id: "ou_509d4d7ace4a9addec2312676ffcba9b",
|
||||
user_id: "on_comment_user_1",
|
||||
},
|
||||
},
|
||||
}),
|
||||
botOpenId: "ou_bot",
|
||||
createClient: () => client as never,
|
||||
});
|
||||
|
||||
expect(turn?.senderId).toBe("ou_509d4d7ace4a9addec2312676ffcba9b");
|
||||
expect(turn?.senderUserId).toBe("on_comment_user_1");
|
||||
});
|
||||
|
||||
it("falls back to the replies API to resolve add_reply text", async () => {
|
||||
const client = makeOpenApiClient({
|
||||
includeTargetReplyInBatch: false,
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@ export type ResolvedDriveCommentEventTurn = {
|
|||
fileToken: string;
|
||||
fileType: CommentFileType;
|
||||
senderId: string;
|
||||
senderUserId?: string;
|
||||
timestamp?: string;
|
||||
isMentioned?: boolean;
|
||||
documentTitle?: string;
|
||||
|
|
@ -443,6 +444,7 @@ async function resolveDriveCommentEventCore(params: ResolveDriveCommentEventPara
|
|||
fileToken: string;
|
||||
fileType: CommentFileType;
|
||||
senderId: string;
|
||||
senderUserId?: string;
|
||||
timestamp?: string;
|
||||
isMentioned?: boolean;
|
||||
context: {
|
||||
|
|
@ -469,6 +471,7 @@ async function resolveDriveCommentEventCore(params: ResolveDriveCommentEventPara
|
|||
const fileToken = event.notice_meta?.file_token?.trim();
|
||||
const fileType = normalizeCommentFileType(event.notice_meta?.file_type);
|
||||
const senderId = event.notice_meta?.from_user_id?.open_id?.trim();
|
||||
const senderUserId = event.notice_meta?.from_user_id?.user_id?.trim() || undefined;
|
||||
if (!eventId || !commentId || !noticeType || !fileToken || !fileType || !senderId) {
|
||||
logger?.(
|
||||
`feishu[${accountId}]: drive comment notice missing required fields event=${eventId ?? "unknown"} comment=${commentId ?? "unknown"}`,
|
||||
|
|
@ -513,6 +516,7 @@ async function resolveDriveCommentEventCore(params: ResolveDriveCommentEventPara
|
|||
fileToken,
|
||||
fileType,
|
||||
senderId,
|
||||
senderUserId,
|
||||
timestamp: event.timestamp,
|
||||
isMentioned: event.is_mentioned,
|
||||
context,
|
||||
|
|
@ -587,6 +591,7 @@ export async function resolveDriveCommentEventTurn(
|
|||
fileToken: resolved.fileToken,
|
||||
fileType: resolved.fileType,
|
||||
senderId: resolved.senderId,
|
||||
senderUserId: resolved.senderUserId,
|
||||
timestamp: resolved.timestamp,
|
||||
isMentioned: resolved.isMentioned,
|
||||
documentTitle: resolved.context.documentTitle,
|
||||
|
|
|
|||
Loading…
Reference in New Issue