From d5e59621a7cab2b306285d2f98c69acf8998a2c7 Mon Sep 17 00:00:00 2001 From: Ayaan Zaidi Date: Sun, 29 Mar 2026 10:44:27 +0530 Subject: [PATCH] fix: keep telegram plugin fallback explicit (#45911) (thanks @suboss87) --- src/auto-reply/reply/commands-approve.ts | 10 +++++++++- src/auto-reply/reply/commands.test.ts | 24 ++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/src/auto-reply/reply/commands-approve.ts b/src/auto-reply/reply/commands-approve.ts index 7395d5ae102..35183879f7b 100644 --- a/src/auto-reply/reply/commands-approve.ts +++ b/src/auto-reply/reply/commands-approve.ts @@ -132,6 +132,7 @@ export const handleApproveCommand: CommandHandler = async (params, allowTextComm const isPluginId = parsed.id.startsWith("plugin:"); let discordExecApprovalDeniedReply: { shouldContinue: false; reply: { text: string } } | null = null; + let isTelegramExplicitApprover = false; if (params.command.channel === "telegram") { const telegramApproverContext = { @@ -139,6 +140,7 @@ export const handleApproveCommand: CommandHandler = async (params, allowTextComm accountId: params.ctx.AccountId, senderId: params.command.senderId, }; + isTelegramExplicitApprover = isTelegramExecApprovalApprover(telegramApproverContext); if (!isPluginId && !isTelegramExecApprovalAuthorizedSender(telegramApproverContext)) { return { @@ -147,7 +149,7 @@ export const handleApproveCommand: CommandHandler = async (params, allowTextComm }; } - if (isPluginId && !isTelegramExecApprovalApprover(telegramApproverContext)) { + if (isPluginId && !isTelegramExplicitApprover) { return { shouldContinue: false, reply: { text: "❌ You are not authorized to approve plugin requests on Telegram." }, @@ -248,6 +250,12 @@ export const handleApproveCommand: CommandHandler = async (params, allowTextComm await callApprovalMethod("exec.approval.resolve"); } catch (err) { if (isApprovalNotFoundError(err)) { + if (params.command.channel === "telegram" && !isTelegramExplicitApprover) { + return { + shouldContinue: false, + reply: { text: `❌ Failed to submit approval: ${String(err)}` }, + }; + } try { await callApprovalMethod("plugin.approval.resolve"); } catch (pluginErr) { diff --git a/src/auto-reply/reply/commands.test.ts b/src/auto-reply/reply/commands.test.ts index cf3aa8e19f0..d3f1eaf3b6b 100644 --- a/src/auto-reply/reply/commands.test.ts +++ b/src/auto-reply/reply/commands.test.ts @@ -742,6 +742,30 @@ describe("/approve command", () => { expect(callGatewayMock).toHaveBeenCalledTimes(0); }); + it("does not fall back to legacy plugin approvals for Telegram target recipients", async () => { + const cfg = createTelegramTargetApproveCfg(); + const params = buildParams("/approve legacy-plugin-123 allow-once", cfg, { + Provider: "telegram", + Surface: "telegram", + SenderId: "123", + }); + + callGatewayMock.mockRejectedValueOnce( + gatewayError("unknown or expired approval id", "APPROVAL_NOT_FOUND"), + ); + + const result = await handleCommands(params); + expect(result.shouldContinue).toBe(false); + expect(result.reply?.text).toContain("unknown or expired approval id"); + expect(callGatewayMock).toHaveBeenCalledTimes(1); + expect(callGatewayMock).toHaveBeenCalledWith( + expect.objectContaining({ + method: "exec.approval.resolve", + params: { id: "legacy-plugin-123", decision: "allow-once" }, + }), + ); + }); + it("enforces gateway approval scopes", async () => { const cfg = { commands: { text: true },