diff options
author | Bob Van Landuyt <bob@vanlanduyt.co> | 2018-10-01 18:49:43 +0200 |
---|---|---|
committer | Bob Van Landuyt <bob@vanlanduyt.co> | 2018-10-01 18:49:43 +0200 |
commit | 1cd07610664ab955c8a044b20c71224594a9a9bb (patch) | |
tree | e96e765ba0a148442efd477221fa9b77628f0f05 /spec | |
parent | c874a481346d0cd83801a510135f29c72fd8d3ae (diff) | |
parent | 7cb9957a33d37394cd884106865e4aedef519e97 (diff) | |
download | gitlab-ce-1cd07610664ab955c8a044b20c71224594a9a9bb.tar.gz |
Merge remote-tracking branch 'dev/master'
Diffstat (limited to 'spec')
-rw-r--r-- | spec/features/issues/issue_detail_spec.rb | 17 | ||||
-rw-r--r-- | spec/javascripts/issue_show/index_spec.js | 19 | ||||
-rw-r--r-- | spec/lib/gitlab/diff/highlight_spec.rb | 28 | ||||
-rw-r--r-- | spec/lib/gitlab/highlight_spec.rb | 17 | ||||
-rw-r--r-- | spec/models/blob_viewer/package_json_spec.rb | 21 | ||||
-rw-r--r-- | spec/models/event_spec.rb | 124 | ||||
-rw-r--r-- | spec/models/group_spec.rb | 42 | ||||
-rw-r--r-- | spec/requests/api/groups_spec.rb | 14 | ||||
-rw-r--r-- | spec/requests/api/redacted_events_spec.rb | 68 | ||||
-rw-r--r-- | spec/rubocop/cop/group_public_or_visible_to_user_spec.rb | 28 | ||||
-rw-r--r-- | spec/serializers/diff_line_entity_spec.rb | 45 | ||||
-rw-r--r-- | spec/services/clusters/applications/check_installation_progress_service_spec.rb | 2 | ||||
-rw-r--r-- | spec/services/clusters/applications/install_service_spec.rb | 2 | ||||
-rw-r--r-- | spec/views/projects/merge_requests/creations/_new_submit.html.haml_spec.rb | 1 | ||||
-rw-r--r-- | spec/views/projects/merge_requests/edit.html.haml_spec.rb | 1 |
15 files changed, 407 insertions, 22 deletions
diff --git a/spec/features/issues/issue_detail_spec.rb b/spec/features/issues/issue_detail_spec.rb index 088ab114df3..76bc93e9766 100644 --- a/spec/features/issues/issue_detail_spec.rb +++ b/spec/features/issues/issue_detail_spec.rb @@ -18,6 +18,23 @@ describe 'Issue Detail', :js do end end + context 'when issue description has xss snippet' do + before do + issue.update!(description: '![xss" onload=alert(1);//](a)') + sign_in(user) + visit project_issue_path(project, issue) + wait_for_requests + end + + it 'should encode the description to prevent xss issues' do + page.within('.issuable-details .detail-page-description') do + expect(page).to have_selector('img', count: 1) + expect(find('img')['onerror']).to be_nil + expect(find('img')['src']).to end_with('/a') + end + end + end + context 'when edited by a user who is later deleted' do before do sign_in(user) diff --git a/spec/javascripts/issue_show/index_spec.js b/spec/javascripts/issue_show/index_spec.js new file mode 100644 index 00000000000..fa0b426c06c --- /dev/null +++ b/spec/javascripts/issue_show/index_spec.js @@ -0,0 +1,19 @@ +import initIssueableApp from '~/issue_show'; + +describe('Issue show index', () => { + describe('initIssueableApp', () => { + it('should initialize app with no potential XSS attack', () => { + const d = document.createElement('div'); + d.id = 'js-issuable-app-initial-data'; + d.innerHTML = JSON.stringify({ + initialDescriptionHtml: '<img src=x onerror=alert(1)>', + }); + document.body.appendChild(d); + + const alertSpy = spyOn(window, 'alert'); + initIssueableApp(); + + expect(alertSpy).not.toHaveBeenCalled(); + }); + }); +}); diff --git a/spec/lib/gitlab/diff/highlight_spec.rb b/spec/lib/gitlab/diff/highlight_spec.rb index 3c8cf9c56cc..5d0a603d11d 100644 --- a/spec/lib/gitlab/diff/highlight_spec.rb +++ b/spec/lib/gitlab/diff/highlight_spec.rb @@ -8,6 +8,20 @@ describe Gitlab::Diff::Highlight do let(:diff) { commit.raw_diffs.first } let(:diff_file) { Gitlab::Diff::File.new(diff, diff_refs: commit.diff_refs, repository: project.repository) } + shared_examples 'without inline diffs' do + let(:code) { '<h2 onmouseover="alert(2)">Test</h2>' } + + before do + allow(Gitlab::Diff::InlineDiff).to receive(:for_lines).and_return([]) + allow_any_instance_of(Gitlab::Diff::Line).to receive(:text).and_return(code) + end + + it 'returns html escaped diff text' do + expect(subject[1].rich_text).to eq html_escape(code) + expect(subject[1].rich_text).to be_html_safe + end + end + describe '#highlight' do context "with a diff file" do let(:subject) { described_class.new(diff_file, repository: project.repository).highlight } @@ -38,6 +52,16 @@ describe Gitlab::Diff::Highlight do expect(subject[5].rich_text).to eq(code) end + + context 'when no diff_refs' do + before do + allow(diff_file).to receive(:diff_refs).and_return(nil) + end + + context 'when no inline diffs' do + it_behaves_like 'without inline diffs' + end + end end context "with diff lines" do @@ -93,6 +117,10 @@ describe Gitlab::Diff::Highlight do expect { subject }. to raise_exception(RangeError) end end + + context 'when no inline diffs' do + it_behaves_like 'without inline diffs' + end end end end diff --git a/spec/lib/gitlab/highlight_spec.rb b/spec/lib/gitlab/highlight_spec.rb index 29e61d15726..88f7099ff3c 100644 --- a/spec/lib/gitlab/highlight_spec.rb +++ b/spec/lib/gitlab/highlight_spec.rb @@ -56,5 +56,22 @@ describe Gitlab::Highlight do described_class.highlight('file.name', 'Contents') end + + context 'timeout' do + subject { described_class.new('file.name', 'Contents') } + + it 'utilizes timeout for web' do + expect(Timeout).to receive(:timeout).with(described_class::TIMEOUT_FOREGROUND).and_call_original + + subject.highlight("Content") + end + + it 'utilizes longer timeout for sidekiq' do + allow(Sidekiq).to receive(:server?).and_return(true) + expect(Timeout).to receive(:timeout).with(described_class::TIMEOUT_BACKGROUND).and_call_original + + subject.highlight("Content") + end + end end end diff --git a/spec/models/blob_viewer/package_json_spec.rb b/spec/models/blob_viewer/package_json_spec.rb index 5ed2f4400bc..fbaa8d47a71 100644 --- a/spec/models/blob_viewer/package_json_spec.rb +++ b/spec/models/blob_viewer/package_json_spec.rb @@ -40,13 +40,14 @@ describe BlobViewer::PackageJson do end context 'when package.json has "private": true' do + let(:homepage) { 'http://example.com' } let(:data) do <<-SPEC.strip_heredoc { "name": "module-name", "version": "10.3.1", "private": true, - "homepage": "myawesomepackage.com" + "homepage": #{homepage.to_json} } SPEC end @@ -54,10 +55,22 @@ describe BlobViewer::PackageJson do subject { described_class.new(blob) } describe '#package_url' do - it 'returns homepage if any' do - expect(subject).to receive(:prepare!) + context 'when the homepage has a valid URL' do + it 'returns homepage URL' do + expect(subject).to receive(:prepare!) + + expect(subject.package_url).to eq(homepage) + end + end + + context 'when the homepage has an invalid URL' do + let(:homepage) { 'javascript:alert()' } + + it 'returns nil' do + expect(subject).to receive(:prepare!) - expect(subject.package_url).to eq('myawesomepackage.com') + expect(subject.package_url).to be_nil + end end end diff --git a/spec/models/event_spec.rb b/spec/models/event_spec.rb index c1eac4fa489..81748681528 100644 --- a/spec/models/event_spec.rb +++ b/spec/models/event_spec.rb @@ -148,9 +148,14 @@ describe Event do let(:admin) { create(:admin) } let(:issue) { create(:issue, project: project, author: author, assignees: [assignee]) } let(:confidential_issue) { create(:issue, :confidential, project: project, author: author, assignees: [assignee]) } + let(:project_snippet) { create(:project_snippet, :public, project: project, author: author) } + let(:personal_snippet) { create(:personal_snippet, :public, author: author) } let(:note_on_commit) { create(:note_on_commit, project: project) } let(:note_on_issue) { create(:note_on_issue, noteable: issue, project: project) } let(:note_on_confidential_issue) { create(:note_on_issue, noteable: confidential_issue, project: project) } + let(:note_on_project_snippet) { create(:note_on_project_snippet, author: author, noteable: project_snippet, project: project) } + let(:note_on_personal_snippet) { create(:note_on_personal_snippet, author: author, noteable: personal_snippet, project: nil) } + let(:milestone_on_project) { create(:milestone, project: project) } let(:event) { described_class.new(project: project, target: target, author_id: author.id) } before do @@ -268,6 +273,125 @@ describe Event do end end end + + context 'milestone event' do + let(:target) { milestone_on_project } + + it do + expect(event.visible_to_user?(nil)).to be_truthy + expect(event.visible_to_user?(non_member)).to be_truthy + expect(event.visible_to_user?(member)).to be_truthy + expect(event.visible_to_user?(guest)).to be_truthy + expect(event.visible_to_user?(admin)).to be_truthy + end + + context 'on public project with private issue tracker and merge requests' do + let(:project) { create(:project, :public, :issues_private, :merge_requests_private) } + + it do + expect(event.visible_to_user?(nil)).to be_falsy + expect(event.visible_to_user?(non_member)).to be_falsy + expect(event.visible_to_user?(member)).to be_truthy + expect(event.visible_to_user?(guest)).to be_truthy + expect(event.visible_to_user?(admin)).to be_truthy + end + end + + context 'on private project' do + let(:project) { create(:project, :private) } + + it do + expect(event.visible_to_user?(nil)).to be_falsy + expect(event.visible_to_user?(non_member)).to be_falsy + expect(event.visible_to_user?(member)).to be_truthy + expect(event.visible_to_user?(guest)).to be_truthy + expect(event.visible_to_user?(admin)).to be_truthy + end + end + end + + context 'project snippet note event' do + let(:target) { note_on_project_snippet } + + it do + expect(event.visible_to_user?(nil)).to be_truthy + expect(event.visible_to_user?(non_member)).to be_truthy + expect(event.visible_to_user?(author)).to be_truthy + expect(event.visible_to_user?(member)).to be_truthy + expect(event.visible_to_user?(guest)).to be_truthy + expect(event.visible_to_user?(admin)).to be_truthy + end + + context 'on public project with private snippets' do + let(:project) { create(:project, :public, :snippets_private) } + + it do + expect(event.visible_to_user?(nil)).to be_falsy + expect(event.visible_to_user?(non_member)).to be_falsy + + # Normally, we'd expect the author of a comment to be able to view it. + # However, this doesn't seem to be the case for comments on snippets. + expect(event.visible_to_user?(author)).to be_falsy + + expect(event.visible_to_user?(member)).to be_truthy + expect(event.visible_to_user?(guest)).to be_truthy + expect(event.visible_to_user?(admin)).to be_truthy + end + end + + context 'on private project' do + let(:project) { create(:project, :private) } + + it do + expect(event.visible_to_user?(nil)).to be_falsy + expect(event.visible_to_user?(non_member)).to be_falsy + + # Normally, we'd expect the author of a comment to be able to view it. + # However, this doesn't seem to be the case for comments on snippets. + expect(event.visible_to_user?(author)).to be_falsy + + expect(event.visible_to_user?(member)).to be_truthy + expect(event.visible_to_user?(guest)).to be_truthy + expect(event.visible_to_user?(admin)).to be_truthy + end + end + end + + context 'personal snippet note event' do + let(:target) { note_on_personal_snippet } + + it do + expect(event.visible_to_user?(nil)).to be_truthy + expect(event.visible_to_user?(non_member)).to be_truthy + expect(event.visible_to_user?(author)).to be_truthy + expect(event.visible_to_user?(admin)).to be_truthy + end + + context 'on internal snippet' do + let(:personal_snippet) { create(:personal_snippet, :internal, author: author) } + + it do + expect(event.visible_to_user?(nil)).to be_falsy + expect(event.visible_to_user?(non_member)).to be_truthy + expect(event.visible_to_user?(author)).to be_truthy + expect(event.visible_to_user?(admin)).to be_truthy + end + end + + context 'on private snippet' do + let(:personal_snippet) { create(:personal_snippet, :private, author: author) } + + it do + expect(event.visible_to_user?(nil)).to be_falsy + expect(event.visible_to_user?(non_member)).to be_falsy + expect(event.visible_to_user?(author)).to be_truthy + + # It is very unexpected that a private personal snippet is not visible + # to an instance administrator. This should be fixed in the future. + expect(event.visible_to_user?(admin)).to be_falsy + end + end + end end describe '.limit_recent' do diff --git a/spec/models/group_spec.rb b/spec/models/group_spec.rb index 0729eb99e78..1bf8f89e126 100644 --- a/spec/models/group_spec.rb +++ b/spec/models/group_spec.rb @@ -169,22 +169,42 @@ describe Group do end end - describe '.visible_to_user' do - let!(:group) { create(:group) } - let!(:user) { create(:user) } + describe '.public_or_visible_to_user' do + let!(:private_group) { create(:group, :private) } + let!(:internal_group) { create(:group, :internal) } - subject { described_class.visible_to_user(user) } + subject { described_class.public_or_visible_to_user(user) } - describe 'when the user has access to a group' do - before do - group.add_user(user, Gitlab::Access::MAINTAINER) - end + context 'when user is nil' do + let!(:user) { nil } - it { is_expected.to eq([group]) } + it { is_expected.to match_array([group]) } end - describe 'when the user does not have access to any groups' do - it { is_expected.to eq([]) } + context 'when user' do + let!(:user) { create(:user) } + + context 'when user does not have access to any private group' do + it { is_expected.to match_array([internal_group, group]) } + end + + context 'when user is a member of private group' do + before do + private_group.add_user(user, Gitlab::Access::DEVELOPER) + end + + it { is_expected.to match_array([private_group, internal_group, group]) } + end + + context 'when user is a member of private subgroup', :postgresql do + let!(:private_subgroup) { create(:group, :private, parent: private_group) } + + before do + private_subgroup.add_user(user, Gitlab::Access::DEVELOPER) + end + + it { is_expected.to match_array([private_subgroup, internal_group, group]) } + end end end diff --git a/spec/requests/api/groups_spec.rb b/spec/requests/api/groups_spec.rb index 3a8948f8477..3802b5c6848 100644 --- a/spec/requests/api/groups_spec.rb +++ b/spec/requests/api/groups_spec.rb @@ -155,7 +155,7 @@ describe API::Groups do expect(response).to have_gitlab_http_status(200) expect(response).to include_pagination_headers expect(json_response).to be_an Array - expect(response_groups).to eq(Group.visible_to_user(user1).order(:name).pluck(:name)) + expect(response_groups).to eq(groups_visible_to_user(user1).order(:name).pluck(:name)) end it "sorts in descending order when passed" do @@ -164,7 +164,7 @@ describe API::Groups do expect(response).to have_gitlab_http_status(200) expect(response).to include_pagination_headers expect(json_response).to be_an Array - expect(response_groups).to eq(Group.visible_to_user(user1).order(name: :desc).pluck(:name)) + expect(response_groups).to eq(groups_visible_to_user(user1).order(name: :desc).pluck(:name)) end it "sorts by path in order_by param" do @@ -173,7 +173,7 @@ describe API::Groups do expect(response).to have_gitlab_http_status(200) expect(response).to include_pagination_headers expect(json_response).to be_an Array - expect(response_groups).to eq(Group.visible_to_user(user1).order(:path).pluck(:name)) + expect(response_groups).to eq(groups_visible_to_user(user1).order(:path).pluck(:name)) end it "sorts by id in the order_by param" do @@ -182,7 +182,7 @@ describe API::Groups do expect(response).to have_gitlab_http_status(200) expect(response).to include_pagination_headers expect(json_response).to be_an Array - expect(response_groups).to eq(Group.visible_to_user(user1).order(:id).pluck(:name)) + expect(response_groups).to eq(groups_visible_to_user(user1).order(:id).pluck(:name)) end it "sorts also by descending id with pagination fix" do @@ -191,7 +191,7 @@ describe API::Groups do expect(response).to have_gitlab_http_status(200) expect(response).to include_pagination_headers expect(json_response).to be_an Array - expect(response_groups).to eq(Group.visible_to_user(user1).order(id: :desc).pluck(:name)) + expect(response_groups).to eq(groups_visible_to_user(user1).order(id: :desc).pluck(:name)) end it "sorts identical keys by id for good pagination" do @@ -211,6 +211,10 @@ describe API::Groups do expect(json_response).to be_an Array expect(response_groups_ids).to eq(Group.select { |group| group['name'] == 'same-name' }.map { |group| group['id'] }.sort) end + + def groups_visible_to_user(user) + Group.where(id: user.authorized_groups.select(:id).reorder(nil)) + end end context 'when using owned in the request' do diff --git a/spec/requests/api/redacted_events_spec.rb b/spec/requests/api/redacted_events_spec.rb new file mode 100644 index 00000000000..086dd3df9ba --- /dev/null +++ b/spec/requests/api/redacted_events_spec.rb @@ -0,0 +1,68 @@ +require 'spec_helper' + +describe 'Redacted events in API::Events' do + shared_examples 'private events are redacted' do + it 'redacts events the user does not have access to' do + expect_any_instance_of(Event).to receive(:visible_to_user?).and_call_original + + get api(path), user + + expect(response).to have_gitlab_http_status(200) + expect(json_response).to contain_exactly( + 'project_id' => nil, + 'action_name' => nil, + 'target_id' => nil, + 'target_iid' => nil, + 'target_type' => nil, + 'author_id' => nil, + 'target_title' => 'Confidential event', + 'created_at' => nil, + 'author_username' => nil + ) + end + end + + describe '/users/:id/events' do + let(:project) { create(:project, :public) } + let(:path) { "/users/#{project.owner.id}/events" } + let(:issue) { create(:issue, :confidential, project: project) } + + before do + EventCreateService.new.open_issue(issue, issue.author) + end + + context 'unauthenticated user views another user with private events' do + let(:user) { nil } + + include_examples 'private events are redacted' + end + + context 'authenticated user without access views another user with private events' do + let(:user) { create(:user) } + + include_examples 'private events are redacted' + end + end + + describe '/projects/:id/events' do + let(:project) { create(:project, :public) } + let(:path) { "/projects/#{project.id}/events" } + let(:issue) { create(:issue, :confidential, project: project) } + + before do + EventCreateService.new.open_issue(issue, issue.author) + end + + context 'unauthenticated user views public project' do + let(:user) { nil } + + include_examples 'private events are redacted' + end + + context 'authenticated user without access views public project' do + let(:user) { create(:user) } + + include_examples 'private events are redacted' + end + end +end diff --git a/spec/rubocop/cop/group_public_or_visible_to_user_spec.rb b/spec/rubocop/cop/group_public_or_visible_to_user_spec.rb new file mode 100644 index 00000000000..7b5235a3da7 --- /dev/null +++ b/spec/rubocop/cop/group_public_or_visible_to_user_spec.rb @@ -0,0 +1,28 @@ +require 'spec_helper' +require 'rubocop' +require 'rubocop/rspec/support' +require_relative '../../../rubocop/cop/group_public_or_visible_to_user' + +describe RuboCop::Cop::GroupPublicOrVisibleToUser do + include CopHelper + + subject(:cop) { described_class.new } + + it 'flags the use of Group.public_or_visible_to_user with a constant receiver' do + inspect_source('Group.public_or_visible_to_user') + + expect(cop.offenses.size).to eq(1) + end + + it 'does not flat the use of public_or_visible_to_user with a constant that is not Group' do + inspect_source('Project.public_or_visible_to_user') + + expect(cop.offenses.size).to eq(0) + end + + it 'does not flag the use of Group.public_or_visible_to_user with a send receiver' do + inspect_source('foo.public_or_visible_to_user') + + expect(cop.offenses.size).to eq(0) + end +end diff --git a/spec/serializers/diff_line_entity_spec.rb b/spec/serializers/diff_line_entity_spec.rb new file mode 100644 index 00000000000..2549f64bcd3 --- /dev/null +++ b/spec/serializers/diff_line_entity_spec.rb @@ -0,0 +1,45 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe DiffLineEntity do + include RepoHelpers + + let(:code) { 'hello world' } + let(:line) { Gitlab::Diff::Line.new(code, 'new', 1, nil, 1) } + let(:entity) { described_class.new(line, request: {}) } + + subject { entity.as_json } + + it 'exposes correct attributes' do + expect(subject).to include( + :line_code, :type, :old_line, :new_line, :text, :meta_data, :rich_text + ) + end + + describe '#rich_text' do + let(:code) { '<h2 onmouseover="alert(2)">Test</h2>' } + let(:rich_text_value) { nil } + + before do + line.instance_variable_set(:@rich_text, rich_text_value) + end + + shared_examples 'escapes html tags' do + it do + expect(subject[:rich_text]).to eq html_escape(code) + expect(subject[:rich_text]).to be_html_safe + end + end + + context 'when rich_line is present' do + let(:rich_text_value) { code } + + it_behaves_like 'escapes html tags' + end + + context 'when rich_line is not present' do + it_behaves_like 'escapes html tags' + end + end +end diff --git a/spec/services/clusters/applications/check_installation_progress_service_spec.rb b/spec/services/clusters/applications/check_installation_progress_service_spec.rb index 986f11410fd..1a565bb734d 100644 --- a/spec/services/clusters/applications/check_installation_progress_service_spec.rb +++ b/spec/services/clusters/applications/check_installation_progress_service_spec.rb @@ -82,7 +82,7 @@ describe Clusters::Applications::CheckInstallationProgressService do service.execute expect(application).to be_errored - expect(application.status_reason).to eq(errors) + expect(application.status_reason).to eq("Installation failed") end end diff --git a/spec/services/clusters/applications/install_service_spec.rb b/spec/services/clusters/applications/install_service_spec.rb index a744ec30b65..4bd19f5bd79 100644 --- a/spec/services/clusters/applications/install_service_spec.rb +++ b/spec/services/clusters/applications/install_service_spec.rb @@ -42,7 +42,7 @@ describe Clusters::Applications::InstallService do service.execute expect(application).to be_errored - expect(application.status_reason).to match(/kubernetes error:/i) + expect(application.status_reason).to match('Kubernetes error.') end end diff --git a/spec/views/projects/merge_requests/creations/_new_submit.html.haml_spec.rb b/spec/views/projects/merge_requests/creations/_new_submit.html.haml_spec.rb index 8befae39d3a..0206928a211 100644 --- a/spec/views/projects/merge_requests/creations/_new_submit.html.haml_spec.rb +++ b/spec/views/projects/merge_requests/creations/_new_submit.html.haml_spec.rb @@ -12,6 +12,7 @@ describe 'projects/merge_requests/creations/_new_submit.html.haml' do assign(:hidden_commit_count, 0) assign(:total_commit_count, merge_request.commits.count) assign(:project, merge_request.target_project) + assign(:mr_presenter, merge_request.present(current_user: merge_request.author)) allow(view).to receive(:can?).and_return(true) allow(view).to receive(:url_for).and_return('#') diff --git a/spec/views/projects/merge_requests/edit.html.haml_spec.rb b/spec/views/projects/merge_requests/edit.html.haml_spec.rb index 9b74a7e1946..c13eab30054 100644 --- a/spec/views/projects/merge_requests/edit.html.haml_spec.rb +++ b/spec/views/projects/merge_requests/edit.html.haml_spec.rb @@ -24,6 +24,7 @@ describe 'projects/merge_requests/edit.html.haml' do before do assign(:project, project) assign(:merge_request, closed_merge_request) + assign(:mr_presenter, closed_merge_request.present(current_user: user)) allow(view).to receive(:can?).and_return(true) allow(view).to receive(:current_user) |