fix: bound slack interactive button urls · openclaw/openclaw@11d8ba9
steipete
·
2026-04-30
·
via Recent Commits to openclaw:main
| Original file line number | Diff line number | Diff line change |
|---|
@@ -39,6 +39,7 @@ Docs: https://docs.openclaw.ai
|
39 | 39 | - Slack/commands: keep native command argument menus on select controls for encoded choice values up to Slack's option limit and truncate fallback button labels to Slack's button-text limit, so long valid choices no longer render invalid Slack blocks. Thanks @slackapi. |
40 | 40 | - Agents/Codex: flush accepted debounced steering messages before normal app-server turn cleanup, so inbound follow-ups acknowledged as queued are not dropped when the turn completes before the debounce fires. Thanks @vincentkoc. |
41 | 41 | - Slack/interactive replies: keep rendered buttons and selects within Slack Block Kit value and count limits, and align command argument select values with Slack's option limit, so overlong agent-authored choices no longer make Slack reject the whole block payload. Thanks @slackapi. |
| 42 | +- Slack/interactive replies: drop overlong Block Kit button URLs while preserving valid callback values, so malformed link buttons no longer make Slack reject the whole interactive reply. Thanks @slackapi. |
42 | 43 | - CLI/update: scope packaged Node compile caches by OpenClaw version and install metadata, so global installs no longer reuse stale compiled chunks after package updates. Thanks @pashpashpash. |
43 | 44 | - Channels/Voice call: keep pre-auth webhook in-flight limiting active when socket remote address metadata is missing, so slow-body requests from stripped-IP proxy paths still share the fallback bucket. (#74453) Thanks @davidangularme. |
44 | 45 | - Plugin SDK/testing: lazy-load TypeScript from the plugin test-contract runtime and add release checks for critical SDK contract entrypoint imports and bundle size, so published packages fail preflight before shipping ESM-incompatible or oversized contract helpers. Thanks @vincentkoc. |
|
| Original file line number | Diff line number | Diff line change |
|---|
@@ -15,6 +15,7 @@ const SLACK_SECTION_TEXT_MAX = 3000;
|
15 | 15 | const SLACK_PLAIN_TEXT_MAX = 75; |
16 | 16 | const SLACK_OPTION_VALUE_MAX = 75; |
17 | 17 | const SLACK_BUTTON_VALUE_MAX = 2000; |
| 18 | +const SLACK_BUTTON_URL_MAX = 3000; |
18 | 19 | const SLACK_STATIC_SELECT_OPTIONS_MAX = 100; |
19 | 20 | const SLACK_ACTION_BLOCK_ELEMENTS_MAX = 25; |
20 | 21 | |
@@ -72,7 +73,11 @@ export function buildSlackInteractiveBlocks(interactive?: InteractiveReply): Sla
|
72 | 73 | button.value && isWithinSlackLimit(button.value, SLACK_BUTTON_VALUE_MAX) |
73 | 74 | ? button.value |
74 | 75 | : undefined; |
75 | | -if (!value && !button.url) { |
| 76 | +const url = |
| 77 | +button.url && isWithinSlackLimit(button.url, SLACK_BUTTON_URL_MAX) |
| 78 | + ? button.url |
| 79 | + : undefined; |
| 80 | +if (!value && !url) { |
76 | 81 | return []; |
77 | 82 | } |
78 | 83 | const style = resolveSlackButtonStyle(button.style); |
@@ -86,7 +91,7 @@ export function buildSlackInteractiveBlocks(interactive?: InteractiveReply): Sla
|
86 | 91 | emoji: true, |
87 | 92 | }, |
88 | 93 | ...(value ? { value } : {}), |
89 | | - ...(button.url ? { url: button.url } : {}), |
| 94 | + ...(url ? { url } : {}), |
90 | 95 | ...(style ? { style } : {}), |
91 | 96 | }, |
92 | 97 | ]; |
|
| Original file line number | Diff line number | Diff line change |
|---|
@@ -164,6 +164,34 @@ describe("buildSlackInteractiveBlocks", () => {
|
164 | 164 | expect(buttonBlock.elements?.[1]).not.toHaveProperty("value"); |
165 | 165 | }); |
166 | 166 | |
| 167 | +it("drops Slack button URLs beyond Block Kit limits", () => { |
| 168 | +const validUrl = `https://example.com/${"a".repeat(2980)}`; |
| 169 | +const longUrl = `https://example.com/${"b".repeat(2981)}`; |
| 170 | +const blocks = buildSlackInteractiveBlocks({ |
| 171 | +blocks: [ |
| 172 | +{ |
| 173 | +type: "buttons", |
| 174 | +buttons: [ |
| 175 | +{ label: "Allowed", url: validUrl }, |
| 176 | +{ label: "Too long", url: longUrl }, |
| 177 | +{ label: "Fallback action", value: "fallback", url: longUrl }, |
| 178 | +], |
| 179 | +}, |
| 180 | +], |
| 181 | +}); |
| 182 | + |
| 183 | +const buttonBlock = blocks[0] as { |
| 184 | +elements?: Array<{ value?: string; url?: string }>; |
| 185 | +}; |
| 186 | + |
| 187 | +expect(validUrl).toHaveLength(3000); |
| 188 | +expect(longUrl).toHaveLength(3001); |
| 189 | +expect(buttonBlock.elements).toHaveLength(2); |
| 190 | +expect(buttonBlock.elements?.[0]?.url).toBe(validUrl); |
| 191 | +expect(buttonBlock.elements?.[1]?.value).toBe("fallback"); |
| 192 | +expect(buttonBlock.elements?.[1]).not.toHaveProperty("url"); |
| 193 | +}); |
| 194 | + |
167 | 195 | it("caps Slack actions blocks at the Block Kit element limit", () => { |
168 | 196 | const blocks = buildSlackInteractiveBlocks({ |
169 | 197 | blocks: [ |
|
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。