diff --git a/app/assets/javascripts/whats_new/components/feature.vue b/app/assets/javascripts/whats_new/components/feature.vue index 5444e77a4d2cde54aac12291710adbbccc4cde9e..11096b0803232d8412bf53e9619e8c10858ed77a 100644 --- a/app/assets/javascripts/whats_new/components/feature.vue +++ b/app/assets/javascripts/whats_new/components/feature.vue @@ -30,6 +30,7 @@ export default { return dateInWords(date); }, }, + safeHtmlConfig: { ADD_ATTR: ['target'] }, }; </script> @@ -71,7 +72,10 @@ export default { <gl-icon name="license" />{{ packageName }} </gl-badge> </div> - <div v-safe-html="feature.body" class="gl-pt-3 gl-line-height-20"></div> + <div + v-safe-html:[$options.safeHtmlConfig]="feature.body" + class="gl-pt-3 gl-line-height-20" + ></div> <gl-button :href="feature.url" target="_blank" diff --git a/app/models/release_highlight.rb b/app/models/release_highlight.rb index 9c30d0611e6d5aa7d8e860c00f976911ec4963a7..84e0a43670b7885bae4d616f85f47fedc5ee48b8 100644 --- a/app/models/release_highlight.rb +++ b/app/models/release_highlight.rb @@ -33,7 +33,7 @@ def self.load_items(page:) next unless include_item?(item) begin - item.tap {|i| i['body'] = Kramdown::Document.new(i['body']).to_html } + item.tap {|i| i['body'] = Banzai.render(i['body'], { project: nil }) } rescue StandardError => e Gitlab::ErrorTracking.track_exception(e, file_path: file_path) diff --git a/spec/fixtures/whats_new/20201225_01_05.yml b/spec/fixtures/whats_new/20201225_01_05.yml index 27c8f989b085eb4c8a019ba9744db20b7f7adb24..d707502af54df954d595db955b3d3c5cc99e90cf 100644 --- a/spec/fixtures/whats_new/20201225_01_05.yml +++ b/spec/fixtures/whats_new/20201225_01_05.yml @@ -1,7 +1,7 @@ --- - title: bright and sunshinin' day body: | - ## bright and sunshinin' day + bright and sunshinin' [day](https://en.wikipedia.org/wiki/Day) self-managed: true gitlab-com: false packages: ["Premium", "Ultimate"] diff --git a/spec/frontend/whats_new/components/feature_spec.js b/spec/frontend/whats_new/components/feature_spec.js index 9e9cb59c0d687a6547cd33a3a6719d44719ed965..8f4b4b08f5067b895f0f07989515ec7d97978bf2 100644 --- a/spec/frontend/whats_new/components/feature_spec.js +++ b/spec/frontend/whats_new/components/feature_spec.js @@ -8,7 +8,7 @@ describe("What's new single feature", () => { const exampleFeature = { title: 'Compliance pipeline configurations', body: - '<p>We are thrilled to announce that it is now possible to define enforceable pipelines that will run for any project assigned a corresponding compliance framework.</p>', + '<p data-testid="body-content">We are thrilled to announce that it is now possible to define enforceable pipelines that will run for any project assigned a corresponding <a href="https://en.wikipedia.org/wiki/Compliance_(psychology)" target="_blank" rel="noopener noreferrer" onload="alert(xss)">compliance</a> framework.</p>', stage: 'Manage', 'self-managed': true, 'gitlab-com': true, @@ -20,6 +20,7 @@ describe("What's new single feature", () => { }; const findReleaseDate = () => wrapper.find('[data-testid="release-date"]'); + const findBodyAnchor = () => wrapper.find('[data-testid="body-content"] a'); const createWrapper = ({ feature } = {}) => { wrapper = shallowMount(Feature, { @@ -43,4 +44,13 @@ describe("What's new single feature", () => { expect(findReleaseDate().exists()).toBe(false); }); }); + + it('safe-html config allows target attribute on elements', () => { + createWrapper({ feature: exampleFeature }); + expect(findBodyAnchor().attributes()).toEqual({ + href: expect.any(String), + rel: 'noopener noreferrer', + target: '_blank', + }); + }); }); diff --git a/spec/models/release_highlight_spec.rb b/spec/models/release_highlight_spec.rb index b4dff4c33ff61d3f6dfce71eec06fe6caea59ad3..a5441e2f47bd4da3016e93fd112217add7851237 100644 --- a/spec/models/release_highlight_spec.rb +++ b/spec/models/release_highlight_spec.rb @@ -67,12 +67,12 @@ expect(subject[:next_page]).to eq(2) end - it 'parses the body as markdown and returns html' do - expect(subject[:items].first['body']).to match("<h2 id=\"bright-and-sunshinin-day\">bright and sunshinin’ day</h2>") + it 'parses the body as markdown and returns html, and links are target="_blank"' do + expect(subject[:items].first['body']).to match('<p data-sourcepos="1:1-1:62" dir="auto">bright and sunshinin\' <a href="https://en.wikipedia.org/wiki/Day" rel="nofollow noreferrer noopener" target="_blank">day</a></p>') end it 'logs an error if theres an error parsing markdown for an item, and skips it' do - allow(Kramdown::Document).to receive(:new).and_raise + allow(Banzai).to receive(:render).and_raise expect(Gitlab::ErrorTracking).to receive(:track_exception) expect(subject[:items]).to be_empty