2019-10-12 21:52:04 +05:30
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2016-08-24 12:49:21 +05:30
|
|
|
require 'spec_helper'
|
|
|
|
|
2023-04-23 21:23:45 +05:30
|
|
|
RSpec.describe Banzai::ReferenceRedactor, feature_category: :team_planning do
|
2018-03-27 19:54:05 +05:30
|
|
|
let(:user) { create(:user) }
|
2017-09-10 17:25:29 +05:30
|
|
|
let(:project) { build(:project) }
|
2018-05-09 12:01:36 +05:30
|
|
|
let(:redactor) { described_class.new(Banzai::RenderContext.new(project, user)) }
|
2016-08-24 12:49:21 +05:30
|
|
|
|
|
|
|
describe '#redact' do
|
2017-08-17 22:00:37 +05:30
|
|
|
context 'when reference not visible to user' do
|
|
|
|
before do
|
|
|
|
expect(redactor).to receive(:nodes_visible_to_user).and_return([])
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'redacts an array of documents' do
|
2017-09-10 17:25:29 +05:30
|
|
|
doc1 = Nokogiri::HTML
|
2019-06-05 12:25:43 +05:30
|
|
|
.fragment('<a class="gfm" href="https://www.gitlab.com" data-reference-type="issue">foo</a>')
|
2017-08-17 22:00:37 +05:30
|
|
|
|
2017-09-10 17:25:29 +05:30
|
|
|
doc2 = Nokogiri::HTML
|
2019-06-05 12:25:43 +05:30
|
|
|
.fragment('<a class="gfm" href="https://www.gitlab.com" data-reference-type="issue">bar</a>')
|
2017-08-17 22:00:37 +05:30
|
|
|
|
|
|
|
redacted_data = redactor.redact([doc1, doc2])
|
|
|
|
|
|
|
|
expect(redacted_data.map { |data| data[:document] }).to eq([doc1, doc2])
|
|
|
|
expect(redacted_data.map { |data| data[:visible_reference_count] }).to eq([0, 0])
|
|
|
|
expect(doc1.to_html).to eq('foo')
|
|
|
|
expect(doc2.to_html).to eq('bar')
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'replaces redacted reference with inner HTML' do
|
2019-06-05 12:25:43 +05:30
|
|
|
doc = Nokogiri::HTML.fragment("<a class='gfm' href='https://www.gitlab.com' data-reference-type='issue'>foo</a>")
|
2017-08-17 22:00:37 +05:30
|
|
|
redactor.redact([doc])
|
|
|
|
expect(doc.to_html).to eq('foo')
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when data-original attribute provided' do
|
2022-04-01 21:47:47 +05:30
|
|
|
let(:original_content) { '<script>alert(1);</script>' }
|
2020-01-01 13:55:28 +05:30
|
|
|
|
2017-08-17 22:00:37 +05:30
|
|
|
it 'replaces redacted reference with original content' do
|
2019-06-05 12:25:43 +05:30
|
|
|
doc = Nokogiri::HTML.fragment("<a class='gfm' href='https://www.gitlab.com' data-reference-type='issue' data-original='#{original_content}'>bar</a>")
|
2017-08-17 22:00:37 +05:30
|
|
|
redactor.redact([doc])
|
|
|
|
expect(doc.to_html).to eq(original_content)
|
|
|
|
end
|
2018-03-27 19:54:05 +05:30
|
|
|
|
2019-06-05 12:25:43 +05:30
|
|
|
it 'does not replace redacted reference with original content if href is given' do
|
|
|
|
html = "<a href='https://www.gitlab.com' data-link-reference='true' class='gfm' data-reference-type='issue' data-reference-type='issue' data-original='Marge'>Marge</a>"
|
|
|
|
doc = Nokogiri::HTML.fragment(html)
|
|
|
|
redactor.redact([doc])
|
|
|
|
expect(doc.to_html).to eq('<a href="https://www.gitlab.com">Marge</a>')
|
|
|
|
end
|
2018-03-27 19:54:05 +05:30
|
|
|
|
2019-06-05 12:25:43 +05:30
|
|
|
it 'uses the original content as the link content if given' do
|
|
|
|
html = "<a href='https://www.gitlab.com' data-link-reference='true' class='gfm' data-reference-type='issue' data-reference-type='issue' data-original='Homer'>Marge</a>"
|
|
|
|
doc = Nokogiri::HTML.fragment(html)
|
|
|
|
redactor.redact([doc])
|
|
|
|
expect(doc.to_html).to eq('<a href="https://www.gitlab.com">Homer</a>')
|
|
|
|
end
|
2018-03-27 19:54:05 +05:30
|
|
|
end
|
2017-08-17 22:00:37 +05:30
|
|
|
end
|
|
|
|
|
|
|
|
context 'when project is in pending delete' do
|
|
|
|
let!(:issue) { create(:issue, project: project) }
|
2018-05-09 12:01:36 +05:30
|
|
|
let(:redactor) { described_class.new(Banzai::RenderContext.new(project, user)) }
|
2017-08-17 22:00:37 +05:30
|
|
|
|
|
|
|
before do
|
2021-04-29 21:17:54 +05:30
|
|
|
project.update!(pending_delete: true)
|
2017-08-17 22:00:37 +05:30
|
|
|
end
|
|
|
|
|
|
|
|
it 'redacts an issue attached' do
|
2019-06-05 12:25:43 +05:30
|
|
|
doc = Nokogiri::HTML.fragment("<a class='gfm' href='https://www.gitlab.com' data-reference-type='issue' data-issue='#{issue.id}'>foo</a>")
|
2017-08-17 22:00:37 +05:30
|
|
|
|
|
|
|
redactor.redact([doc])
|
2016-08-24 12:49:21 +05:30
|
|
|
|
2017-08-17 22:00:37 +05:30
|
|
|
expect(doc.to_html).to eq('foo')
|
|
|
|
end
|
2016-08-24 12:49:21 +05:30
|
|
|
|
2017-08-17 22:00:37 +05:30
|
|
|
it 'redacts an external issue' do
|
2019-06-05 12:25:43 +05:30
|
|
|
doc = Nokogiri::HTML.fragment("<a class='gfm' href='https://www.gitlab.com' data-reference-type='issue' data-external-issue='#{issue.id}' data-project='#{project.id}'>foo</a>")
|
2016-08-24 12:49:21 +05:30
|
|
|
|
2017-08-17 22:00:37 +05:30
|
|
|
redactor.redact([doc])
|
2016-08-24 12:49:21 +05:30
|
|
|
|
2017-08-17 22:00:37 +05:30
|
|
|
expect(doc.to_html).to eq('foo')
|
|
|
|
end
|
2016-08-24 12:49:21 +05:30
|
|
|
end
|
|
|
|
|
2017-08-17 22:00:37 +05:30
|
|
|
context 'when reference visible to user' do
|
|
|
|
it 'does not redact an array of documents' do
|
|
|
|
doc1_html = '<a class="gfm" data-reference-type="issue">foo</a>'
|
|
|
|
doc1 = Nokogiri::HTML.fragment(doc1_html)
|
2016-08-24 12:49:21 +05:30
|
|
|
|
2017-08-17 22:00:37 +05:30
|
|
|
doc2_html = '<a class="gfm" data-reference-type="issue">bar</a>'
|
|
|
|
doc2 = Nokogiri::HTML.fragment(doc2_html)
|
2016-08-24 12:49:21 +05:30
|
|
|
|
2017-08-17 22:00:37 +05:30
|
|
|
nodes = redactor.document_nodes([doc1, doc2]).map { |x| x[:nodes] }
|
|
|
|
expect(redactor).to receive(:nodes_visible_to_user).and_return(nodes.flatten)
|
2016-08-24 12:49:21 +05:30
|
|
|
|
2017-08-17 22:00:37 +05:30
|
|
|
redacted_data = redactor.redact([doc1, doc2])
|
2016-08-24 12:49:21 +05:30
|
|
|
|
2017-08-17 22:00:37 +05:30
|
|
|
expect(redacted_data.map { |data| data[:document] }).to eq([doc1, doc2])
|
|
|
|
expect(redacted_data.map { |data| data[:visible_reference_count] }).to eq([1, 1])
|
|
|
|
expect(doc1.to_html).to eq(doc1_html)
|
|
|
|
expect(doc2.to_html).to eq(doc2_html)
|
|
|
|
end
|
2016-08-24 12:49:21 +05:30
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2018-03-27 19:54:05 +05:30
|
|
|
context 'when the user cannot read cross project' do
|
|
|
|
let(:project) { create(:project) }
|
|
|
|
let(:other_project) { create(:project, :public) }
|
|
|
|
|
|
|
|
def create_link(issuable)
|
|
|
|
type = issuable.class.name.underscore.downcase
|
2023-06-20 00:43:36 +05:30
|
|
|
ActionController::Base.helpers.link_to(
|
|
|
|
issuable.to_reference,
|
|
|
|
'',
|
|
|
|
class: 'gfm has-tooltip',
|
|
|
|
title: issuable.title,
|
|
|
|
data: {
|
|
|
|
reference_type: type,
|
|
|
|
"#{type}": issuable.id
|
|
|
|
}
|
|
|
|
)
|
2018-03-27 19:54:05 +05:30
|
|
|
end
|
|
|
|
|
|
|
|
before do
|
|
|
|
project.add_developer(user)
|
|
|
|
|
|
|
|
allow(Ability).to receive(:allowed?).and_call_original
|
|
|
|
allow(Ability).to receive(:allowed?).with(user, :read_cross_project, :global) { false }
|
|
|
|
allow(Ability).to receive(:allowed?).with(user, :read_cross_project) { false }
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'skips links to issues within the same project' do
|
|
|
|
issue = create(:issue, project: project)
|
|
|
|
link = create_link(issue)
|
|
|
|
doc = Nokogiri::HTML.fragment(link)
|
|
|
|
|
|
|
|
redactor.redact([doc])
|
|
|
|
result = doc.css('a').last
|
|
|
|
|
|
|
|
expect(result['class']).to include('has-tooltip')
|
|
|
|
expect(result['title']).to eq(issue.title)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'removes info from a cross project reference' do
|
|
|
|
issue = create(:issue, project: other_project)
|
|
|
|
link = create_link(issue)
|
|
|
|
doc = Nokogiri::HTML.fragment(link)
|
|
|
|
|
|
|
|
redactor.redact([doc])
|
|
|
|
result = doc.css('a').last
|
|
|
|
|
|
|
|
expect(result['class']).not_to include('has-tooltip')
|
|
|
|
expect(result['title']).to be_empty
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2016-08-24 12:49:21 +05:30
|
|
|
describe '#redact_nodes' do
|
|
|
|
it 'redacts an Array of nodes' do
|
|
|
|
doc = Nokogiri::HTML.fragment('<a href="foo">foo</a>')
|
|
|
|
node = doc.children[0]
|
|
|
|
|
2017-09-10 17:25:29 +05:30
|
|
|
expect(redactor).to receive(:nodes_visible_to_user)
|
|
|
|
.with([node])
|
|
|
|
.and_return(Set.new)
|
2016-08-24 12:49:21 +05:30
|
|
|
|
|
|
|
redactor.redact_document_nodes([{ document: doc, nodes: [node] }])
|
|
|
|
|
|
|
|
expect(doc.to_html).to eq('foo')
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
describe '#nodes_visible_to_user' do
|
|
|
|
it 'returns a Set containing the visible nodes' do
|
|
|
|
doc = Nokogiri::HTML.fragment('<a data-reference-type="issue"></a>')
|
|
|
|
node = doc.children[0]
|
|
|
|
|
2020-01-01 13:55:28 +05:30
|
|
|
expect_next_instance_of(Banzai::ReferenceParser::IssueParser) do |instance|
|
|
|
|
expect(instance).to receive(:nodes_visible_to_user)
|
|
|
|
.with(user, [node])
|
|
|
|
.and_return([node])
|
|
|
|
end
|
2016-08-24 12:49:21 +05:30
|
|
|
|
|
|
|
expect(redactor.nodes_visible_to_user([node])).to eq(Set.new([node]))
|
|
|
|
end
|
2021-01-03 14:25:43 +05:30
|
|
|
|
|
|
|
it 'handles invalid references gracefully' do
|
|
|
|
doc = Nokogiri::HTML.fragment('<a data-reference-type="some_invalid_type"></a>')
|
|
|
|
node = doc.children[0]
|
|
|
|
|
|
|
|
expect(redactor.nodes_visible_to_user([node])).to be_empty
|
|
|
|
end
|
2016-08-24 12:49:21 +05:30
|
|
|
end
|
|
|
|
end
|