fix(feishu): bound approval card expiry · openclaw/openclaw@19f22b5
steipete
·
2026-05-30
·
via Recent Commits to openclaw:main
| Original file line number | Diff line number | Diff line change |
|---|
@@ -270,6 +270,45 @@ describe("Feishu Card Action Handler", () => {
|
270 | 270 | expect(handleFeishuMessage).not.toHaveBeenCalled(); |
271 | 271 | }); |
272 | 272 | |
| 273 | +it("does not open approval cards when the expiry would exceed a valid Date", async () => { |
| 274 | +vi.useFakeTimers(); |
| 275 | +vi.setSystemTime(new Date(8_640_000_000_000_000)); |
| 276 | +try { |
| 277 | +const event: FeishuCardActionEvent = { |
| 278 | +operator: { open_id: "u123", user_id: "uid1", union_id: "un1" }, |
| 279 | +token: "tok4-boundary", |
| 280 | +action: { |
| 281 | +value: createFeishuCardInteractionEnvelope({ |
| 282 | +k: "meta", |
| 283 | +a: FEISHU_APPROVAL_REQUEST_ACTION, |
| 284 | +m: { |
| 285 | +command: "/new", |
| 286 | +prompt: "Start a fresh session?", |
| 287 | +}, |
| 288 | +c: { |
| 289 | +u: "u123", |
| 290 | +h: "chat1", |
| 291 | +t: "group", |
| 292 | +s: "agent:codex:feishu:chat:chat1", |
| 293 | +e: 8_640_000_000_000_000, |
| 294 | +}, |
| 295 | +}), |
| 296 | +tag: "button", |
| 297 | +}, |
| 298 | +context: { open_id: "u123", user_id: "uid1", chat_id: "chat1" }, |
| 299 | +}; |
| 300 | + |
| 301 | +await handleFeishuCardAction({ cfg, event, runtime, accountId: "main" }); |
| 302 | + |
| 303 | +expect(sendCardFeishuMock).not.toHaveBeenCalled(); |
| 304 | +const sendMessage = sendMessageCall(); |
| 305 | +expect(sendMessage.to).toBe("chat:chat1"); |
| 306 | +expect(String(sendMessage.text)).toContain("payload is invalid"); |
| 307 | +} finally { |
| 308 | +vi.useRealTimers(); |
| 309 | +} |
| 310 | +}); |
| 311 | + |
273 | 312 | it("runs approval confirmation through the normal message path", async () => { |
274 | 313 | const event = createStructuredQuickActionEvent({ |
275 | 314 | token: "tok5", |
|
| Original file line number | Diff line number | Diff line change |
|---|
@@ -217,6 +217,13 @@ function sanitizeLogValue(v: string): string {
|
217 | 217 | return v.replace(/[\r\n]/g, " ").slice(0, 500); |
218 | 218 | } |
219 | 219 | |
| 220 | +function resolveFeishuApprovalCardExpiresAt(nowRaw = Date.now()): number | undefined { |
| 221 | +const now = asDateTimestampMs(nowRaw); |
| 222 | +return now === undefined |
| 223 | + ? undefined |
| 224 | + : resolveExpiresAtMsFromDurationMs(FEISHU_APPROVAL_CARD_TTL_MS, { nowMs: now }); |
| 225 | +} |
| 226 | + |
220 | 227 | function cacheResolvedCardActionChatType( |
221 | 228 | cacheKey: string, |
222 | 229 | value: "p2p" | "group", |
@@ -373,6 +380,17 @@ export async function handleFeishuCardAction(params: {
|
373 | 380 | typeof envelope.m?.prompt === "string" && envelope.m.prompt.trim() |
374 | 381 | ? envelope.m.prompt |
375 | 382 | : `Run \`${command}\` in this Feishu conversation?`; |
| 383 | +const expiresAt = resolveFeishuApprovalCardExpiresAt(); |
| 384 | +if (expiresAt === undefined) { |
| 385 | +await sendInvalidInteractionNotice({ |
| 386 | + cfg, |
| 387 | + event, |
| 388 | +reason: "malformed", |
| 389 | + accountId, |
| 390 | +}); |
| 391 | +completeFeishuCardActionToken({ token: event.token, accountId: account.accountId }); |
| 392 | +return; |
| 393 | +} |
376 | 394 | await sendCardFeishu({ |
377 | 395 | cfg, |
378 | 396 | to: resolveCallbackTarget(event), |
@@ -382,7 +400,7 @@ export async function handleFeishuCardAction(params: {
|
382 | 400 | command, |
383 | 401 | prompt, |
384 | 402 | sessionKey: envelope.c?.s, |
385 | | -expiresAt: Date.now() + FEISHU_APPROVAL_CARD_TTL_MS, |
| 403 | + expiresAt, |
386 | 404 | chatType: await resolveCardActionChatType({ |
387 | 405 | event, |
388 | 406 | account, |
|
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。