mirror of
https://github.com/openclaw/openclaw.git
synced 2026-06-06 22:02:57 +00:00
Use read-only Telegram account inspection for prompt-time channel actions, inline buttons, and reaction guidance so unresolved SecretRef tokens retain configured non-secret behavior before runtime snapshot hydration. Match runtime Telegram account lookup for normalized config keys and multi-account fallback guards, while keeping sends/actions on the existing strict credential resolution path. Fixes #75433. Co-authored-by: Shubhankar Tripathy <reach2shubhankar@gmail.com>
143 lines
5.0 KiB
TypeScript
143 lines
5.0 KiB
TypeScript
import type { OpenClawConfig } from "openclaw/plugin-sdk/config-types";
|
|
import { describe, expect, it } from "vitest";
|
|
import { buildTelegramInteractiveButtons } from "./button-types.js";
|
|
import { describeTelegramInteractiveButtonBehavior } from "./button-types.test-helpers.js";
|
|
import {
|
|
isTelegramInlineButtonsEnabled,
|
|
resolveTelegramInlineButtonsScope,
|
|
resolveTelegramTargetChatType,
|
|
} from "./inline-buttons.js";
|
|
|
|
describe("resolveTelegramTargetChatType", () => {
|
|
it("returns 'direct' for positive numeric IDs", () => {
|
|
expect(resolveTelegramTargetChatType("5232990709")).toBe("direct");
|
|
expect(resolveTelegramTargetChatType("123456789")).toBe("direct");
|
|
});
|
|
|
|
it("returns 'group' for negative numeric IDs", () => {
|
|
expect(resolveTelegramTargetChatType("-123456789")).toBe("group");
|
|
expect(resolveTelegramTargetChatType("-1001234567890")).toBe("group");
|
|
});
|
|
|
|
it("handles telegram: prefix from normalizeTelegramMessagingTarget", () => {
|
|
expect(resolveTelegramTargetChatType("telegram:5232990709")).toBe("direct");
|
|
expect(resolveTelegramTargetChatType("telegram:-123456789")).toBe("group");
|
|
expect(resolveTelegramTargetChatType("TELEGRAM:5232990709")).toBe("direct");
|
|
});
|
|
|
|
it("handles tg/group prefixes and topic suffixes", () => {
|
|
expect(resolveTelegramTargetChatType("tg:5232990709")).toBe("direct");
|
|
expect(resolveTelegramTargetChatType("telegram:group:-1001234567890")).toBe("group");
|
|
expect(resolveTelegramTargetChatType("telegram:group:-1001234567890:topic:456")).toBe("group");
|
|
expect(resolveTelegramTargetChatType("-1001234567890:456")).toBe("group");
|
|
});
|
|
|
|
it("returns 'unknown' for usernames", () => {
|
|
expect(resolveTelegramTargetChatType("@username")).toBe("unknown");
|
|
expect(resolveTelegramTargetChatType("telegram:@username")).toBe("unknown");
|
|
});
|
|
|
|
it("returns 'unknown' for empty strings", () => {
|
|
expect(resolveTelegramTargetChatType("")).toBe("unknown");
|
|
expect(resolveTelegramTargetChatType(" ")).toBe("unknown");
|
|
});
|
|
});
|
|
|
|
describeTelegramInteractiveButtonBehavior();
|
|
|
|
describe("buildTelegramInteractiveButtons callback rewrites", () => {
|
|
it("drops shared buttons whose callback data exceeds Telegram's limit", () => {
|
|
expect(
|
|
buildTelegramInteractiveButtons({
|
|
blocks: [
|
|
{
|
|
type: "buttons",
|
|
buttons: [
|
|
{ label: "Keep", value: "keep" },
|
|
{ label: "Too long", value: `a${"b".repeat(64)}` },
|
|
],
|
|
},
|
|
],
|
|
}),
|
|
).toEqual([[{ text: "Keep", callback_data: "keep", style: undefined }]]);
|
|
});
|
|
|
|
it("rewrites /approve allow-always callbacks to always so plugin IDs fit Telegram limits", () => {
|
|
const pluginApprovalId = `plugin:${"a".repeat(36)}`;
|
|
expect(
|
|
buildTelegramInteractiveButtons({
|
|
blocks: [
|
|
{
|
|
type: "buttons",
|
|
buttons: [
|
|
{
|
|
label: "Allow Always",
|
|
value: `/approve ${pluginApprovalId} allow-always`,
|
|
style: "primary",
|
|
},
|
|
],
|
|
},
|
|
],
|
|
}),
|
|
).toEqual([
|
|
[
|
|
{
|
|
text: "Allow Always",
|
|
callback_data: `/approve ${pluginApprovalId} always`,
|
|
style: "primary",
|
|
},
|
|
],
|
|
]);
|
|
});
|
|
});
|
|
|
|
describe("resolveTelegramInlineButtonsScope (#75433 SecretRef tolerance)", () => {
|
|
// Embedded prompt prep calls this from raw config before the active runtime
|
|
// snapshot has resolved channel credentials. Read-only account inspection
|
|
// keeps SecretRef-backed config readable without resolving the token.
|
|
it("preserves the default inline-buttons scope when botToken is an unresolved SecretRef", () => {
|
|
const cfg = {
|
|
channels: {
|
|
telegram: {
|
|
botToken: { source: "exec", provider: "default", id: "telegram-token" },
|
|
},
|
|
},
|
|
} as unknown as OpenClawConfig;
|
|
|
|
expect(resolveTelegramInlineButtonsScope({ cfg })).toBe("allowlist");
|
|
expect(isTelegramInlineButtonsEnabled({ cfg })).toBe(true);
|
|
});
|
|
|
|
it('preserves configured "off" when botToken is an unresolved SecretRef', () => {
|
|
const cfg = {
|
|
channels: {
|
|
telegram: {
|
|
botToken: { source: "exec", provider: "default", id: "telegram-token" },
|
|
capabilities: { inlineButtons: "off" },
|
|
},
|
|
},
|
|
} as unknown as OpenClawConfig;
|
|
|
|
expect(resolveTelegramInlineButtonsScope({ cfg })).toBe("off");
|
|
expect(isTelegramInlineButtonsEnabled({ cfg })).toBe(false);
|
|
});
|
|
|
|
it("preserves scoped account inline-buttons config when the token is an unresolved SecretRef", () => {
|
|
const cfg = {
|
|
channels: {
|
|
telegram: {
|
|
accounts: {
|
|
ops: {
|
|
botToken: { source: "exec", provider: "default", id: "telegram-ops" },
|
|
capabilities: { inlineButtons: "all" },
|
|
},
|
|
},
|
|
},
|
|
},
|
|
} as unknown as OpenClawConfig;
|
|
|
|
expect(resolveTelegramInlineButtonsScope({ cfg, accountId: "ops" })).toBe("all");
|
|
expect(isTelegramInlineButtonsEnabled({ cfg, accountId: "ops" })).toBe(true);
|
|
});
|
|
});
|