Send user-written link markup as plain text in Slack notifications
What does this MR do and why?
What does this MR do and why?
GitLab posts chat notifications and slash command responses to Slack. Slack renders a <url|label> token as a link that shows only the label, with no hover preview of the destination. So these messages are conservative about which text becomes a link: links GitLab builds itself (issue, project, pipeline) stay clickable, and user-written text is sent as plain text.
- Send user-written text in issue and incident descriptions, note bodies, wiki page messages, and group mention text as written. Angle brackets are escaped and link markup (HTML anchors, Markdown links, raw
<url|label>tokens) is not converted. The webhook notifier no longer uses the slack-messenger gem's link formatting middleware, because links are converted while the message is built. The GitLab for Slack app posts the same attachments directly. - Escape
<url|label>tokens that contain more than one pipe in the sanitizer used for integrations that render Markdown themselves. - Strip link markup from slash command responses: issue titles, assignee names, milestone titles, label names, the attachment author name, the plain-text fallback summary, and the project name in pretexts. In a personal namespace the project name includes the owner's display name. This matches chat notifications.
References
Issue: https://gitlab.com/gitlab-org/gitlab/-/work_items/593573 (confidential). Background and discussion are in that issue.
Screenshots or screen recordings
Not applicable.
How to set up and validate locally
Option A: without a Slack workspace
-
In
bin/rails console, build a notification message and inspect the attachment text:description = <<~TEXT <a href="https://example.org/one">https://example.com/two</a> [https://example.com/two](https://example.org/one) <https://example.org/one|https://example.com/two|extra> TEXT message = Integrations::ChatMessage::IssueMessage.new( object_kind: 'issue', user: { name: 'Dev', username: 'dev' }, project_name: 'group/project', project_url: 'https://gitlab.example.com/group/project', object_attributes: { title: 'Title', iid: 1, action: 'open', state: 'opened', url: 'https://gitlab.example.com/group/project/-/issues/1', description: description } ) puts message.attachments.first[:text] -
Expected:
<a href="https://example.org/one">https://example.com/two</a> [https://example.com/two](https://example.org/one) <https://example.org/one|https://example.com/two|extra>None of the three is a
<url|label>token, so Slack shows them as text and only auto-links the bare URLs to themselves.
Option B: with a Slack or Mattermost integration configured on a project
- Create an issue whose description contains the three lines above and confirm the posted message shows them as plain text, with only the bare URLs auto-linked to themselves.
- With Slack slash commands or the GitLab for Slack app configured, create an issue whose title contains
<https://example.org/one|https://example.com/two>, run/gitlab issue search two, and confirm the response shows the title text without a clickable link.
Specs to run (the first command must run separately from the others because that spec uses fast_spec_helper):
bin/rspec spec/lib/slack_markdown_sanitizer_spec.rbbin/rspec spec/lib/gitlab/slash_commands/presenters spec/models/integrations/chat_message
bin/rspec spec/models/integrations/slack_spec.rb spec/models/integrations/mattermost_spec.rbMR acceptance checklist
Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.