summaryrefslogtreecommitdiff
path: root/spec
diff options
context:
space:
mode:
authorRobert Speicher <rspeicher@gmail.com>2019-07-29 13:19:50 -0500
committerRobert Speicher <rspeicher@gmail.com>2019-07-29 13:19:50 -0500
commitfe22704a203111ab2146143a4ff9d2e1256aecc7 (patch)
tree1bafbd0bdfbd498220cef09c94eb71bf4f9e072f /spec
parentf039d592aa6203502be487801777167e433ad9d2 (diff)
parentcc7b15fe935d41aab85918eb7ae7c0ef81f8bfb0 (diff)
downloadgitlab-ce-fe22704a203111ab2146143a4ff9d2e1256aecc7.tar.gz
Merge branch 'master' of dev.gitlab.org:gitlab/gitlabhq
Diffstat (limited to 'spec')
-rw-r--r--spec/controllers/groups/uploads_controller_spec.rb5
-rw-r--r--spec/controllers/projects/badges_controller_spec.rb124
-rw-r--r--spec/controllers/projects/merge_requests_controller_spec.rb98
-rw-r--r--spec/controllers/projects/uploads_controller_spec.rb5
-rw-r--r--spec/features/merge_request/user_tries_to_access_private_project_info_through_new_mr_spec.rb (renamed from spec/features/merge_request/user_tries_to_access_private_repository_through_new_mr_spec.rb)19
-rw-r--r--spec/features/triggers_spec.rb23
-rw-r--r--spec/lib/banzai/filter/wiki_link_filter_spec.rb42
-rw-r--r--spec/lib/banzai/pipeline/wiki_pipeline_spec.rb79
-rw-r--r--spec/lib/gitlab/octokit/middleware_spec.rb68
-rw-r--r--spec/lib/gitlab/url_blocker_spec.rb44
-rw-r--r--spec/lib/gitlab/utils/sanitize_node_link_spec.rb72
-rw-r--r--spec/requests/api/triggers_spec.rb28
-rw-r--r--spec/serializers/issue_entity_spec.rb33
-rw-r--r--spec/services/merge_requests/build_service_spec.rb37
-rw-r--r--spec/spec_helper.rb1
-rw-r--r--spec/support/shared_examples/controllers/uploads_actions_shared_examples.rb10
-rw-r--r--spec/uploaders/records_uploads_spec.rb21
17 files changed, 568 insertions, 141 deletions
diff --git a/spec/controllers/groups/uploads_controller_spec.rb b/spec/controllers/groups/uploads_controller_spec.rb
index 0f99a957581..60342bf8e3d 100644
--- a/spec/controllers/groups/uploads_controller_spec.rb
+++ b/spec/controllers/groups/uploads_controller_spec.rb
@@ -10,6 +10,11 @@ describe Groups::UploadsController do
{ group_id: model }
end
+ let(:other_model) { create(:group, :public) }
+ let(:other_params) do
+ { group_id: other_model }
+ end
+
it_behaves_like 'handle uploads' do
let(:uploader_class) { NamespaceFileUploader }
end
diff --git a/spec/controllers/projects/badges_controller_spec.rb b/spec/controllers/projects/badges_controller_spec.rb
index 5ec8d8d41d7..4ae29ba7f54 100644
--- a/spec/controllers/projects/badges_controller_spec.rb
+++ b/spec/controllers/projects/badges_controller_spec.rb
@@ -7,51 +7,115 @@ describe Projects::BadgesController do
let!(:pipeline) { create(:ci_empty_pipeline) }
let(:user) { create(:user) }
- before do
- project.add_maintainer(user)
- sign_in(user)
- end
+ shared_examples 'a badge resource' do |badge_type|
+ context 'when pipelines are public' do
+ before do
+ project.update!(public_builds: true)
+ end
+
+ context 'when project is public' do
+ before do
+ project.update!(visibility_level: Gitlab::VisibilityLevel::PUBLIC)
+ end
+
+ it "returns the #{badge_type} badge to unauthenticated users" do
+ get_badge(badge_type)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+ end
+
+ context 'when project is restricted' do
+ before do
+ project.update!(visibility_level: Gitlab::VisibilityLevel::INTERNAL)
+ project.add_guest(user)
+ sign_in(user)
+ end
+
+ it "returns the #{badge_type} badge to guest users" do
+ get_badge(badge_type)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+ end
+ end
- it 'requests the pipeline badge successfully' do
- get_badge(:pipeline)
+ context 'format' do
+ before do
+ project.add_maintainer(user)
+ sign_in(user)
+ end
- expect(response).to have_gitlab_http_status(:ok)
- end
+ it 'renders the `flat` badge layout by default' do
+ get_badge(badge_type)
- it 'requests the coverage badge successfully' do
- get_badge(:coverage)
+ expect(response).to render_template('projects/badges/badge')
+ end
- expect(response).to have_gitlab_http_status(:ok)
- end
+ context 'when style param is set to `flat`' do
+ it 'renders the `flat` badge layout' do
+ get_badge(badge_type, 'flat')
- it 'renders the `flat` badge layout by default' do
- get_badge(:coverage)
+ expect(response).to render_template('projects/badges/badge')
+ end
+ end
- expect(response).to render_template('projects/badges/badge')
- end
+ context 'when style param is set to an invalid type' do
+ it 'renders the `flat` (default) badge layout' do
+ get_badge(badge_type, 'xxx')
+
+ expect(response).to render_template('projects/badges/badge')
+ end
+ end
- context 'when style param is set to `flat`' do
- it 'renders the `flat` badge layout' do
- get_badge(:coverage, 'flat')
+ context 'when style param is set to `flat-square`' do
+ it 'renders the `flat-square` badge layout' do
+ get_badge(badge_type, 'flat-square')
- expect(response).to render_template('projects/badges/badge')
+ expect(response).to render_template('projects/badges/badge_flat-square')
+ end
+ end
end
- end
- context 'when style param is set to an invalid type' do
- it 'renders the `flat` (default) badge layout' do
- get_badge(:coverage, 'xxx')
+ context 'when pipelines are not public' do
+ before do
+ project.update!(public_builds: false)
+ end
- expect(response).to render_template('projects/badges/badge')
+ context 'when project is public' do
+ before do
+ project.update!(visibility_level: Gitlab::VisibilityLevel::PUBLIC)
+ end
+
+ it 'returns 404 to unauthenticated users' do
+ get_badge(badge_type)
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+
+ context 'when project is restricted to the user' do
+ before do
+ project.update!(visibility_level: Gitlab::VisibilityLevel::INTERNAL)
+ project.add_guest(user)
+ sign_in(user)
+ end
+
+ it 'defaults to project permissions' do
+ get_badge(:coverage)
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
end
end
- context 'when style param is set to `flat-square`' do
- it 'renders the `flat-square` badge layout' do
- get_badge(:coverage, 'flat-square')
+ describe '#pipeline' do
+ it_behaves_like 'a badge resource', :pipeline
+ end
- expect(response).to render_template('projects/badges/badge_flat-square')
- end
+ describe '#coverage' do
+ it_behaves_like 'a badge resource', :coverage
end
def get_badge(badge, style = nil)
diff --git a/spec/controllers/projects/merge_requests_controller_spec.rb b/spec/controllers/projects/merge_requests_controller_spec.rb
index fa71d9b61b1..57a432de3f5 100644
--- a/spec/controllers/projects/merge_requests_controller_spec.rb
+++ b/spec/controllers/projects/merge_requests_controller_spec.rb
@@ -621,10 +621,100 @@ describe Projects::MergeRequestsController do
format: :json
end
- it 'responds with serialized pipelines' do
- expect(json_response['pipelines']).not_to be_empty
- expect(json_response['count']['all']).to eq 1
- expect(response).to include_pagination_headers
+ context 'with "enabled" builds on a public project' do
+ let(:project) { create(:project, :repository, :public) }
+
+ context 'for a project owner' do
+ it 'responds with serialized pipelines' do
+ expect(json_response['pipelines']).to be_present
+ expect(json_response['count']['all']).to eq(1)
+ expect(response).to include_pagination_headers
+ end
+ end
+
+ context 'for an unassociated user' do
+ let(:user) { create :user }
+
+ it 'responds with no pipelines' do
+ expect(json_response['pipelines']).to be_present
+ expect(json_response['count']['all']).to eq(1)
+ expect(response).to include_pagination_headers
+ end
+ end
+ end
+
+ context 'with private builds on a public project' do
+ let(:project) { create(:project, :repository, :public, :builds_private) }
+
+ context 'for a project owner' do
+ it 'responds with serialized pipelines' do
+ expect(json_response['pipelines']).to be_present
+ expect(json_response['count']['all']).to eq(1)
+ expect(response).to include_pagination_headers
+ end
+ end
+
+ context 'for an unassociated user' do
+ let(:user) { create :user }
+
+ it 'responds with no pipelines' do
+ expect(json_response['pipelines']).to be_empty
+ expect(json_response['count']['all']).to eq(0)
+ expect(response).to include_pagination_headers
+ end
+ end
+
+ context 'from a project fork' do
+ let(:fork_user) { create :user }
+ let(:forked_project) { fork_project(project, fork_user, repository: true) } # Forked project carries over :builds_private
+ let(:merge_request) { create(:merge_request_with_diffs, target_project: project, source_project: forked_project) }
+
+ context 'with private builds' do
+ context 'for the target project member' do
+ it 'does not respond with serialized pipelines' do
+ expect(json_response['pipelines']).to be_empty
+ expect(json_response['count']['all']).to eq(0)
+ expect(response).to include_pagination_headers
+ end
+ end
+
+ context 'for the source project member' do
+ let(:user) { fork_user }
+
+ it 'responds with serialized pipelines' do
+ expect(json_response['pipelines']).to be_present
+ expect(json_response['count']['all']).to eq(1)
+ expect(response).to include_pagination_headers
+ end
+ end
+ end
+
+ context 'with public builds' do
+ let(:forked_project) do
+ fork_project(project, fork_user, repository: true).tap do |new_project|
+ new_project.project_feature.update(builds_access_level: ProjectFeature::ENABLED)
+ end
+ end
+
+ context 'for the target project member' do
+ it 'does not respond with serialized pipelines' do
+ expect(json_response['pipelines']).to be_present
+ expect(json_response['count']['all']).to eq(1)
+ expect(response).to include_pagination_headers
+ end
+ end
+
+ context 'for the source project member' do
+ let(:user) { fork_user }
+
+ it 'responds with serialized pipelines' do
+ expect(json_response['pipelines']).to be_present
+ expect(json_response['count']['all']).to eq(1)
+ expect(response).to include_pagination_headers
+ end
+ end
+ end
+ end
end
end
diff --git a/spec/controllers/projects/uploads_controller_spec.rb b/spec/controllers/projects/uploads_controller_spec.rb
index 776c1270977..661ed9840b1 100644
--- a/spec/controllers/projects/uploads_controller_spec.rb
+++ b/spec/controllers/projects/uploads_controller_spec.rb
@@ -10,6 +10,11 @@ describe Projects::UploadsController do
{ namespace_id: model.namespace.to_param, project_id: model }
end
+ let(:other_model) { create(:project, :public) }
+ let(:other_params) do
+ { namespace_id: other_model.namespace.to_param, project_id: other_model }
+ end
+
it_behaves_like 'handle uploads'
context 'when the URL the old style, without /-/system' do
diff --git a/spec/features/merge_request/user_tries_to_access_private_repository_through_new_mr_spec.rb b/spec/features/merge_request/user_tries_to_access_private_project_info_through_new_mr_spec.rb
index d0dba4b9761..1ebe9e2e409 100644
--- a/spec/features/merge_request/user_tries_to_access_private_repository_through_new_mr_spec.rb
+++ b/spec/features/merge_request/user_tries_to_access_private_project_info_through_new_mr_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe 'Merge Request > Tries to access private repo of public project' do
+describe 'Merge Request > User tries to access private project information through the new mr page' do
let(:current_user) { create(:user) }
let(:private_project) do
create(:project, :public, :repository,
@@ -35,5 +35,22 @@ describe 'Merge Request > Tries to access private repo of public project' do
it "does not mention the project the user can't see the repo of" do
expect(page).not_to have_content('nothing-to-see-here')
end
+
+ context 'when the user enters label information from the private project in the querystring' do
+ let(:inaccessible_label) { create(:label, project: private_project) }
+ let(:mr_path) do
+ project_new_merge_request_path(
+ owned_project,
+ merge_request: {
+ label_ids: [inaccessible_label.id],
+ source_branch: 'feature'
+ }
+ )
+ end
+
+ it 'does not expose the label name' do
+ expect(page).not_to have_content(inaccessible_label.name)
+ end
+ end
end
end
diff --git a/spec/features/triggers_spec.rb b/spec/features/triggers_spec.rb
index 9661e204dfb..19cd21e4161 100644
--- a/spec/features/triggers_spec.rb
+++ b/spec/features/triggers_spec.rb
@@ -83,29 +83,6 @@ describe 'Triggers', :js do
end
end
- describe 'trigger "Take ownership" workflow' do
- before do
- create(:ci_trigger, owner: user2, project: @project, description: trigger_title)
- visit project_settings_ci_cd_path(@project)
- end
-
- it 'button "Take ownership" has correct alert' do
- expected_alert = 'By taking ownership you will bind this trigger to your user account. With this the trigger will have access to all your projects as if it was you. Are you sure?'
- expect(page.find('a.btn-trigger-take-ownership')['data-confirm']).to eq expected_alert
- end
-
- it 'take trigger ownership' do
- # See if "Take ownership" on trigger works post trigger creation
- page.accept_confirm do
- first(:link, "Take ownership").send_keys(:return)
- end
-
- expect(page.find('.flash-notice')).to have_content 'Trigger was re-assigned.'
- expect(page.find('.triggers-list')).to have_content trigger_title
- expect(page.find('.triggers-list .trigger-owner')).to have_content user.name
- end
- end
-
describe 'trigger "Revoke" workflow' do
before do
create(:ci_trigger, owner: user2, project: @project, description: trigger_title)
diff --git a/spec/lib/banzai/filter/wiki_link_filter_spec.rb b/spec/lib/banzai/filter/wiki_link_filter_spec.rb
index 877d99b68f3..d2d539a62fc 100644
--- a/spec/lib/banzai/filter/wiki_link_filter_spec.rb
+++ b/spec/lib/banzai/filter/wiki_link_filter_spec.rb
@@ -72,47 +72,5 @@ describe Banzai::Filter::WikiLinkFilter do
expect(filtered_link.attribute('href').value).to eq(invalid_link)
end
end
-
- context "when the slug is deemed unsafe or invalid" do
- let(:link) { "alert(1);" }
-
- invalid_slugs = [
- "javascript:",
- "JaVaScRiPt:",
- "\u0001java\u0003script:",
- "javascript :",
- "javascript: ",
- "javascript : ",
- ":javascript:",
- "javascript&#58;",
- "javascript&#0058;",
- "javascript&#x3A;",
- "javascript&#x003A;",
- "java\0script:",
- " &#14; javascript:"
- ]
-
- invalid_slugs.each do |slug|
- context "with the slug #{slug}" do
- it "doesn't rewrite a (.) relative link" do
- filtered_link = filter(
- "<a href='.#{link}'>Link</a>",
- project_wiki: wiki,
- page_slug: slug).children[0]
-
- expect(filtered_link.attribute('href').value).not_to include(slug)
- end
-
- it "doesn't rewrite a (..) relative link" do
- filtered_link = filter(
- "<a href='..#{link}'>Link</a>",
- project_wiki: wiki,
- page_slug: slug).children[0]
-
- expect(filtered_link.attribute('href').value).not_to include(slug)
- end
- end
- end
- end
end
end
diff --git a/spec/lib/banzai/pipeline/wiki_pipeline_spec.rb b/spec/lib/banzai/pipeline/wiki_pipeline_spec.rb
index cb94944fdfb..015af20f220 100644
--- a/spec/lib/banzai/pipeline/wiki_pipeline_spec.rb
+++ b/spec/lib/banzai/pipeline/wiki_pipeline_spec.rb
@@ -179,6 +179,85 @@ describe Banzai::Pipeline::WikiPipeline do
end
end
end
+
+ describe "checking slug validity when assembling links" do
+ context "with a valid slug" do
+ let(:valid_slug) { "http://example.com" }
+
+ it "includes the slug in a (.) relative link" do
+ output = described_class.to_html(
+ "[Link](./alert(1);)",
+ project: project,
+ project_wiki: project_wiki,
+ page_slug: valid_slug
+ )
+
+ expect(output).to include(valid_slug)
+ end
+
+ it "includeds the slug in a (..) relative link" do
+ output = described_class.to_html(
+ "[Link](../alert(1);)",
+ project: project,
+ project_wiki: project_wiki,
+ page_slug: valid_slug
+ )
+
+ expect(output).to include(valid_slug)
+ end
+ end
+
+ context "when the slug is deemed unsafe or invalid" do
+ invalid_slugs = [
+ "javascript:",
+ "JaVaScRiPt:",
+ "\u0001java\u0003script:",
+ "javascript :",
+ "javascript: ",
+ "javascript : ",
+ ":javascript:",
+ "javascript&#58;",
+ "javascript&#0058;",
+ "javascript&#x3A;",
+ "javascript&#x003A;",
+ "java\0script:",
+ " &#14; javascript:"
+ ]
+
+ invalid_js_links = [
+ "alert(1);",
+ "alert(document.location);"
+ ]
+
+ invalid_slugs.each do |slug|
+ context "with the invalid slug #{slug}" do
+ invalid_js_links.each do |link|
+ it "doesn't include a prohibited slug in a (.) relative link '#{link}'" do
+ output = described_class.to_html(
+ "[Link](./#{link})",
+ project: project,
+ project_wiki: project_wiki,
+ page_slug: slug
+ )
+
+ expect(output).not_to include(slug)
+ end
+
+ it "doesn't include a prohibited slug in a (..) relative link '#{link}'" do
+ output = described_class.to_html(
+ "[Link](../#{link})",
+ project: project,
+ project_wiki: project_wiki,
+ page_slug: slug
+ )
+
+ expect(output).not_to include(slug)
+ end
+ end
+ end
+ end
+ end
+ end
end
describe 'videos' do
diff --git a/spec/lib/gitlab/octokit/middleware_spec.rb b/spec/lib/gitlab/octokit/middleware_spec.rb
new file mode 100644
index 00000000000..7f2b523f5b7
--- /dev/null
+++ b/spec/lib/gitlab/octokit/middleware_spec.rb
@@ -0,0 +1,68 @@
+require 'spec_helper'
+
+describe Gitlab::Octokit::Middleware do
+ let(:app) { double(:app) }
+ let(:middleware) { described_class.new(app) }
+
+ shared_examples 'Public URL' do
+ it 'does not raise an error' do
+ expect(app).to receive(:call).with(env)
+
+ expect { middleware.call(env) }.not_to raise_error
+ end
+ end
+
+ shared_examples 'Local URL' do
+ it 'raises an error' do
+ expect { middleware.call(env) }.to raise_error(Gitlab::UrlBlocker::BlockedUrlError)
+ end
+ end
+
+ describe '#call' do
+ context 'when the URL is a public URL' do
+ let(:env) { { url: 'https://public-url.com' } }
+
+ it_behaves_like 'Public URL'
+ end
+
+ context 'when the URL is a localhost adresss' do
+ let(:env) { { url: 'http://127.0.0.1' } }
+
+ context 'when localhost requests are not allowed' do
+ before do
+ stub_application_setting(allow_local_requests_from_hooks_and_services: false)
+ end
+
+ it_behaves_like 'Local URL'
+ end
+
+ context 'when localhost requests are allowed' do
+ before do
+ stub_application_setting(allow_local_requests_from_hooks_and_services: true)
+ end
+
+ it_behaves_like 'Public URL'
+ end
+ end
+
+ context 'when the URL is a local network address' do
+ let(:env) { { url: 'http://172.16.0.0' } }
+
+ context 'when local network requests are not allowed' do
+ before do
+ stub_application_setting(allow_local_requests_from_hooks_and_services: false)
+ end
+
+ it_behaves_like 'Local URL'
+ end
+
+ context 'when local network requests are allowed' do
+ before do
+ stub_application_setting(allow_local_requests_from_hooks_and_services: true)
+ end
+
+ it_behaves_like 'Public URL'
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/url_blocker_spec.rb b/spec/lib/gitlab/url_blocker_spec.rb
index 93194de4a1b..45d9022abeb 100644
--- a/spec/lib/gitlab/url_blocker_spec.rb
+++ b/spec/lib/gitlab/url_blocker_spec.rb
@@ -68,6 +68,16 @@ describe Gitlab::UrlBlocker do
expect(uri).to eq(Addressable::URI.parse('https://example.org'))
expect(hostname).to eq(nil)
end
+
+ context 'when it cannot be resolved' do
+ let(:import_url) { 'http://foobar.x' }
+
+ it 'raises error' do
+ stub_env('RSPEC_ALLOW_INVALID_URLS', 'false')
+
+ expect { described_class.validate!(import_url) }.to raise_error(described_class::BlockedUrlError)
+ end
+ end
end
context 'when the URL hostname is an IP address' do
@@ -79,6 +89,16 @@ describe Gitlab::UrlBlocker do
expect(uri).to eq(Addressable::URI.parse('https://93.184.216.34'))
expect(hostname).to be(nil)
end
+
+ context 'when it is invalid' do
+ let(:import_url) { 'http://1.1.1.1.1' }
+
+ it 'raises an error' do
+ stub_env('RSPEC_ALLOW_INVALID_URLS', 'false')
+
+ expect { described_class.validate!(import_url) }.to raise_error(described_class::BlockedUrlError)
+ end
+ end
end
end
end
@@ -180,8 +200,6 @@ describe Gitlab::UrlBlocker do
end
it 'returns true for a non-alphanumeric hostname' do
- stub_resolv
-
aggregate_failures do
expect(described_class).to be_blocked_url('ssh://-oProxyCommand=whoami/a')
@@ -454,10 +472,6 @@ describe Gitlab::UrlBlocker do
end
context 'when enforce_user is' do
- before do
- stub_resolv
- end
-
context 'false (default)' do
it 'does not block urls with a non-alphanumeric username' do
expect(described_class).not_to be_blocked_url('ssh://-oProxyCommand=whoami@example.com/a')
@@ -505,6 +519,18 @@ describe Gitlab::UrlBlocker do
expect(described_class.blocked_url?('https://git‌lab.com/foo/foo.bar', ascii_only: true)).to be true
end
end
+
+ it 'blocks urls with invalid ip address' do
+ stub_env('RSPEC_ALLOW_INVALID_URLS', 'false')
+
+ expect(described_class).to be_blocked_url('http://8.8.8.8.8')
+ end
+
+ it 'blocks urls whose hostname cannot be resolved' do
+ stub_env('RSPEC_ALLOW_INVALID_URLS', 'false')
+
+ expect(described_class).to be_blocked_url('http://foobar.x')
+ end
end
describe '#validate_hostname' do
@@ -536,10 +562,4 @@ describe Gitlab::UrlBlocker do
end
end
end
-
- # Resolv does not support resolving UTF-8 domain names
- # See https://bugs.ruby-lang.org/issues/4270
- def stub_resolv
- allow(Resolv).to receive(:getaddresses).and_return([])
- end
end
diff --git a/spec/lib/gitlab/utils/sanitize_node_link_spec.rb b/spec/lib/gitlab/utils/sanitize_node_link_spec.rb
new file mode 100644
index 00000000000..064c2707d06
--- /dev/null
+++ b/spec/lib/gitlab/utils/sanitize_node_link_spec.rb
@@ -0,0 +1,72 @@
+require 'spec_helper'
+
+describe Gitlab::Utils::SanitizeNodeLink do
+ let(:klass) do
+ struct = Struct.new(:value)
+ struct.include(described_class)
+
+ struct
+ end
+
+ subject(:object) { klass.new(:value) }
+
+ invalid_schemes = [
+ "javascript:",
+ "JaVaScRiPt:",
+ "\u0001java\u0003script:",
+ "javascript :",
+ "javascript: ",
+ "javascript : ",
+ ":javascript:",
+ "javascript&#58;",
+ "javascript&#0058;",
+ " &#14; javascript:"
+ ]
+
+ invalid_schemes.each do |scheme|
+ context "with the scheme: #{scheme}" do
+ describe "#remove_unsafe_links" do
+ tags = {
+ a: {
+ doc: HTML::Pipeline.parse("<a href='#{scheme}alert(1);'>foo</a>"),
+ attr: "href",
+ node_to_check: -> (doc) { doc.children.first }
+ },
+ img: {
+ doc: HTML::Pipeline.parse("<img src='#{scheme}alert(1);'>"),
+ attr: "src",
+ node_to_check: -> (doc) { doc.children.first }
+ },
+ video: {
+ doc: HTML::Pipeline.parse("<video><source src='#{scheme}alert(1);'></video>"),
+ attr: "src",
+ node_to_check: -> (doc) { doc.children.first.children.filter("source").first }
+ }
+ }
+
+ tags.each do |tag, opts|
+ context "<#{tag}> tags" do
+ it "removes the unsafe link" do
+ node = opts[:node_to_check].call(opts[:doc])
+
+ expect { object.remove_unsafe_links({ node: node }, remove_invalid_links: true) }
+ .to change { node[opts[:attr]] }
+
+ expect(node[opts[:attr]]).to be_blank
+ end
+ end
+ end
+ end
+
+ describe "#safe_protocol?" do
+ let(:doc) { HTML::Pipeline.parse("<a href='#{scheme}alert(1);'>foo</a>") }
+ let(:node) { doc.children.first }
+ let(:uri) { Addressable::URI.parse(node['href'])}
+
+ it "returns false" do
+ expect(object.safe_protocol?(scheme)).to be_falsy
+ end
+ end
+ end
+ end
+end
diff --git a/spec/requests/api/triggers_spec.rb b/spec/requests/api/triggers_spec.rb
index f0f01e97f1d..8ea3d16a41f 100644
--- a/spec/requests/api/triggers_spec.rb
+++ b/spec/requests/api/triggers_spec.rb
@@ -270,34 +270,6 @@ describe API::Triggers do
end
end
- describe 'POST /projects/:id/triggers/:trigger_id/take_ownership' do
- context 'authenticated user with valid permissions' do
- it 'updates owner' do
- post api("/projects/#{project.id}/triggers/#{trigger.id}/take_ownership", user)
-
- expect(response).to have_gitlab_http_status(200)
- expect(json_response).to include('owner')
- expect(trigger.reload.owner).to eq(user)
- end
- end
-
- context 'authenticated user with invalid permissions' do
- it 'does not update owner' do
- post api("/projects/#{project.id}/triggers/#{trigger.id}/take_ownership", user2)
-
- expect(response).to have_gitlab_http_status(403)
- end
- end
-
- context 'unauthenticated user' do
- it 'does not update owner' do
- post api("/projects/#{project.id}/triggers/#{trigger.id}/take_ownership")
-
- expect(response).to have_gitlab_http_status(401)
- end
- end
- end
-
describe 'DELETE /projects/:id/triggers/:trigger_id' do
context 'authenticated user with valid permissions' do
it 'deletes trigger' do
diff --git a/spec/serializers/issue_entity_spec.rb b/spec/serializers/issue_entity_spec.rb
index caa3e41402b..0e05b3c84f4 100644
--- a/spec/serializers/issue_entity_spec.rb
+++ b/spec/serializers/issue_entity_spec.rb
@@ -17,4 +17,37 @@ describe IssueEntity do
it 'has time estimation attributes' do
expect(subject).to include(:time_estimate, :total_time_spent, :human_time_estimate, :human_total_time_spent)
end
+
+ context 'when issue got moved' do
+ let(:public_project) { create(:project, :public) }
+ let(:member) { create(:user) }
+ let(:non_member) { create(:user) }
+ let(:issue) { create(:issue, project: public_project) }
+
+ before do
+ project.add_developer(member)
+ public_project.add_developer(member)
+ Issues::MoveService.new(public_project, member).execute(issue, project)
+ end
+
+ context 'when user cannot read target project' do
+ it 'does not return moved_to_id' do
+ request = double('request', current_user: non_member)
+
+ response = described_class.new(issue, request: request).as_json
+
+ expect(response[:moved_to_id]).to be_nil
+ end
+ end
+
+ context 'when user can read target project' do
+ it 'returns moved moved_to_id' do
+ request = double('request', current_user: member)
+
+ response = described_class.new(issue, request: request).as_json
+
+ expect(response[:moved_to_id]).to eq(issue.moved_to_id)
+ end
+ end
+ end
end
diff --git a/spec/services/merge_requests/build_service_spec.rb b/spec/services/merge_requests/build_service_spec.rb
index 5c3b209086c..f18239f6d39 100644
--- a/spec/services/merge_requests/build_service_spec.rb
+++ b/spec/services/merge_requests/build_service_spec.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
require 'spec_helper'
describe MergeRequests::BuildService do
@@ -225,6 +224,11 @@ describe MergeRequests::BuildService do
let(:label_ids) { [label2.id] }
let(:milestone_id) { milestone2.id }
+ before do
+ # Guests are not able to assign labels or milestones to an issue
+ project.add_developer(user)
+ end
+
it 'assigns milestone_id and label_ids instead of issue labels and milestone' do
expect(merge_request.milestone).to eq(milestone2)
expect(merge_request.labels).to match_array([label2])
@@ -479,4 +483,35 @@ describe MergeRequests::BuildService do
end
end
end
+
+ context 'when assigning labels' do
+ let(:label_ids) { [create(:label, project: project).id] }
+
+ context 'for members with less than developer access' do
+ it 'is not allowed' do
+ expect(merge_request.label_ids).to be_empty
+ end
+ end
+
+ context 'for users allowed to assign labels' do
+ before do
+ project.add_developer(user)
+ end
+
+ context 'for labels in the project' do
+ it 'is allowed for developers' do
+ expect(merge_request.label_ids).to contain_exactly(*label_ids)
+ end
+ end
+
+ context 'for unrelated labels' do
+ let(:project_label) { create(:label, project: project) }
+ let(:label_ids) { [create(:label).id, project_label.id] }
+
+ it 'only assigns related labels' do
+ expect(merge_request.label_ids).to contain_exactly(project_label.id)
+ end
+ end
+ end
+ end
end
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index 6ef5f46c81b..6994b6687fc 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -3,6 +3,7 @@ SimpleCovEnv.start!
ENV["RAILS_ENV"] = 'test'
ENV["IN_MEMORY_APPLICATION_SETTINGS"] = 'true'
+ENV["RSPEC_ALLOW_INVALID_URLS"] = 'true'
require File.expand_path('../config/environment', __dir__)
require 'rspec/rails'
diff --git a/spec/support/shared_examples/controllers/uploads_actions_shared_examples.rb b/spec/support/shared_examples/controllers/uploads_actions_shared_examples.rb
index 97b2a01576c..39d13cccb13 100644
--- a/spec/support/shared_examples/controllers/uploads_actions_shared_examples.rb
+++ b/spec/support/shared_examples/controllers/uploads_actions_shared_examples.rb
@@ -76,6 +76,16 @@ shared_examples 'handle uploads' do
UploadService.new(model, jpg, uploader_class).execute
end
+ context 'when accessing a specific upload via different model' do
+ it 'responds with status 404' do
+ params.merge!(other_params)
+
+ show_upload
+
+ expect(response).to have_gitlab_http_status(404)
+ end
+ end
+
context "when the model is public" do
before do
model.update_attribute(:visibility_level, Gitlab::VisibilityLevel::PUBLIC)
diff --git a/spec/uploaders/records_uploads_spec.rb b/spec/uploaders/records_uploads_spec.rb
index 42352f9b9f8..6134137d2b7 100644
--- a/spec/uploaders/records_uploads_spec.rb
+++ b/spec/uploaders/records_uploads_spec.rb
@@ -85,6 +85,27 @@ describe RecordsUploads do
expect { existing.reload }.to raise_error(ActiveRecord::RecordNotFound)
expect(Upload.count).to eq(1)
end
+
+ it 'does not affect other uploads with different model but the same path' do
+ project = create(:project)
+ other_project = create(:project)
+
+ uploader = RecordsUploadsExampleUploader.new(other_project)
+
+ upload_for_project = Upload.create!(
+ path: File.join('uploads', 'rails_sample.jpg'),
+ size: 512.kilobytes,
+ model: project,
+ uploader: uploader.class.to_s
+ )
+
+ uploader.store!(upload_fixture('rails_sample.jpg'))
+
+ upload_for_project_fresh = Upload.find(upload_for_project.id)
+
+ expect(upload_for_project).to eq(upload_for_project_fresh)
+ expect(Upload.count).to eq(2)
+ end
end
describe '#destroy_upload callback' do