Skip to content

Telegram: stabilize pairing/session/forum routing and reply formatting tests#50155

Merged
joshavant merged 11 commits intomainfrom
feat/telegram-area2-stabilization
Mar 19, 2026
Merged

Telegram: stabilize pairing/session/forum routing and reply formatting tests#50155
joshavant merged 11 commits intomainfrom
feat/telegram-area2-stabilization

Conversation

@joshavant
Copy link
Copy Markdown
Contributor

@joshavant joshavant commented Mar 19, 2026

Summary

Describe the problem and fix in 2–5 bullets:

  • Problem: Telegram routing and test harness paths drifted during refactor, leaving fragile coverage and inconsistent behavior around pairing, session routing, and callback/reply flows.
  • Why it matters: This affected confidence in DM pairing enforcement, session/forum routing decisions, and reply-format dispatch behavior, and made CI stability worse.
  • What changed:
    • Pairing and routing deps were wired through TelegramBotDeps (upsertChannelPairingRequest, readChannelAllowFromStore, buildModelsProviderData) and threaded through handlers/native command paths.
    • Session and forum topic routing resolution now consistently uses injected/store-backed allow-from readers and fresh config routing inputs.
    • Message-context routing now reads config via injected fresh loader (loadFreshConfig) per inbound message for route/binding resolution consistency.
    • Reply formatting test harness now uses the reply dispatcher path (createReplyDispatcher) so prefix/skip/error/reply-shape behavior is exercised more realistically.
    • Telegram media/sticker e2e harness was stabilized; two flaky sticker cases are quarantined (it.skip) pending deterministic follow-up.
  • What did NOT change (scope boundary): No new user-facing command set or config keys were introduced.

Change Type (select all)

  • Bug fix
  • Feature
  • Refactor
  • Docs
  • Security hardening
  • Chore/infra

Scope (select all touched areas)

  • Gateway / orchestration
  • Skills / tool execution
  • Auth / tokens
  • Memory / storage
  • Integrations
  • API / contracts
  • UI / DX
  • CI/CD / infra

Linked Issue/PR

User-visible / Behavior Changes

  • No broad new user-facing feature is introduced; this PR primarily stabilizes Telegram dependency wiring and routing/reply test coverage.

Security Impact (required)

  • New permissions/capabilities? (Yes/No): No
  • Secrets/tokens handling changed? (Yes/No): No
  • New/changed network calls? (Yes/No): No
  • Command/tool execution surface changed? (Yes/No): No
  • Data access scope changed? (Yes/No): No
  • If any Yes, explain risk + mitigation:

Repro + Verification

Environment

  • OS: macOS
  • Runtime/container: Node 25.x, pnpm
  • Model/provider: N/A
  • Integration/channel (if any): Telegram extension tests
  • Relevant config (redacted): Test harness defaults only

Steps

  1. Run pnpm test -- extensions/telegram/src.
  2. Run pnpm test -- extensions/telegram/src/monitor.test.ts.
  3. Run pnpm test -- extensions/telegram/src/bot.create-telegram-bot.test.ts.
  4. Run pnpm build.
  5. Run pnpm tsgo.
  6. Run pnpm test -- src/plugin-sdk/channel-import-guardrails.test.ts.
  7. Run pnpm test -- src/plugins/contracts/runtime.contract.test.ts.

Expected

  • Telegram lane and guardrail checks pass consistently with routing/pairing/reply harness updates.

Actual

  • Targeted regression commands and boundary checks passed on this branch.

Evidence

Attach at least one:

  • Failing test/log before + passing after
  • Trace/log snippets
  • Screenshot/recording
  • Perf numbers (if relevant)
  • Before: CI run 23277677077 failed extension-src-outside-plugin-sdk-boundary due a Telegram test harness import crossing extension boundaries.
  • After: commit d93a39153a switched the harness import to openclaw/plugin-sdk/reply-runtime, and CI run 23278040250 shows extension-src-outside-plugin-sdk-boundary passing.

Human Verification (required)

What you personally verified (not just CI), and how:

  • Verified scenarios:
    • pnpm test -- extensions/telegram/src passed (channels green; e2e green with 2 intentional skips).
    • Pairing/session/forum routing-adjacent Telegram suites (monitor, create-telegram-bot) passed after dependency/routing adjustments.
    • pnpm test -- extensions/telegram/src/bot.create-telegram-bot.test.ts -t "reloads DM routing bindings between messages without recreating the bot" passed (regression test for per-message route/binding refresh).
    • pnpm test -- extensions/telegram/src/monitor.test.ts -t "retries setup-time recoverable errors before starting polling" passed, including explicit backoff helper assertions.
    • pnpm build, pnpm tsgo, and both contract/guardrail suites passed.
  • Edge cases checked:
    • Animated/video sticker skip path remains active and passing.
    • Existing media e2e path coverage remains active and passing.
  • What you did not verify:

Review Conversations

  • I replied to or resolved every bot review conversation I addressed in this PR.
  • I left unresolved only the conversations that still need reviewer or maintainer judgment.

If a bot review conversation is addressed by this PR, resolve that conversation yourself. Do not leave bot review conversation cleanup for maintainers.

Compatibility / Migration

  • Backward compatible? (Yes/No): Yes
  • Config/env changes? (Yes/No): No
  • Migration needed? (Yes/No): No
  • If yes, exact upgrade steps:

Failure Recovery (if this breaks)

  • How to disable/revert this change quickly: Revert PR commits (f0d56e255f, 4d617a9f69, 262ce888de, ab81e32a2a, d93a39153a).
  • Files/config to restore: Telegram files touched in this PR under extensions/telegram/src/.
  • Known bad symptoms reviewers should watch for:
    • Telegram DM pairing prompts not issuing expected code challenges.
    • Route/binding updates not being reflected on subsequent inbound messages.
    • Callback/provider selection menus not formatting/dispatching reply payloads as expected.

Risks and Mitigations

List only real risks for this PR. Add/remove entries as needed. If none, write None.

  • Risk: Two sticker e2e tests are skipped, reducing immediate coverage for static sticker download/cache refresh behavior.
  • Risk: Per-message config reload may differ from startup snapshot behavior in custom embedding scenarios.
    • Mitigation: Default persisted-config deployments benefit from fresher routing behavior; no config schema change required.

@openclaw-barnacle openclaw-barnacle bot added channel: telegram Channel integration: telegram size: L maintainer Maintainer-authored PR labels Mar 19, 2026
@joshavant joshavant changed the title Telegram: stabilize Area 2 harness and quarantine flaky sticker e2e Telegram: stabilize harness and quarantine flaky sticker e2e Mar 19, 2026
@joshavant joshavant force-pushed the feat/telegram-area2-stabilization branch from 678b5ad to 8cf7f36 Compare March 19, 2026 02:53
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 678b5ad848

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Mar 19, 2026

Greptile Summary

This PR stabilizes the Area 2 Telegram test harness by completing dependency injection wiring (upsertChannelPairingRequest, buildModelsProviderData, readChannelAllowFromStore) through TelegramBotDeps, fixing module-mock hoisting issues (vi.doMockvi.mock for undici, web-media, and media-runtime), and quarantining two flaky sticker e2e tests pending a deterministic rework. No production runtime logic changes were introduced.

Key changes:

  • bot-deps.ts, bot-handlers.runtime.ts, bot-message-context.ts, dm-access.ts, bot/helpers.ts: properly route upsertChannelPairingRequest, buildModelsProviderData, and readChannelAllowFromStore through the injectable TelegramBotDeps object instead of direct module imports.
  • bot.create-telegram-bot.test-harness.ts: switches vi.doMockvi.mock for undici and web-media so mocks are hoisted before any module import; adds .js extension variants for ESM dual-resolution; extracts dispatchHarnessReplies to avoid duplicated harness logic; wires buildModelsProviderData mock backed by a local createModelsProviderDataFromConfig helper.
  • bot.media.e2e-harness.ts / bot.media.test-utils.ts: exports undiciFetchSpy (reset in beforeEach) and threads it as the default proxyFetch, so sticker/media e2e paths are correctly intercepted at the HTTP layer.
  • bot.media.stickers-and-fragments.e2e.test.ts: quarantines two sticker download/cache-hit tests with it.skip; migrates the active animated-sticker test to the proxyFetch-injection pattern.
  • monitor.test.ts / fetch.test.ts: removes vi.resetModules() calls and drops computeBackoff/sleepWithAbort assertions that were causing flakiness — note this reduces coverage of the retry backoff mechanism (see inline comment).

Confidence Score: 4/5

  • Safe to merge — all production logic is unchanged; changes are confined to test harness wiring and dependency injection plumbing.
  • Production code changes are minimal and well-scoped: they only make existing direct imports injectable via TelegramBotDeps, all with correct fallbacks to the original imports. The test harness changes are more substantial but the author verified full suite passage. The one meaningful concern is that computeBackoff/sleepWithAbort assertions were dropped from monitor.test.ts, reducing verification of the retry-backoff mechanism. Two sticker e2e tests are intentionally quarantined with it.skip, leaving a noted coverage gap. These are acknowledged trade-offs rather than defects.
  • extensions/telegram/src/monitor.test.ts — three test paths no longer assert that backoff and sleep were invoked during recoverable retry scenarios.
Prompt To Fix All With AI
This is a comment left during a code review.
Path: extensions/telegram/src/monitor.test.ts
Line: 203-205

Comment:
**Weakened retry-backoff verification**

Removing the `computeBackoff` and `sleepWithAbort` assertions from `expectRecoverableRetryState` (and from the three inline test callsites at lines ~451, ~532, ~676) reduces confidence that the retry mechanism actually engages backoff before retrying. The remaining `runSpy.toHaveBeenCalledTimes(N)` only confirms *that* retries occurred, not *that* the system backed off between them — meaning a busy-loop regression would still pass these tests.

If the root cause of flakiness was that `computeBackoff`/`sleepWithAbort` weren't always called on the exact invocation being checked (e.g., race with timer mocks), a more targeted fix would be to scope the assertion to the correct call count rather than dropping it entirely:

```suggestion
function expectRecoverableRetryState(expectedRunCalls: number) {
  expect(computeBackoff).toHaveBeenCalled();
  expect(sleepWithAbort).toHaveBeenCalled();
  expect(runSpy).toHaveBeenCalledTimes(expectedRunCalls);
}
```

If the assertions genuinely cannot be made reliable, a brief comment explaining the known limitation would help future maintainers understand the reduced coverage is intentional.

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: extensions/telegram/src/bot.create-telegram-bot.test-harness.ts
Line: 145-149

Comment:
**Inconsistent null-safety on `dispatcherOptions`**

In `dispatchHarnessReplies`, some accesses to `dispatcherOptions` use optional chaining (lines 137, 143, 151, 154) while the accesses to `responsePrefix`, `enableSlackInteractiveReplies`, `responsePrefixContextProvider`, `responsePrefixContext`, and `onHeartbeatStrip` here do not. Since TypeScript is satisfied (implying `dispatcherOptions` is a required field in `DispatchReplyHarnessParams`), the `?.` usages elsewhere are just overly defensive — but the inconsistency could mislead future readers into thinking `dispatcherOptions` can be nullish and make them wonder why these lines aren't equally guarded.

Consider removing the redundant `?.` on `dispatcherOptions` in the other spots so the code reads uniformly, e.g.:

```typescript
  await params.dispatcherOptions.typingCallbacks?.onReplyStart?.();
  // ...
  await params.dispatcherOptions.deliver?.(payload, info);
  // ...
  params.dispatcherOptions.onSkip?.(payload, info);
  params.dispatcherOptions.onError?.(err, info);
```

This makes it clear the object itself is always present and only its callback sub-fields are optional.

How can I resolve this? If you propose a fix, please make it concise.

Last reviewed commit: "Telegram: stabilize ..."

@joshavant joshavant changed the title Telegram: stabilize harness and quarantine flaky sticker e2e Telegram: stabilize pairing/session/forum routing and reply formatting Mar 19, 2026
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0bd609d1e7

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

resolveGroupActivation,
resolveGroupRequireMention,
resolveTelegramGroupConfig,
loadFreshConfig: () => telegramDeps.loadConfig(),
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve caller-supplied config in fresh route reloads

When createTelegramBot is constructed with config (a supported path used by monitorTelegramProvider, startTelegramWebhook, and tests), this callback now ignores that object and re-reads the global config from disk. That makes ACP binding/session routing diverge from the rest of the bot whenever the caller is running against an in-memory or not-yet-persisted config: for example, a named-account bot created from a custom config can start dropping inbound group messages because resolveTelegramConversationRoute no longer sees that account or its bindings in the on-disk config. The fresh-load path should only bypass opts.config when no explicit config was supplied.

Useful? React with 👍 / 👎.

@joshavant joshavant changed the title Telegram: stabilize pairing/session/forum routing and reply formatting Telegram: stabilize pairing/session/forum routing and reply formatting tests Mar 19, 2026
@joshavant joshavant force-pushed the feat/telegram-area2-stabilization branch from 84449f3 to d93a391 Compare March 19, 2026 03:40
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d93a39153a

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

: dmPolicy;
// Fresh config for bindings lookup; other routing inputs are payload-derived.
const freshCfg = loadConfig();
const freshCfg = (loadFreshConfig ?? loadConfig)();
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Reload the full config alongside fresh Telegram routing

When Telegram config changes after startup, this line now recomputes route from a fresh config, but the rest of the pipeline still uses the startup snapshot: resolveTelegramInboundBody/ACK setup continue reading cfg in extensions/telegram/src/bot-message-context.ts:271-333, and dispatchTelegramMessage is still called with the original cfg in extensions/telegram/src/bot-message.ts:88-99. That means a newly added ACP binding or topic-agent change can send a message to a fresh route.agentId while model selection, agent directories, media roots, and other per-agent settings are resolved from stale config, so hot-routed messages can be answered with the wrong agent settings until the bot is restarted.

Useful? React with 👍 / 👎.

@joshavant
Copy link
Copy Markdown
Contributor Author

Addressed the review concerns in this branch:

  1. Scope/claim tightening
  • Updated the PR description to remove the broad "no-restart" user-visible claim and frame this as Telegram DI/routing/reply stabilization.
  1. Explicit regression test for routing refresh behavior
  • Added reloads DM routing bindings between messages without recreating the bot in extensions/telegram/src/bot.create-telegram-bot.test.ts.
  • This verifies route/session binding selection updates across consecutive messages on the same bot instance when config bindings change.
  1. Retry/backoff assertion coverage
  • Added explicit helper assertions in extensions/telegram/src/monitor.test.ts for the setup-time recoverable retry path (computeBackoff + sleepWithAbort).
  1. Skipped sticker tests follow-up tracked

Evidence snippets (local):

pnpm test -- extensions/telegram/src/bot.create-telegram-bot.test.ts -t "reloads DM routing bindings between messages without recreating the bot"
Test Files  1 passed (1)
Tests       1 passed | 46 skipped (47)
pnpm test -- extensions/telegram/src/monitor.test.ts -t "retries setup-time recoverable errors before starting polling"
Test Files  1 passed (1)
Tests       1 passed | 23 skipped (24)

Also included CI before/after boundary evidence in the PR description:

  • before: run 23277677077 extension-src-outside-plugin-sdk-boundary failed
  • after: run 23278040250 extension-src-outside-plugin-sdk-boundary passed

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 249d19cfec

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +1119 to +1126
const fetchSpy = vi.spyOn(globalThis, "fetch").mockResolvedValue(
new Response(Buffer.from("GIF89a"), {
status: 200,
headers: {
"content-type": "image/gif",
},
}),
);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Restore the mocked media loader in the GIF reply test

The new assertion spies on globalThis.fetch, but Telegram reply delivery still loads outbound media through loadWebMedia in extensions/telegram/src/bot/delivery.replies.ts:250-259. In this harness, loadWebMedia is just a vi.fn() that gets reset without any implementation in extensions/telegram/src/bot.create-telegram-bot.test-harness.ts:480, so await handler(...) will hit undefined.contentType instead of returning GIF bytes. As written, this regression test no longer exercises the sendAnimation path and will fail once the Telegram suite runs.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5e0abdb744

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

: dmPolicy;
// Fresh config for bindings lookup; other routing inputs are payload-derived.
const freshCfg = loadConfig();
const freshCfg = (loadFreshConfig ?? loadConfig)();
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Guard the per-message config reload with a snapshot fallback

This new loadFreshConfig() call is unconditional, and loadConfig() can throw on parse/include errors in src/config/io.ts. If the config file is briefly unreadable while an admin is editing it, every inbound Telegram message will now fail during context construction instead of being processed with the already-loaded startup cfg. That turns a temporary bad write into dropped messages or generic failure responses until the file becomes readable again.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 57c322f6e8

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

for (const issue of pluginCatalog.issues) {
runtime.error?.(danger(issue));
}
const loadFreshRuntimeConfig = (): OpenClawConfig => telegramDeps.loadConfig();
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Guard slash-command config reload with a startup fallback

loadFreshRuntimeConfig() now calls telegramDeps.loadConfig() unconditionally for every native and plugin command. Because loadConfig() throws on parse/include/env validation errors in src/config/io.ts, a temporary bad write while an admin edits the config will make /status, /new, and plugin commands fail before auth/routing runs, even though registerTelegramNativeCommands() still has the startup cfg snapshot available. This turns transient config-edit errors into dropped command replies until the file becomes readable again.

Useful? React with 👍 / 👎.

Comment on lines +1342 to +1344
const modelData = await telegramDeps.buildModelsProviderData(
runtimeCfg,
sessionState.agentId,
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep model-button writes on the same config snapshot

Fresh evidence from this commit: this branch now reloads the current agent via buildModelsProviderData(runtimeCfg, sessionState.agentId), but later in the same modelCallback handler it still uses the startup cfg for formatModelsAvailableHeader, resolveStorePath, and resolveDefaultModelForAgent. If a Telegram binding is retargeted to another agent or the session store/default model changes without restarting the bot, the button UI can show the reloaded agent's models but persist the selection into the old store or compare against the old default, so the reported model change does not affect the next message.

Useful? React with 👍 / 👎.

@aisle-research-bot
Copy link
Copy Markdown

aisle-research-bot bot commented Mar 19, 2026

🔒 Aisle Security Analysis

We found 1 potential security issue(s) in this PR:

# Severity Title
1 🟡 Medium Telegram native command auth uses mixed config snapshots (stale allowlists) despite per-invocation runtime config reload

1. 🟡 Telegram native command auth uses mixed config snapshots (stale allowlists) despite per-invocation runtime config reload

Property Value
Severity Medium
CWE CWE-285
Location extensions/telegram/src/bot-native-commands.ts:589-603

Description

registerTelegramNativeCommands now loads a fresh runtimeCfg and runtimeTelegramCfg on every command invocation, but the authorization decision still depends on startup-captured allowlists/policy resolvers. This creates a TOCTOU-style inconsistency where access can be granted using stale authorization inputs even though other decisions (routing/session/delivery) use the fresh config.

Impact:

  • DM / group sender allowlists can remain permissive after runtime config revocation. The handler refreshes runtimeTelegramCfg, but still passes allowFrom / groupAllowFrom variables that were captured when the bot started (and are not derived from runtimeTelegramCfg).
  • Group allowlist policy can be evaluated using an older snapshot because resolveGroupPolicy is injected from bot.ts and (currently) closes over the startup cfg rather than runtimeCfg. As a result, removing a group from the allowlist in the live config may not take effect for native commands until restart.

Vulnerable code (mixed fresh+stale auth inputs):

const runtimeCfg = loadFreshRuntimeConfig();
const runtimeTelegramCfg = resolveFreshTelegramConfig(runtimeCfg);
const auth = await resolveTelegramCommandAuth({
  cfg: runtimeCfg,
  telegramCfg: runtimeTelegramCfg,
  allowFrom,        // startup snapshot
  groupAllowFrom,   // startup snapshot
  resolveGroupPolicy, // may use startup cfg
  ...
});

And inside auth, DM allowlist prefers these values:

const dmAllowFrom = groupAllowOverride ?? allowFrom;

This means a user/group that was removed from config allowlists can potentially continue executing native/plugin commands (until process restart), contrary to the intent of loading fresh runtime configuration per invocation.

Recommendation

Ensure all authorization inputs come from the same fresh snapshot used for the rest of the command execution.

Suggested fixes:

  1. Derive allowFrom/groupAllowFrom from the freshly resolved runtimeTelegramCfg (and only fall back to startup values for CLI overrides if that is intentional):
const runtimeAllowFrom = runtimeTelegramCfg.allowFrom;
const runtimeGroupAllowFrom =
  runtimeTelegramCfg.groupAllowFrom ?? runtimeTelegramCfg.allowFrom ?? runtimeAllowFrom;

const auth = await resolveTelegramCommandAuth({
  ...,
  telegramCfg: runtimeTelegramCfg,
  allowFrom: runtimeAllowFrom,
  groupAllowFrom: runtimeGroupAllowFrom,
});
  1. Make resolveGroupPolicy use runtimeCfg (not a startup closure). For example, change the function signature to accept cfg or construct a per-invocation resolver:
const resolveGroupPolicyRuntime = (chatId: string | number) =>
  resolveChannelGroupPolicy({ cfg: runtimeCfg, channel: "telegram", accountId, groupId: String(chatId) });
  1. Consider failing closed when fresh account config cannot be resolved (instead of silently falling back to the startup snapshot) for auth-relevant settings.

These changes prevent stale allowlists/policies from granting access after runtime revocation.


Analyzed PR: #50155 at commit a1d84d9

Last updated on: 2026-03-19T06:17:02Z

@joshavant joshavant force-pushed the feat/telegram-area2-stabilization branch from dee50f7 to ada1df3 Compare March 19, 2026 04:59
Signed-off-by: joshavant <[email protected]>
@joshavant joshavant merged commit 68bc6ef into main Mar 19, 2026
9 checks passed
@joshavant joshavant deleted the feat/telegram-area2-stabilization branch March 19, 2026 05:01
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a1d84d988f

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

return;
}

const runtimeCfg = telegramDeps.loadConfig();
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Guard callback config reload with a startup fallback

This callback path now unconditionally calls telegramDeps.loadConfig() before handling approvals, command pagination, or model buttons. loadConfig() can throw on parse/include/env errors, so a transient invalid config edit will make inline buttons stop working even though this bot instance still has a valid startup snapshot in memory. That turns a temporary admin write error into dropped callback actions until the file is fixed.

Useful? React with 👍 / 👎.

readChannelAllowFromStore: telegramDeps.readChannelAllowFromStore,
allowFrom,
groupAllowFrom,
useAccessGroups,
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Recompute command chat allowlists from the fresh config

This command path reloads runtimeCfg, but it still passes the startup resolveGroupPolicy closure from extensions/telegram/src/bot.ts:391-397 into resolveTelegramCommandAuth(). evaluateTelegramGroupPolicyAccess() uses that closure for the chat-level allowlist check, so changing channels.telegram.groupPolicy or channels.telegram.groups after startup can leave /models and /new authorizing against the old group list even while route/topic resolution is using the fresh config.

Useful? React with 👍 / 👎.

cxa pushed a commit to cxa/openclaw that referenced this pull request Mar 19, 2026
…g tests (openclaw#50155)

* Telegram: stabilize Area 2 DM and model callbacks

* Telegram: fix dispatch test deps wiring

* Telegram: stabilize area2 test harness and gate flaky sticker e2e

* Telegram: address review feedback on config reload and tests

* Telegram tests: use plugin-sdk reply dispatcher import

* Telegram tests: add routing reload regression and track sticker skips

* Telegram: add polling-session backoff regression test

* Telegram tests: mock loadWebMedia through plugin-sdk path

* Telegram: refresh native and callback routing config

* Telegram tests: fix compact callback config typing
fuller-stack-dev pushed a commit to fuller-stack-dev/openclaw that referenced this pull request Mar 20, 2026
…g tests (openclaw#50155)

* Telegram: stabilize Area 2 DM and model callbacks

* Telegram: fix dispatch test deps wiring

* Telegram: stabilize area2 test harness and gate flaky sticker e2e

* Telegram: address review feedback on config reload and tests

* Telegram tests: use plugin-sdk reply dispatcher import

* Telegram tests: add routing reload regression and track sticker skips

* Telegram: add polling-session backoff regression test

* Telegram tests: mock loadWebMedia through plugin-sdk path

* Telegram: refresh native and callback routing config

* Telegram tests: fix compact callback config typing
fuller-stack-dev pushed a commit to fuller-stack-dev/openclaw that referenced this pull request Mar 20, 2026
…g tests (openclaw#50155)

* Telegram: stabilize Area 2 DM and model callbacks

* Telegram: fix dispatch test deps wiring

* Telegram: stabilize area2 test harness and gate flaky sticker e2e

* Telegram: address review feedback on config reload and tests

* Telegram tests: use plugin-sdk reply dispatcher import

* Telegram tests: add routing reload regression and track sticker skips

* Telegram: add polling-session backoff regression test

* Telegram tests: mock loadWebMedia through plugin-sdk path

* Telegram: refresh native and callback routing config

* Telegram tests: fix compact callback config typing
pholpaphankorn pushed a commit to pholpaphankorn/openclaw that referenced this pull request Mar 22, 2026
…g tests (openclaw#50155)

* Telegram: stabilize Area 2 DM and model callbacks

* Telegram: fix dispatch test deps wiring

* Telegram: stabilize area2 test harness and gate flaky sticker e2e

* Telegram: address review feedback on config reload and tests

* Telegram tests: use plugin-sdk reply dispatcher import

* Telegram tests: add routing reload regression and track sticker skips

* Telegram: add polling-session backoff regression test

* Telegram tests: mock loadWebMedia through plugin-sdk path

* Telegram: refresh native and callback routing config

* Telegram tests: fix compact callback config typing
frankekn pushed a commit to artwalker/openclaw that referenced this pull request Mar 23, 2026
…g tests (openclaw#50155)

* Telegram: stabilize Area 2 DM and model callbacks

* Telegram: fix dispatch test deps wiring

* Telegram: stabilize area2 test harness and gate flaky sticker e2e

* Telegram: address review feedback on config reload and tests

* Telegram tests: use plugin-sdk reply dispatcher import

* Telegram tests: add routing reload regression and track sticker skips

* Telegram: add polling-session backoff regression test

* Telegram tests: mock loadWebMedia through plugin-sdk path

* Telegram: refresh native and callback routing config

* Telegram tests: fix compact callback config typing
alexey-pelykh pushed a commit to remoteclaw/remoteclaw that referenced this pull request Mar 28, 2026
…g tests (openclaw#50155)

* Telegram: stabilize Area 2 DM and model callbacks

* Telegram: fix dispatch test deps wiring

* Telegram: stabilize area2 test harness and gate flaky sticker e2e

* Telegram: address review feedback on config reload and tests

* Telegram tests: use plugin-sdk reply dispatcher import

* Telegram tests: add routing reload regression and track sticker skips

* Telegram: add polling-session backoff regression test

* Telegram tests: mock loadWebMedia through plugin-sdk path

* Telegram: refresh native and callback routing config

* Telegram tests: fix compact callback config typing

(cherry picked from commit 68bc6ef)

# Conflicts:
#	CHANGELOG.md
#	extensions/telegram/src/bot-deps.ts
#	extensions/telegram/src/bot-message-dispatch.test.ts
#	extensions/telegram/src/bot-native-commands.group-auth.test.ts
#	extensions/telegram/src/bot-native-commands.menu-test-support.ts
#	extensions/telegram/src/bot-native-commands.session-meta.test.ts
#	extensions/telegram/src/bot-native-commands.test-helpers.ts
#	extensions/telegram/src/bot-native-commands.test.ts
#	extensions/telegram/src/bot-native-commands.ts
#	extensions/telegram/src/bot.create-telegram-bot.test-harness.ts
#	extensions/telegram/src/bot.create-telegram-bot.test.ts
#	extensions/telegram/src/bot.media.e2e-harness.ts
#	extensions/telegram/src/bot.media.stickers-and-fragments.e2e.test.ts
#	extensions/telegram/src/bot.media.test-utils.ts
#	extensions/telegram/src/bot.test.ts
#	extensions/telegram/src/bot/delivery.test.ts
#	extensions/telegram/src/dm-access.ts
#	extensions/telegram/src/fetch.test.ts
#	src/telegram/bot-handlers.ts
alexey-pelykh pushed a commit to remoteclaw/remoteclaw that referenced this pull request Mar 28, 2026
…g tests (openclaw#50155)

* Telegram: stabilize Area 2 DM and model callbacks

* Telegram: fix dispatch test deps wiring

* Telegram: stabilize area2 test harness and gate flaky sticker e2e

* Telegram: address review feedback on config reload and tests

* Telegram tests: use plugin-sdk reply dispatcher import

* Telegram tests: add routing reload regression and track sticker skips

* Telegram: add polling-session backoff regression test

* Telegram tests: mock loadWebMedia through plugin-sdk path

* Telegram: refresh native and callback routing config

* Telegram tests: fix compact callback config typing

(cherry picked from commit 68bc6ef)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

channel: telegram Channel integration: telegram maintainer Maintainer-authored PR size: XL

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant