Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 17 additions & 2 deletions plugins/platforms/slack/adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -3262,10 +3262,14 @@ async def send_exec_approval(
# buttons). execute_code approvals embed the entire script in
# ``command``, so budget the preview against the fixed parts
# instead of a flat truncation that overflows once the header +
# reason are added.
# reason are added. Target 2900 rather than 3000: Slack
# HTML-escapes ``< > &`` on storage, and dangerous commands
# (redirects/pipes/``&&``) grow once escaped — the headroom keeps
# the *stored* (escaped) section under the cap so the later
# chat_update on approval doesn't fail with ``invalid_blocks``.
header = ":warning: *Command Approval Required*\n"
reason = f"Reason: {description[:500]}"
budget = 3000 - len(header) - len(reason) - len("``````\n") - len("...")
budget = 2900 - len(header) - len(reason) - len("``````\n") - len("...")
cmd_preview = command[:budget] + "..." if len(command) > budget else command

blocks = [
Expand Down Expand Up @@ -3636,6 +3640,17 @@ async def _handle_approval_action(self, ack, body, action) -> None:
original_text = block.get("text", {}).get("text", "")
break

# Slack HTML-escapes ``< > &`` when it stores the message, so the text
# echoed back in the button payload can exceed the 3000-char section
# cap that chat_update enforces even though the send path budgeted the
# RAW command to <=3000 — dangerous commands (redirects/pipes/``&&``)
# balloon once escaped. Clamp before re-posting so the decision update
# 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:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

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.

original_text = original_text[:_SECTION_CAP].rstrip() + "\n... [truncated]"

updated_blocks = [
{
"type": "section",
Expand Down