fix(slack): insert resolved display names literally when humanizing mentions - #78837
Closed
Drexuxux wants to merge 1 commit into
Closed
fix(slack): insert resolved display names literally when humanizing mentions#78837Drexuxux wants to merge 1 commit into
Drexuxux wants to merge 1 commit into
Conversation
…entions _humanize_user_mentions rewrites <@uid> to @DisplayName by passing the resolved name as re.sub's replacement, where re parses it as a template. A display name is arbitrary user-set text, so the escapes in it are the user's characters, not regex syntax: dev\ops -> re.error: bad escape \o a\1b -> re.error: invalid group reference 1 \g<0> -> expands to the whole match, silently putting the opaque <@uid> back — the token this method exists to remove The trigger-text call site sits in _handle_slack_message outside any try, and both Bolt event handlers await it bare, so the raise takes the whole inbound message down: every message mentioning that person is dropped. Pass the replacement as a function instead — re does no template parsing on the return value, so the name lands verbatim. Same shape the Matrix adapter already uses for its outbound mention rewrite.
Contributor
|
Merged via #81738 with your commit and authorship preserved (rebase-merge, now commit 7c02bfc on main) — thanks for the clean fix and the regression tests, the lambda-replacement approach was exactly right. Closing this original since the salvage PR carried it in. Verified live: |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
SlackAdapter._humanize_user_mentionsturns Slack's opaque<@U123>tokens into@DisplayNameso the agent can tell participants apart — the fix from 5d747a9 (2026-07-22, fix(slack): humanize inbound user mentions + ground bot identity), salvaged from #55340 by @benbarclay. It resolves the name, then substitutes:The second argument to
re.subis a replacement template, not a literal —reparses backslash escapes in it. A Slack display name is arbitrary user-set text, so those backslashes are the user's characters, not regex syntax. Running the real substitution:Two distinct failures:
_handle_slack_message) is not inside anytry— I checked the enclosing function's AST, noTrynode covers it — and both Bolt handlers (@self._app.event("message")and@self._app.event("app_mention"))await self._handle_slack_message(...)bare. Sore.errorunwinds the whole inbound path: every message mentioning that person is dropped, with no reply, for as long as their name has a backslash in it. Thereply_to_textcall a few lines earlier is wrapped, which is what makes the unwrapped one easy to miss.\g<0>expands to the entire match, so the raw<@U123>gets written straight back. No error, and the agent is handed exactly the opaque token this method exists to remove — the "bot thinks it's @Someone-Else" bug the original fix was for, quietly restored for that user.The pattern side is fine:
uidcomes fromre.findall(r"<@([A-Z0-9]+)..."), so it can only be[A-Z0-9]+. Only the replacement is unsafe.The fix
Pass the replacement as a function.
reperforms no template parsing on a callable's return value, so the name lands verbatim:This is the shape the Matrix adapter already uses for its outbound mention rewrite (
_OUTBOUND_MENTION_RE.sub(lambda match: ..., protected)), so it matches existing practice rather than introducing a new convention. The default argument binds the name per iteration instead of closing over the loop variable.Names without backslashes produce byte-identical output, so the existing behaviour is untouched.
Scope: this is the only site in the Slack adapter that puts resolved user text into a replacement template — every other
re.subthere uses a literal, a group reference, or a callable — so there is no sibling to sweep.Tests
Added to
tests/gateway/test_slack_mention_humanization.py, reusing its_adapter_with_namesharness:dev\opsno longer raises and renders as@dev\opsa\1bis inserted literally instead of raising on the group reference\g<0>renders literally and the assertion"<@" not in outpins that the raw ID is never re-injectedResults:
The 3 pre-existing tests in the file are unchanged and still green.
Red without the source change (tests kept,
plugins/platforms/slack/adapter.pyreverted):Regression run over 159 test files (everything under
tests/mentioning Slack), against the same files on main:The set difference is two tests — one in
tests/honcho_plugin/test_pin_peer_name.pyand one intests/test_mcp_serve.py::TestEventBridgePollE2E— and both are flaky rather than caused by this change: run in isolation they fail 2, 1, 2 times across three consecutive runs on unmodified main and 2, 2, 1 with the fix applied. Neither touches Slack.tests/gateway/test_teams.pyis excluded from both runs: it errors at collection on an unrelated missing Teams dependency and aborts the session before any test executes.scripts/check-windows-footguns.pypasses on both changed files.