fix(slack): clamp approval message so chat_update survives HTML-escaped >3000-char sections - #61697
Conversation
…escaped >3000-char sections Interactive command-approval buttons appeared dead: clicking Allow/Always left the message visually unchanged, even though the approval itself resolved and the agent unblocked. Root cause: send_exec_approval budgets the command preview against the RAW 3000-char section limit, but Slack HTML-escapes `< > &` when it stores the message. Dangerous commands (redirects/pipes/`&&`) — exactly the ones that trigger approval — grow once escaped. chat_postMessage accepts the escaped text, but the chat_update fired on button click enforces the 3000 cap strictly and fails with `invalid_blocks`, so the message never redraws. Observed live: a prompt budgeted to exactly 3000 raw chars was stored by Slack at 3061 (escaping added 61), and the approval update failed every time while the approval still resolved. Fix: - _handle_approval_action: clamp the echoed section text to 2900 chars before chat_update (the buttons are being stripped anyway, so truncating the echoed command is harmless). - send_exec_approval: target 2900 rather than 3000 to leave headroom for escaping so the stored section stays under the cap. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Duplicate of #53701 — both fix the same #53693 bug (Slack |
teknium1
left a comment
There was a problem hiding this comment.
Thanks for targeting the real post-decision chat.update failure.
Problems
- The same unbounded reconstruction remains in
_handle_slash_confirm_actionatplugins/platforms/slack/adapter.py:3511-3539; it sendsoriginal_textunchanged at:3522, so slash-confirm cards retain this failure mode. - This PR adds no regression coverage. Existing approval and slash-confirm tests in
tests/gateway/test_slack_approval_buttons.py:174-348do not provide an inflated interaction payload or assert the section length sent tochat_update.
Suggested changes
- Apply the bounded-section logic to both update handlers, ideally through a shared helper.
- Add one regression test per handler for an over-limit echoed section and assert the outgoing update block is capped.
The earlier canonical PR #53701 already demonstrates both sibling coverage and tests. This is an automated hermes-sweeper review.
| # never fails with ``invalid_blocks`` (the buttons are stripped anyway, | ||
| # so truncating the echoed command is harmless). | ||
| _SECTION_CAP = 2900 | ||
| if len(original_text) > _SECTION_CAP: |
There was a problem hiding this comment.
Please apply the same cap to _handle_slash_confirm_action: current main still rebuilds its chat_update section from unbounded original_text at plugins/platforms/slack/adapter.py:3511-3523, so slash-confirm cards retain the same failure mode.
|
Closing as superseded by #69317 (merged): the escape-inflation clamp landed via #53701 (earlier) plus the new sanitize_blocks() boundary; the 2900-char send budget became unnecessary once the update boundary clamps. Thanks for digging into this — the consolidated fix stands on the cluster's collective analysis, and your work is credited in #69317's summary. |
Problem
Interactive command-approval buttons (
Allow Once/Allow Session/Always Allow/Deny) appear dead: clicking leaves the message visually unchanged. The approval does resolve — the agent unblocks and continues — but the message never redraws to strip the buttons and stamp the decision, so from the user's seat "nothing happens" and they re-click.Root cause
send_exec_approvalbudgets the command preview against Slack's 3000-char section limit measured on the raw string. But Slack HTML-escapes<>&when it stores the message (>->>, +3 chars each). Dangerous commands — the ones full of redirects / pipes /&&that trigger approval in the first place — grow once escaped.chat.postMessageaccepts the escaped text, but thechat.updatefired on button click (_handle_approval_action) enforces the 3000 cap strictly and fails:so the redraw silently fails (only a
logger.warning), leaving the buttons on screen.Observed live: a prompt budgeted to exactly 3000 raw chars was stored by Slack at 3061 (escaping added 61 chars:
>x7,<x8,&x4). Every approval update failed while the approval itself resolved normally.Fix
_handle_approval_action— clamp the echoed section text to 2900 chars beforechat_update. The buttons are being stripped anyway, so truncating the echoed command is harmless, and it guarantees the decision update never fails regardless of escaping.send_exec_approval— target 2900 instead of 3000 so the stored (escaped) section stays under the cap, avoiding the rarer case where a metacharacter-heavy command escapes past 3000 on the initial post and loses its buttons entirely.Cosmetic / update-path only; no change to approval semantics.