From 9912982fbb465ad59bb07cdc2ff94590948e6184 Mon Sep 17 00:00:00 2001 From: Asherah Connor Date: Thu, 6 Nov 2025 11:58:53 +1100 Subject: [PATCH 1/5] Fix accidental promotion of label content to HTML The sanitise was load-bearing, but now it needn't be, because we correctly escape the text from the non-EE label_tooltip_title before inserting it directly into HTML. --- app/helpers/labels_helper.rb | 17 +++++++---------- ee/app/helpers/ee/labels_helper.rb | 5 ++++- .../references/label_reference_filter_spec.rb | 15 ++++----------- 3 files changed, 15 insertions(+), 22 deletions(-) diff --git a/app/helpers/labels_helper.rb b/app/helpers/labels_helper.rb index 6b7dc73be88b38..9699e7ecc31ce1 100644 --- a/app/helpers/labels_helper.rb +++ b/app/helpers/labels_helper.rb @@ -1,6 +1,7 @@ # frozen_string_literal: true module LabelsHelper + include ActionView::Helpers::TagHelper extend self def show_label_issuables_link?(label, issuables_type, current_user: nil) @@ -35,7 +36,7 @@ def show_label_issuables_link?(label, issuables_type, current_user: nil) # # Customize link body with a block # link_to_label(label) { "My Custom Label Text" } # - # Returns a String + # Returns a String containing HTML. def link_to_label(label, type: :issue, tooltip: true, css_class: nil, &block) link = label.filter_path(type: type) @@ -46,6 +47,7 @@ def link_to_label(label, type: :issue, tooltip: true, css_class: nil, &block) end end + # Returns a String containing HTML. def render_label(label, link: nil, tooltip: true, dataset: nil, tooltip_shows_title: false) html = render_colored_label(label) @@ -74,7 +76,7 @@ def wrap_label_html(label_html, label:) end def label_tooltip_title(label, tooltip_shows_title: false) - Sanitize.clean(tooltip_shows_title ? label.title : label.description) + tooltip_shows_title ? label.title : label.description end def suggested_colors @@ -225,14 +227,9 @@ def render_label_link(label_html, link:, title:, dataset:) end def render_label_text(name, suffix: '', css_class: nil, bg_color: nil) - <<~HTML.chomp.html_safe - #{ERB::Util.html_escape_once(name)}#{suffix} - HTML + attrs = { "class" => css_class, "data-container" => "body", "data-html" => "true" } + attrs["style"] = "background-color: #{bg_color}" if bg_color + content_tag(:span, "#{name}#{suffix}", **attrs) end end diff --git a/ee/app/helpers/ee/labels_helper.rb b/ee/app/helpers/ee/labels_helper.rb index 26b926ccc4d5f5..b6d3b2fc4e15a5 100644 --- a/ee/app/helpers/ee/labels_helper.rb +++ b/ee/app/helpers/ee/labels_helper.rb @@ -32,7 +32,10 @@ def wrap_label_html(label_html, label:) end def label_tooltip_title(label, tooltip_shows_title: false) - tooltip = super + # Non-EE LabelsHelper#label_tooltip_title returns text. + # EE returns HTML -- see EE::Banzai::Filter::References::LabelReferenceFilter#data_attributes_for -- + # so we must escape the non-EE tooltip before including it in HTML. + tooltip = CGI.escapeHTML(super) tooltip = %(Scoped label
#{tooltip}) if label.scoped_label? tooltip diff --git a/ee/spec/lib/ee/banzai/filter/references/label_reference_filter_spec.rb b/ee/spec/lib/ee/banzai/filter/references/label_reference_filter_spec.rb index 82ef964e7bd56c..52d9a33a72b979 100644 --- a/ee/spec/lib/ee/banzai/filter/references/label_reference_filter_spec.rb +++ b/ee/spec/lib/ee/banzai/filter/references/label_reference_filter_spec.rb @@ -27,17 +27,10 @@ end it "doesn't unescape HTML in the label's title" do - # Note that this is *flawed*: ">" from the input *text* is becoming ">" in the output *HTML*. - # No XSS is possible but we are still corrupting the user's input, albeit less badly than before. - # FIXME. - expect(doc.at_css('.gl-label-scoped a').attr('title')).to include('&lt;svg id="svgId">') - - # The below is what *should* be the case, but LabelsHelper.label_tooltip_title is (incorrectly) sanitising - # instead of safely escaping the output, and LabelsHelper.render_label_text is using html_escape_once (!!), - # which is always bad! - # - # expect(doc.at_css('.gl-label-scoped a').attr('title')).to include('xss <script>alert') - # expect(doc.at_css('.gl-label-scoped a').attr('title')).to include('&<a>lt;svg id=&quot;svgId&quot;&gt;') + # The `title` attribute's DOM value is interpreted as HTML in EE, so we expect it contains the + # scoped_description escaped. + expect(doc.at_css('.gl-label-scoped a').attr('title')).to include('xss <script>alert') + expect(doc.at_css('.gl-label-scoped a').attr('title')).to include('&<a>lt;svg id=&quot;svgId&quot;&gt;') end end -- GitLab From fea0a70dd358f6d6e4861208ebbf23924481830c Mon Sep 17 00:00:00 2001 From: Asherah Connor Date: Thu, 6 Nov 2025 11:58:53 +1100 Subject: [PATCH 2/5] Fix (scoped) label confusion by splitting text and HTML methods --- app/helpers/labels_helper.rb | 6 +++++ ee/app/helpers/ee/labels_helper.rb | 11 +++----- .../references/label_reference_filter.rb | 12 ++++++++- ee/spec/helpers/ee/labels_helper_spec.rb | 24 ++++++++++++++++++ .../references/label_reference_filter.rb | 1 + spec/helpers/labels_helper_spec.rb | 25 ++++++++++++++++--- 6 files changed, 68 insertions(+), 11 deletions(-) diff --git a/app/helpers/labels_helper.rb b/app/helpers/labels_helper.rb index 9699e7ecc31ce1..2e3d933885ed05 100644 --- a/app/helpers/labels_helper.rb +++ b/app/helpers/labels_helper.rb @@ -75,10 +75,16 @@ def wrap_label_html(label_html, label:) %(#{label_html}).html_safe end + # Returns a String containing text. def label_tooltip_title(label, tooltip_shows_title: false) tooltip_shows_title ? label.title : label.description end + # Returns a string containing HTML. Overridden in EE. + def label_tooltip_title_html(label, tooltip_shows_title: false) + CGI.escapeHTML(label_tooltip_title(label, tooltip_shows_title:).to_s) + end + def suggested_colors { '#cc338b' => s_('SuggestedColors|Magenta-pink'), diff --git a/ee/app/helpers/ee/labels_helper.rb b/ee/app/helpers/ee/labels_helper.rb index b6d3b2fc4e15a5..8dec8880dfd595 100644 --- a/ee/app/helpers/ee/labels_helper.rb +++ b/ee/app/helpers/ee/labels_helper.rb @@ -31,14 +31,11 @@ def wrap_label_html(label_html, label:) %(#{label_html}).html_safe end - def label_tooltip_title(label, tooltip_shows_title: false) - # Non-EE LabelsHelper#label_tooltip_title returns text. - # EE returns HTML -- see EE::Banzai::Filter::References::LabelReferenceFilter#data_attributes_for -- - # so we must escape the non-EE tooltip before including it in HTML. - tooltip = CGI.escapeHTML(super) - tooltip = %(Scoped label
#{tooltip}) if label.scoped_label? + def label_tooltip_title_html(label, tooltip_shows_title: false) + tooltip_html = super + tooltip_html = %(Scoped label
#{tooltip_html}) if label.scoped_label? - tooltip + tooltip_html end def label_dropdown_data(edit_context, opts = {}) diff --git a/ee/lib/ee/banzai/filter/references/label_reference_filter.rb b/ee/lib/ee/banzai/filter/references/label_reference_filter.rb index 6cdab6d09621e0..48a5ba0a77b48f 100644 --- a/ee/lib/ee/banzai/filter/references/label_reference_filter.rb +++ b/ee/lib/ee/banzai/filter/references/label_reference_filter.rb @@ -11,9 +11,19 @@ module LabelReferenceFilter def data_attributes_for(original, parent, object, link_content: false, link_reference: false) return super unless object.scoped_label? - # Enabling HTML tooltips for scoped labels here. + # Causes the title (returned by `object_link_title` below) to be interpreted + # as HTML. super.merge!(html: true) end + + override :object_link_title + def object_link_title(object, _matches) + presenter = object.present(issuable_subject: project || group) + + # Return the HTML variant, which in EE includes the "Scoped label" + # prefix where applicable. + ::LabelsHelper.label_tooltip_title_html(presenter) + end end end end diff --git a/ee/spec/helpers/ee/labels_helper_spec.rb b/ee/spec/helpers/ee/labels_helper_spec.rb index cdfb7927013b46..f9e6816a27bf0d 100644 --- a/ee/spec/helpers/ee/labels_helper_spec.rb +++ b/ee/spec/helpers/ee/labels_helper_spec.rb @@ -123,4 +123,28 @@ } end end + + describe '#label_tooltip_title_html' do + let(:description) { 'This is an image' } + let(:label_with_html_content) { create(:label, title: title, description: description) } + let(:tooltip) { label_tooltip_title_html(label_with_html_content) } + + context 'when label is unscoped' do + let(:title) { 'test' } + + it 'escapes HTML for display' do + expect(tooltip).to eq('<img src="example.png">This is an image</img>') + end + end + + context 'when label is scoped' do + let(:title) { 'scope::test' } + + it 'includes scoped label tag and escapes HTML for display' do + expect(tooltip).to eq( + "Scoped label
" \ + '<img src="example.png">This is an image</img>') + end + end + end end diff --git a/lib/banzai/filter/references/label_reference_filter.rb b/lib/banzai/filter/references/label_reference_filter.rb index 07ad15247528d0..869c651fdc4aae 100644 --- a/lib/banzai/filter/references/label_reference_filter.rb +++ b/lib/banzai/filter/references/label_reference_filter.rb @@ -146,6 +146,7 @@ def reference_class(type, tooltip: true) super + ' gl-link gl-label-link' end + # Returns a String containing text. def object_link_title(object, matches) presenter = object.present(issuable_subject: project || group) LabelsHelper.label_tooltip_title(presenter) diff --git a/spec/helpers/labels_helper_spec.rb b/spec/helpers/labels_helper_spec.rb index ed3467eb96c37b..e2b300f322e8a2 100644 --- a/spec/helpers/labels_helper_spec.rb +++ b/spec/helpers/labels_helper_spec.rb @@ -237,20 +237,39 @@ let(:label_with_html_content) { create(:label, title: 'test', description: html) } context 'tooltip shows description' do - it 'removes HTML' do + it 'leaves HTML untouched' do tooltip = label_tooltip_title(label_with_html_content) - expect(tooltip).to eq('This is an image') + expect(tooltip).to eq(html) end end context 'tooltip shows title' do - it 'shows title' do + it 'returns title' do tooltip = label_tooltip_title(label_with_html_content, tooltip_shows_title: true) expect(tooltip).to eq('test') end end end + describe '#label_tooltip_title_html' do + let(:html) { 'This is an image' } + let(:label_with_html_content) { create(:label, title: 'test', description: html) } + + context 'tooltip shows description' do + it 'escapes HTML for display' do + tooltip = label_tooltip_title_html(label_with_html_content) + expect(tooltip).to eq('<img src="example.png">This is an image</img>') + end + end + + context 'tooltip shows title' do + it 'shows title' do + tooltip = label_tooltip_title_html(label_with_html_content, tooltip_shows_title: true) + expect(tooltip).to eq('test') + end + end + end + describe '#show_labels_full_path?' do let_it_be(:group) { create(:group) } let_it_be(:subgroup) { create(:group, parent: group) } -- GitLab From 3712b2f5b1c0a6521bb998c32ab5d41d99153a52 Mon Sep 17 00:00:00 2001 From: Asherah Connor Date: Thu, 6 Nov 2025 13:49:36 +1100 Subject: [PATCH 3/5] Be clear that this suffix is HTML --- app/helpers/labels_helper.rb | 9 +++++---- ee/app/helpers/ee/labels_helper.rb | 4 ++-- lib/banzai/filter/references/label_reference_filter.rb | 6 +++--- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/app/helpers/labels_helper.rb b/app/helpers/labels_helper.rb index 2e3d933885ed05..7f9b507ca0ca01 100644 --- a/app/helpers/labels_helper.rb +++ b/app/helpers/labels_helper.rb @@ -59,10 +59,11 @@ def render_label(label, link: nil, tooltip: true, dataset: nil, tooltip_shows_ti wrap_label_html(html, label: label) end - def render_colored_label(label, suffix: '') + # Renders a label, with the given suffix HTML. + def render_colored_label(label, suffix_html: '') render_label_text( label.name, - suffix: suffix, + suffix_html: suffix_html, css_class: "gl-label-text #{label.text_color_class}", bg_color: label.color ) @@ -232,10 +233,10 @@ def render_label_link(label_html, link:, title:, dataset:) link_to(label_html, link, class: classes.join(' '), data: dataset) end - def render_label_text(name, suffix: '', css_class: nil, bg_color: nil) + def render_label_text(name, suffix_html: '', css_class: nil, bg_color: nil) attrs = { "class" => css_class, "data-container" => "body", "data-html" => "true" } attrs["style"] = "background-color: #{bg_color}" if bg_color - content_tag(:span, "#{name}#{suffix}", **attrs) + content_tag(:span, "#{CGI.escapeHTML(name)}#{suffix_html}".html_safe, **attrs) end end diff --git a/ee/app/helpers/ee/labels_helper.rb b/ee/app/helpers/ee/labels_helper.rb index 8dec8880dfd595..54b320deda49ce 100644 --- a/ee/app/helpers/ee/labels_helper.rb +++ b/ee/app/helpers/ee/labels_helper.rb @@ -8,7 +8,7 @@ module LabelsHelper singleton_class.prepend self end - def render_colored_label(label, suffix: '') + def render_colored_label(label, suffix_html: '') return super unless label.scoped_label? render_label_text( @@ -18,7 +18,7 @@ def render_colored_label(label, suffix: '') ) + render_label_text( label.scoped_label_value, css_class: "gl-label-text-scoped", - suffix: suffix + suffix_html: suffix_html ) end diff --git a/lib/banzai/filter/references/label_reference_filter.rb b/lib/banzai/filter/references/label_reference_filter.rb index 869c651fdc4aae..a4cfdc17435102 100644 --- a/lib/banzai/filter/references/label_reference_filter.rb +++ b/lib/banzai/filter/references/label_reference_filter.rb @@ -118,7 +118,7 @@ def url_for_object(label, parent) end def object_link_text(object, matches) - label_suffix = '' + label_suffix_html = '' parent = project || group if matches[:absolute_path].blank? && (project || full_path_ref?(matches)) @@ -126,11 +126,11 @@ def object_link_text(object, matches) parent_from_ref = from_ref_cached(project_path) reference = parent_from_ref.to_human_reference(parent) - label_suffix = " in #{ERB::Util.html_escape(reference)}" if reference.present? + label_suffix_html = " in #{ERB::Util.html_escape(reference)}" if reference.present? end presenter = object.present(issuable_subject: parent) - LabelsHelper.render_colored_label(presenter, suffix: label_suffix) + LabelsHelper.render_colored_label(presenter, suffix_html: label_suffix_html) end def wrap_link(link, label) -- GitLab From 74d7043c7aac497b3fcdea2680d983c872ae5154 Mon Sep 17 00:00:00 2001 From: Asherah Connor Date: Tue, 11 Nov 2025 14:40:02 +1100 Subject: [PATCH 4/5] EE-only label_tooltip_title_html and make HTMLification unconditional We don't need multiple codepaths here, so let's not have them. --- app/helpers/labels_helper.rb | 5 ----- ee/app/helpers/ee/labels_helper.rb | 5 +++-- .../references/label_reference_filter.rb | 5 +---- .../references/label_reference_filter_spec.rb | 17 +++++++++++------ spec/helpers/labels_helper_spec.rb | 19 ------------------- 5 files changed, 15 insertions(+), 36 deletions(-) diff --git a/app/helpers/labels_helper.rb b/app/helpers/labels_helper.rb index 7f9b507ca0ca01..3c13b1f01e2e76 100644 --- a/app/helpers/labels_helper.rb +++ b/app/helpers/labels_helper.rb @@ -81,11 +81,6 @@ def label_tooltip_title(label, tooltip_shows_title: false) tooltip_shows_title ? label.title : label.description end - # Returns a string containing HTML. Overridden in EE. - def label_tooltip_title_html(label, tooltip_shows_title: false) - CGI.escapeHTML(label_tooltip_title(label, tooltip_shows_title:).to_s) - end - def suggested_colors { '#cc338b' => s_('SuggestedColors|Magenta-pink'), diff --git a/ee/app/helpers/ee/labels_helper.rb b/ee/app/helpers/ee/labels_helper.rb index 54b320deda49ce..4b10bc83850e7f 100644 --- a/ee/app/helpers/ee/labels_helper.rb +++ b/ee/app/helpers/ee/labels_helper.rb @@ -31,8 +31,9 @@ def wrap_label_html(label_html, label:) %(#{label_html}).html_safe end - def label_tooltip_title_html(label, tooltip_shows_title: false) - tooltip_html = super + # Returns a String containing HTML. + def label_tooltip_title_html(label) + tooltip_html = CGI.escapeHTML(label_tooltip_title(label).to_s) tooltip_html = %(Scoped label
#{tooltip_html}) if label.scoped_label? tooltip_html diff --git a/ee/lib/ee/banzai/filter/references/label_reference_filter.rb b/ee/lib/ee/banzai/filter/references/label_reference_filter.rb index 48a5ba0a77b48f..8bee34df542ad8 100644 --- a/ee/lib/ee/banzai/filter/references/label_reference_filter.rb +++ b/ee/lib/ee/banzai/filter/references/label_reference_filter.rb @@ -9,19 +9,16 @@ module LabelReferenceFilter override :data_attributes_for def data_attributes_for(original, parent, object, link_content: false, link_reference: false) - return super unless object.scoped_label? - # Causes the title (returned by `object_link_title` below) to be interpreted # as HTML. super.merge!(html: true) end + # Returns a String containing HTML. override :object_link_title def object_link_title(object, _matches) presenter = object.present(issuable_subject: project || group) - # Return the HTML variant, which in EE includes the "Scoped label" - # prefix where applicable. ::LabelsHelper.label_tooltip_title_html(presenter) end end diff --git a/ee/spec/lib/ee/banzai/filter/references/label_reference_filter_spec.rb b/ee/spec/lib/ee/banzai/filter/references/label_reference_filter_spec.rb index 52d9a33a72b979..1e87e7f467f313 100644 --- a/ee/spec/lib/ee/banzai/filter/references/label_reference_filter_spec.rb +++ b/ee/spec/lib/ee/banzai/filter/references/label_reference_filter_spec.rb @@ -6,9 +6,9 @@ include FilterSpecHelper let(:project) { create(:project, :public, name: 'sample-project') } - let(:label) { create(:label, name: 'label', project: project) } - let(:scoped_description) { 'xss &lt;svg id="svgId"></svg>' } - let(:scoped_label) { create(:label, name: 'key::value', project: project, description: scoped_description) } + let(:description) { 'xss &lt;svg id="svgId"></svg>' } + let(:label) { create(:label, name: 'label', project: project, description: description) } + let(:scoped_label) { create(:label, name: 'key::value', project: project, description: description) } context 'with scoped labels enabled' do before do @@ -28,7 +28,7 @@ it "doesn't unescape HTML in the label's title" do # The `title` attribute's DOM value is interpreted as HTML in EE, so we expect it contains the - # scoped_description escaped. + # description escaped. expect(doc.at_css('.gl-label-scoped a').attr('title')).to include('xss <script>alert') expect(doc.at_css('.gl-label-scoped a').attr('title')).to include('&<a>lt;svg id=&quot;svgId&quot;&gt;') end @@ -41,8 +41,13 @@ expect(doc.css('.gl-label .gl-label-text').map(&:text)).to eq([label.name]) end - it 'renders non-HTML tooltips' do - expect(doc.at_css('.gl-label a').attr('data-html')).to be_nil + it 'renders HTML tooltips' do + expect(doc.at_css('.gl-label a').attr('data-html')).to eq('true') + end + + it "doesn't unescape HTML in the label's title" do + expect(doc.at_css('.gl-label a').attr('title')).to include('xss <script>alert') + expect(doc.at_css('.gl-label a').attr('title')).to include('&<a>lt;svg id=&quot;svgId&quot;&gt;') end end end diff --git a/spec/helpers/labels_helper_spec.rb b/spec/helpers/labels_helper_spec.rb index e2b300f322e8a2..82ebeaa63c3b7e 100644 --- a/spec/helpers/labels_helper_spec.rb +++ b/spec/helpers/labels_helper_spec.rb @@ -251,25 +251,6 @@ end end - describe '#label_tooltip_title_html' do - let(:html) { 'This is an image' } - let(:label_with_html_content) { create(:label, title: 'test', description: html) } - - context 'tooltip shows description' do - it 'escapes HTML for display' do - tooltip = label_tooltip_title_html(label_with_html_content) - expect(tooltip).to eq('<img src="example.png">This is an image</img>') - end - end - - context 'tooltip shows title' do - it 'shows title' do - tooltip = label_tooltip_title_html(label_with_html_content, tooltip_shows_title: true) - expect(tooltip).to eq('test') - end - end - end - describe '#show_labels_full_path?' do let_it_be(:group) { create(:group) } let_it_be(:subgroup) { create(:group, parent: group) } -- GitLab From 792b37d3a55fed6eb20c4a82b999fe1e6307b9f2 Mon Sep 17 00:00:00 2001 From: Asherah Connor Date: Tue, 11 Nov 2025 15:21:54 +1100 Subject: [PATCH 5/5] Pass reference name to HTML helper, let it append tag --- app/helpers/labels_helper.rb | 11 +++++++---- ee/app/helpers/ee/labels_helper.rb | 4 ++-- .../filter/references/label_reference_filter.rb | 6 ++---- .../filter/references/label_reference_filter_spec.rb | 12 +++++++++++- 4 files changed, 22 insertions(+), 11 deletions(-) diff --git a/app/helpers/labels_helper.rb b/app/helpers/labels_helper.rb index 3c13b1f01e2e76..0b21ee4fccc99e 100644 --- a/app/helpers/labels_helper.rb +++ b/app/helpers/labels_helper.rb @@ -60,10 +60,10 @@ def render_label(label, link: nil, tooltip: true, dataset: nil, tooltip_shows_ti end # Renders a label, with the given suffix HTML. - def render_colored_label(label, suffix_html: '') + def render_colored_label(label, in_reference: nil) render_label_text( label.name, - suffix_html: suffix_html, + in_reference: in_reference, css_class: "gl-label-text #{label.text_color_class}", bg_color: label.color ) @@ -228,10 +228,13 @@ def render_label_link(label_html, link:, title:, dataset:) link_to(label_html, link, class: classes.join(' '), data: dataset) end - def render_label_text(name, suffix_html: '', css_class: nil, bg_color: nil) + def render_label_text(name, in_reference: nil, css_class: nil, bg_color: nil) + label_name_html = CGI.escapeHTML(name) + label_name_html << " " << content_tag(:i, "in #{in_reference}") if in_reference.present? + attrs = { "class" => css_class, "data-container" => "body", "data-html" => "true" } attrs["style"] = "background-color: #{bg_color}" if bg_color - content_tag(:span, "#{CGI.escapeHTML(name)}#{suffix_html}".html_safe, **attrs) + content_tag(:span, label_name_html.html_safe, **attrs) end end diff --git a/ee/app/helpers/ee/labels_helper.rb b/ee/app/helpers/ee/labels_helper.rb index 4b10bc83850e7f..bc898baec84e72 100644 --- a/ee/app/helpers/ee/labels_helper.rb +++ b/ee/app/helpers/ee/labels_helper.rb @@ -8,7 +8,7 @@ module LabelsHelper singleton_class.prepend self end - def render_colored_label(label, suffix_html: '') + def render_colored_label(label, in_reference: nil) return super unless label.scoped_label? render_label_text( @@ -18,7 +18,7 @@ def render_colored_label(label, suffix_html: '') ) + render_label_text( label.scoped_label_value, css_class: "gl-label-text-scoped", - suffix_html: suffix_html + in_reference: in_reference ) end diff --git a/lib/banzai/filter/references/label_reference_filter.rb b/lib/banzai/filter/references/label_reference_filter.rb index a4cfdc17435102..9b89c1ad84e706 100644 --- a/lib/banzai/filter/references/label_reference_filter.rb +++ b/lib/banzai/filter/references/label_reference_filter.rb @@ -118,19 +118,17 @@ def url_for_object(label, parent) end def object_link_text(object, matches) - label_suffix_html = '' + reference = nil parent = project || group if matches[:absolute_path].blank? && (project || full_path_ref?(matches)) project_path = reference_cache.full_project_path(matches[:namespace], matches[:project], matches) parent_from_ref = from_ref_cached(project_path) reference = parent_from_ref.to_human_reference(parent) - - label_suffix_html = " in #{ERB::Util.html_escape(reference)}" if reference.present? end presenter = object.present(issuable_subject: parent) - LabelsHelper.render_colored_label(presenter, suffix_html: label_suffix_html) + LabelsHelper.render_colored_label(presenter, in_reference: reference) end def wrap_link(link, label) diff --git a/spec/lib/banzai/filter/references/label_reference_filter_spec.rb b/spec/lib/banzai/filter/references/label_reference_filter_spec.rb index f66af715a99000..fd25cc99bf62d2 100644 --- a/spec/lib/banzai/filter/references/label_reference_filter_spec.rb +++ b/spec/lib/banzai/filter/references/label_reference_filter_spec.rb @@ -439,13 +439,23 @@ end it 'has valid color' do - expect(result.css('a span').first.attr('style')).to match(/background-color: #00ff00/) + expect(result.css('a span').first.attr('style')).to match('background-color: #00ff00') end it 'has valid link text' do expect(result.css('a').first.text).to eq "#{label.name} in #{project2.full_name}" end + it 'has correct HTML content' do + frag = Nokogiri::HTML.fragment("") + span = frag.children.first + span.content = "#{label.name} " + span << i = frag.document.create_element("i") + i.content = "in #{project2.full_name}" + + expect(result.css('a').first.to_html).to include_html(span.inner_html) + end + it 'has valid text' do expect(result.text).to eq "See #{label.name} in #{project2.full_name}" end -- GitLab