summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordrew cimino <dcimino@gitlab.com>2019-06-28 10:40:34 -0400
committerdrew cimino <dcimino@gitlab.com>2019-07-05 11:40:31 -0400
commit51f506cacddcac58edfd832bf8beead3135a11b1 (patch)
tree2ca1691dc7a46dde8393b04c357bcbc12a41a3cc
parent08a51a9db938bb05f9a4c999075d010079e16bad (diff)
downloadgitlab-ce-51f506cacddcac58edfd832bf8beead3135a11b1.tar.gz
Use MergeRequest#source_project as permissions reference for MergeRequest#all_pipelines
MergeRequest#all_pipelines fetches Ci::Pipeline records from the source project, so we should specifically check that project for permissions. This was already happening for intra-project merge requests, but in the event that the target and source projects both have private builds, we should ensure that the project permissions are respected.
-rw-r--r--app/controllers/projects/merge_requests/application_controller.rb2
-rw-r--r--app/controllers/projects/merge_requests_controller.rb3
-rw-r--r--changelogs/unreleased/security-mr-pipeline-permissions.yml5
-rw-r--r--spec/controllers/projects/merge_requests_controller_spec.rb98
4 files changed, 102 insertions, 6 deletions
diff --git a/app/controllers/projects/merge_requests/application_controller.rb b/app/controllers/projects/merge_requests/application_controller.rb
index f2a6268b3e9..60eddcbab0e 100644
--- a/app/controllers/projects/merge_requests/application_controller.rb
+++ b/app/controllers/projects/merge_requests/application_controller.rb
@@ -45,7 +45,7 @@ class Projects::MergeRequests::ApplicationController < Projects::ApplicationCont
def set_pipeline_variables
@pipelines =
- if can?(current_user, :read_pipeline, @project)
+ if can?(current_user, :read_pipeline, @merge_request.source_project)
@merge_request.all_pipelines
else
Ci::Pipeline.none
diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb
index 9e7e3ed5afb..97238dbb385 100644
--- a/app/controllers/projects/merge_requests_controller.rb
+++ b/app/controllers/projects/merge_requests_controller.rb
@@ -82,7 +82,8 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
end
def pipelines
- @pipelines = @merge_request.all_pipelines.page(params[:page]).per(30)
+ set_pipeline_variables
+ @pipelines = @pipelines.page(params[:page]).per(30)
Gitlab::PollingInterval.set_header(response, interval: 10_000)
diff --git a/changelogs/unreleased/security-mr-pipeline-permissions.yml b/changelogs/unreleased/security-mr-pipeline-permissions.yml
new file mode 100644
index 00000000000..a317c93228c
--- /dev/null
+++ b/changelogs/unreleased/security-mr-pipeline-permissions.yml
@@ -0,0 +1,5 @@
+---
+title: Use source project as permissions reference for MergeRequestsController#pipelines
+merge_request:
+author:
+type: security
diff --git a/spec/controllers/projects/merge_requests_controller_spec.rb b/spec/controllers/projects/merge_requests_controller_spec.rb
index 34cbf0c8723..2408ff1177b 100644
--- a/spec/controllers/projects/merge_requests_controller_spec.rb
+++ b/spec/controllers/projects/merge_requests_controller_spec.rb
@@ -623,10 +623,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