Skip to content

refactor(exec): unify channel approvals and restore routing/auth#57838

Merged
scoootscooob merged 18 commits into
openclaw:mainfrom
scoootscooob:codex/exec-approval-reviewable
Mar 30, 2026
Merged

refactor(exec): unify channel approvals and restore routing/auth#57838
scoootscooob merged 18 commits into
openclaw:mainfrom
scoootscooob:codex/exec-approval-reviewable

Conversation

@scoootscooob

@scoootscooob scoootscooob commented Mar 30, 2026

Copy link
Copy Markdown
Contributor

Summary

This PR replaces the old stacked approval work in #57655, #57649, #57516, and #57650 with one reviewable channel-approval change.

It is both a refactor and a bug fix:

  • the refactor unifies Discord and Telegram approval delivery around shared runtime and delivery helpers
  • the fix restores consistent approval behavior across /approve, native callbacks, plugin fallback, and account-scoped routing

The refactor is not incidental here. It is the mechanism that removes the duplicated approval paths that were causing the routing and auth drift.

Problem

Before this branch:

  • Discord and Telegram had separate approval delivery paths
  • /approve and native callback resolution did not share the same fallback and auth rules
  • legacy unprefixed plugin approvals and exec approvals could resolve differently depending on the surface
  • Telegram account-scoped approval delivery could mis-scope prompts when turn metadata was incomplete
  • the work was spread across overlapping PRs that all touched the same approval lifecycle

That made both review and maintenance worse: the code paths diverged, and the bug fixes could not really be validated without mentally composing the whole stack.

What changed

Shared approval runtime and helpers

  • add shared approval runtime in src/infra/exec-approval-channel-runtime.ts
  • centralize shared reply/action helpers in src/infra/exec-approval-reply.ts
  • export the shared runtime surface through src/plugin-sdk/infra-runtime.ts

Native delivery unification

  • centralize native approval delivery planning in src/infra/approval-native-delivery.ts
  • add shared SDK delivery helpers in src/plugin-sdk/approval-delivery-helpers.ts
  • move Discord and Telegram onto thin native adapters in extensions/discord/src/approval-native.ts and extensions/telegram/src/approval-native.ts

Routing and resolution fixes

  • restore Discord and Telegram approval routing onto the unified runtime path
  • restore /approve resolution and callback handling across exec and plugin approvals
  • preserve legacy unprefixed plugin fallback where backward compatibility still matters
  • make Telegram callback resolution use the same not-found fallback rules as /approve

Auth and account-scoping hardening

  • centralize approval command auth in src/infra/channel-approval-auth.ts
  • enforce channel-specific approver rules instead of relying on generic command authorization alone
  • tighten Telegram account binding and origin-target validation so approvals stay on the correct account and surface

Review follow-ups included in this PR

  • preserve the real not-found error in plugin-only fallback paths instead of converting it into an auth error
  • fall back to the session-bound Telegram account when the turn source is Telegram but turnSourceAccountId is missing
  • detect structured APPROVAL_NOT_FOUND gateway envelopes before Telegram falls back to plugin.approval.resolve
  • dedupe Discord delivery when a DM-origin approval and approver DM target collapse to the same conversation
  • align the Discord /approve test registry with the unified native approval auth model after rebasing to current main

Why this is one PR

All of these changes sit on the same lifecycle:

request -> delivery -> reply/callback -> auth -> resolution -> final status update

Splitting them left overlapping diffs in the same files and made the later fixes depend on intermediate refactor branches. Keeping the whole channel approval path together is the cleanest review boundary.

Out of scope

Shell-side /approve command rejection and wrapper parsing are not in this PR. That work is isolated in #57839.

Verification

  • pnpm plugin-sdk:api:check
  • pnpm build
  • pnpm test -- src/auto-reply/reply/commands.test.ts
  • targeted approval tests across Discord and Telegram runtime/resolution paths during review
  • live smoke for Discord and Telegram approval delivery and resolution during review

Supersedes

@greptile-apps

greptile-apps Bot commented Mar 30, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR consolidates the Discord and Telegram exec-approval flow — runtime lifecycle, native delivery routing, and channel auth — from four stacked PRs into a single mainline-safe change. A new shared createExecApprovalChannelRuntime factory replaces hand-rolled pending maps and gateway lifecycle code in both channel adapters, the delivery-plan helper centralises surface-selection (origin vs. approver DM, deduplication, notifyOriginWhenDmOnly), and resolveApprovalCommandAuthorization gains an explicit flag to distinguish "no channel plugin configured" from an explicit channel-level allow.

Key findings:

  • P1 — Wrong error message in /approve plugin-only fallback path (src/auto-reply/reply/commands-approve.ts lines 247-252): when execApprovalAuthorization.authorized === false and pluginApprovalAuthorization.authorized === true, an "unknown or expired approval id" thrown by plugin.approval.resolve returns pluginApprovalAuthorization.reason ?? \"❌ You are not authorized to approve this request.\". Since the user IS authorized in this branch, reason is typically undefined, so they incorrectly see a "not authorized" message when the real issue is that the approval has expired or doesn't exist. The fix is to use ❌ Failed to submit approval: ${String(err)} (consistent with all other not-found paths).
  • The shared runtime handles concurrent start/stop races, delivery-before-resolution, and expiration correctly.
  • The Telegram one-shot resolver (exec-approval-resolver.ts) guards the ready-promise against duplicate settlement properly.
  • Discord's deliverRequested correctly consults deliveryPlan.notifyOriginWhenDmOnly; Telegram's adapter never sets that capability, so the omission there is safe.

Confidence Score: 4/5

Safe to merge after fixing the misleading not-authorized error message in the plugin-only /approve fallback path.

One P1 logic bug remains: in commands-approve.ts the else-if (pluginApprovalAuthorization.authorized) branch returns an authorization-flavored message when the approval is not found, even though the user is authorized. All other findings are clean — the shared runtime, delivery-plan helper, auth refactor, and both channel adapters look correct.

src/auto-reply/reply/commands-approve.ts (lines 247-252 — wrong error message in plugin-only fallback)

Important Files Changed

Filename Overview
src/auto-reply/reply/commands-approve.ts Rewrites /approve routing to use pre-computed exec/plugin authorization objects; adds Telegram-gated exec path and a new plugin-only fallback branch. Contains a P1 logic bug: the "not found" error inside the else if (pluginApprovalAuthorization.authorized) block returns the wrong error message.
src/infra/exec-approval-channel-runtime.ts New shared approval runtime that centralizes gateway lifecycle, pending-state tracking, delivery/expiration races, and event dispatch. Race conditions (concurrent start/stop, delivery-before-resolution) are handled correctly.
src/infra/approval-native-delivery.ts New helper to build a typed delivery plan (preferred/fallback targets, origin DM redirect) for approval notifications; deduplication and surface preference selection logic is straightforward.
src/infra/channel-approval-auth.ts Adds the explicit flag to distinguish implicit allow (no channel plugin) from an explicit channel-level authorization decision.
src/infra/exec-approval-reply.ts Refactors internal button-building helpers into exported buildExecApprovalActionDescriptors / buildExecApprovalCommandText, and adds parseExecApprovalCommandText for typed command parsing.
extensions/discord/src/monitor/exec-approvals.ts Migrates DiscordExecApprovalHandler to the shared runtime; removes hand-rolled pending map and gateway lifecycle code; properly uses notifyOriginWhenDmOnly from the delivery plan.
extensions/telegram/src/exec-approvals-handler.ts Migrates TelegramExecApprovalHandler to the shared runtime; removes hand-rolled pending map and gateway lifecycle; adds PluginApprovalRequest support by converting to exec-like requests where needed.
extensions/telegram/src/exec-approval-resolver.ts New one-shot gateway client that resolves a Telegram approval; properly guards the ready-promise against duplicate settlement via readySettled.
Prompt To Fix All With AI
This is a comment left during a code review.
Path: src/auto-reply/reply/commands-approve.ts
Line: 247-252

Comment:
**Wrong error message when approval not found in plugin-only path**

In this branch `pluginApprovalAuthorization.authorized === true` is guaranteed (we're inside `else if (pluginApprovalAuthorization.authorized)`), which means `reason` is typically `undefined`. So when `plugin.approval.resolve` throws an "unknown or expired approval id" error, the user receives:

```
❌ You are not authorized to approve this request.
```

…even though they ARE authorized — the approval simply doesn't exist or has expired.

Compare with the parallel exec-approval-not-found path (line ~223) which correctly returns `❌ Failed to submit approval: ${String(err)}`.

Suggested fix:

```suggestion
      if (isApprovalNotFoundError(err)) {
        return {
          shouldContinue: false,
          reply: { text: `❌ Failed to submit approval: ${String(err)}` },
        };
      }
```

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

Reviews (1): Last reviewed commit: "fix(exec): align approval rebase followu..." | Re-trigger Greptile

Comment thread src/auto-reply/reply/commands-approve.ts Outdated
@scoootscooob scoootscooob changed the title fix(exec): restore approval runtime, routing, and auth fix(exec): unify channel approval runtime, delivery, and auth Mar 30, 2026

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

Copy link
Copy Markdown

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: 9a44eed09e

ℹ️ 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 thread src/auto-reply/reply/commands-approve.ts Outdated

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

Copy link
Copy Markdown

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: d363db2914

ℹ️ 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 thread extensions/telegram/src/exec-approvals-handler.ts

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

Copy link
Copy Markdown

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: dd236fdf10

ℹ️ 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 thread extensions/telegram/src/exec-approval-resolver.ts Outdated

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

Copy link
Copy Markdown

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: 312f23b4ab

ℹ️ 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 thread extensions/discord/src/approval-native.ts

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

Copy link
Copy Markdown

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: 52d410d056

ℹ️ 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 thread extensions/telegram/src/bot-handlers.runtime.ts Outdated

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

Copy link
Copy Markdown

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: 93d5e28415

ℹ️ 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 thread src/infra/channel-approval-auth.ts Outdated
@scoootscooob

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Already looking forward to the next diff.

ℹ️ 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".

@scoootscooob scoootscooob merged commit 9ff57ac into openclaw:main Mar 30, 2026
8 checks passed
pgondhi987 pushed a commit to pgondhi987/openclaw that referenced this pull request Mar 31, 2026
…nclaw#57838)

* fix(exec): add shared approval runtime

* fix(exec): harden shared approval runtime

* fix(exec): guard approval expiration callbacks

* fix(exec): handle approval runtime races

* fix(exec): clean up failed approval deliveries

* fix(exec): restore channel approval routing

* fix(exec): scope telegram legacy approval fallback

* refactor(exec): centralize native approval delivery

* fix(exec): harden approval auth and account routing

* test(exec): align telegram approval auth assertions

* fix(exec): align approval rebase followups

* fix(exec): clarify plugin approval not-found errors

* fix(exec): fall back to session-bound telegram accounts

* fix(exec): detect structured telegram approval misses

* test(exec): align discord approval auth coverage

* fix(exec): ignore discord dm origin channel routes

* fix(telegram): skip self-authored message echoes

* fix(exec): keep implicit approval auth non-explicit
pgondhi987 pushed a commit to pgondhi987/openclaw that referenced this pull request Mar 31, 2026
…nclaw#57838)

* fix(exec): add shared approval runtime

* fix(exec): harden shared approval runtime

* fix(exec): guard approval expiration callbacks

* fix(exec): handle approval runtime races

* fix(exec): clean up failed approval deliveries

* fix(exec): restore channel approval routing

* fix(exec): scope telegram legacy approval fallback

* refactor(exec): centralize native approval delivery

* fix(exec): harden approval auth and account routing

* test(exec): align telegram approval auth assertions

* fix(exec): align approval rebase followups

* fix(exec): clarify plugin approval not-found errors

* fix(exec): fall back to session-bound telegram accounts

* fix(exec): detect structured telegram approval misses

* test(exec): align discord approval auth coverage

* fix(exec): ignore discord dm origin channel routes

* fix(telegram): skip self-authored message echoes

* fix(exec): keep implicit approval auth non-explicit
lovewanwan pushed a commit to lovewanwan/openclaw that referenced this pull request Apr 28, 2026
…nclaw#57838)

* fix(exec): add shared approval runtime

* fix(exec): harden shared approval runtime

* fix(exec): guard approval expiration callbacks

* fix(exec): handle approval runtime races

* fix(exec): clean up failed approval deliveries

* fix(exec): restore channel approval routing

* fix(exec): scope telegram legacy approval fallback

* refactor(exec): centralize native approval delivery

* fix(exec): harden approval auth and account routing

* test(exec): align telegram approval auth assertions

* fix(exec): align approval rebase followups

* fix(exec): clarify plugin approval not-found errors

* fix(exec): fall back to session-bound telegram accounts

* fix(exec): detect structured telegram approval misses

* test(exec): align discord approval auth coverage

* fix(exec): ignore discord dm origin channel routes

* fix(telegram): skip self-authored message echoes

* fix(exec): keep implicit approval auth non-explicit
Tardisyuan pushed a commit to Tardisyuan/openclaw that referenced this pull request Apr 30, 2026
…nclaw#57838)

* fix(exec): add shared approval runtime

* fix(exec): harden shared approval runtime

* fix(exec): guard approval expiration callbacks

* fix(exec): handle approval runtime races

* fix(exec): clean up failed approval deliveries

* fix(exec): restore channel approval routing

* fix(exec): scope telegram legacy approval fallback

* refactor(exec): centralize native approval delivery

* fix(exec): harden approval auth and account routing

* test(exec): align telegram approval auth assertions

* fix(exec): align approval rebase followups

* fix(exec): clarify plugin approval not-found errors

* fix(exec): fall back to session-bound telegram accounts

* fix(exec): detect structured telegram approval misses

* test(exec): align discord approval auth coverage

* fix(exec): ignore discord dm origin channel routes

* fix(telegram): skip self-authored message echoes

* fix(exec): keep implicit approval auth non-explicit
ogt-redknie pushed a commit to ogt-redknie/OPENX that referenced this pull request May 2, 2026
…nclaw#57838)

* fix(exec): add shared approval runtime

* fix(exec): harden shared approval runtime

* fix(exec): guard approval expiration callbacks

* fix(exec): handle approval runtime races

* fix(exec): clean up failed approval deliveries

* fix(exec): restore channel approval routing

* fix(exec): scope telegram legacy approval fallback

* refactor(exec): centralize native approval delivery

* fix(exec): harden approval auth and account routing

* test(exec): align telegram approval auth assertions

* fix(exec): align approval rebase followups

* fix(exec): clarify plugin approval not-found errors

* fix(exec): fall back to session-bound telegram accounts

* fix(exec): detect structured telegram approval misses

* test(exec): align discord approval auth coverage

* fix(exec): ignore discord dm origin channel routes

* fix(telegram): skip self-authored message echoes

* fix(exec): keep implicit approval auth non-explicit
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request May 9, 2026
…nclaw#57838)

* fix(exec): add shared approval runtime

* fix(exec): harden shared approval runtime

* fix(exec): guard approval expiration callbacks

* fix(exec): handle approval runtime races

* fix(exec): clean up failed approval deliveries

* fix(exec): restore channel approval routing

* fix(exec): scope telegram legacy approval fallback

* refactor(exec): centralize native approval delivery

* fix(exec): harden approval auth and account routing

* test(exec): align telegram approval auth assertions

* fix(exec): align approval rebase followups

* fix(exec): clarify plugin approval not-found errors

* fix(exec): fall back to session-bound telegram accounts

* fix(exec): detect structured telegram approval misses

* test(exec): align discord approval auth coverage

* fix(exec): ignore discord dm origin channel routes

* fix(telegram): skip self-authored message echoes

* fix(exec): keep implicit approval auth non-explicit
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request May 24, 2026
…nclaw#57838)

* fix(exec): add shared approval runtime

* fix(exec): harden shared approval runtime

* fix(exec): guard approval expiration callbacks

* fix(exec): handle approval runtime races

* fix(exec): clean up failed approval deliveries

* fix(exec): restore channel approval routing

* fix(exec): scope telegram legacy approval fallback

* refactor(exec): centralize native approval delivery

* fix(exec): harden approval auth and account routing

* test(exec): align telegram approval auth assertions

* fix(exec): align approval rebase followups

* fix(exec): clarify plugin approval not-found errors

* fix(exec): fall back to session-bound telegram accounts

* fix(exec): detect structured telegram approval misses

* test(exec): align discord approval auth coverage

* fix(exec): ignore discord dm origin channel routes

* fix(telegram): skip self-authored message echoes

* fix(exec): keep implicit approval auth non-explicit
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

channel: discord Channel integration: discord channel: telegram Channel integration: telegram docs Improvements or additions to documentation maintainer Maintainer-authored PR size: XL

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant