diff --git a/lib/api/commits.rb b/lib/api/commits.rb index 964780cba6a..92329465b2c 100644 --- a/lib/api/commits.rb +++ b/lib/api/commits.rb @@ -6,6 +6,18 @@ module API before { authorize! :download_code, user_project } + helpers do + def user_access + @user_access ||= Gitlab::UserAccess.new(current_user, project: user_project) + end + + def authorize_push_to_branch!(branch) + unless user_access.can_push_to_branch?(branch) + forbidden!("You are not allowed to push into this branch") + end + end + end + params do requires :id, type: String, desc: 'The ID of a project' end @@ -67,7 +79,7 @@ module API optional :author_name, type: String, desc: 'Author name for commit' end post ':id/repository/commits' do - authorize! :push_code, user_project + authorize_push_to_branch!(params[:branch]) attrs = declared_params attrs[:branch_name] = attrs.delete(:branch) @@ -142,7 +154,7 @@ module API requires :branch, type: String, desc: 'The name of the branch' end post ':id/repository/commits/:sha/cherry_pick', requirements: API::COMMIT_ENDPOINT_REQUIREMENTS do - authorize! :push_code, user_project + authorize_push_to_branch!(params[:branch]) commit = user_project.commit(params[:sha]) not_found!('Commit') unless commit diff --git a/spec/requests/api/commits_spec.rb b/spec/requests/api/commits_spec.rb index 113703fac38..246947e58a8 100644 --- a/spec/requests/api/commits_spec.rb +++ b/spec/requests/api/commits_spec.rb @@ -514,6 +514,38 @@ describe API::Commits do expect(response).to have_gitlab_http_status(400) end end + + context 'when committing into a fork as a maintainer' do + include_context 'merge request allowing collaboration' + + let(:project_id) { forked_project.id } + + def push_params(branch_name) + { + branch: branch_name, + commit_message: 'Hello world', + actions: [ + { + action: 'create', + file_path: 'foo/bar/baz.txt', + content: 'puts 8' + } + ] + } + end + + it 'allows pushing to the source branch of the merge request' do + post api(url, user), push_params('feature') + + expect(response).to have_gitlab_http_status(:created) + end + + it 'denies pushing to another branch' do + post api(url, user), push_params('other-branch') + + expect(response).to have_gitlab_http_status(:forbidden) + end + end end describe 'GET /projects/:id/repository/commits/:sha/refs' do @@ -1065,11 +1097,29 @@ describe API::Commits do it 'returns 400 if you are not allowed to push to the target branch' do post api(route, current_user), branch: 'feature' - expect(response).to have_gitlab_http_status(400) - expect(json_response['message']).to eq('You are not allowed to push into this branch') + expect(response).to have_gitlab_http_status(:forbidden) + expect(json_response['message']).to match(/You are not allowed to push into this branch/) end end end + + context 'when cherry picking to a fork as a maintainer' do + include_context 'merge request allowing collaboration' + + let(:project_id) { forked_project.id } + + it 'allows access from a maintainer that to the source branch' do + post api(route, user), branch: 'feature' + + expect(response).to have_gitlab_http_status(:created) + end + + it 'denies cherry picking to another branch' do + post api(route, user), branch: 'master' + + expect(response).to have_gitlab_http_status(:forbidden) + end + end end describe 'POST /projects/:id/repository/commits/:sha/comments' do diff --git a/spec/support/shared_contexts/merge_requests_allowing_collaboration.rb b/spec/support/shared_contexts/merge_requests_allowing_collaboration.rb new file mode 100644 index 00000000000..05424d08b9d --- /dev/null +++ b/spec/support/shared_contexts/merge_requests_allowing_collaboration.rb @@ -0,0 +1,15 @@ +shared_context 'merge request allowing collaboration' do + include ProjectForksHelper + + let(:canonical) { create(:project, :public, :repository) } + let(:forked_project) { fork_project(canonical, nil, repository: true) } + + before do + canonical.add_maintainer(user) + create(:merge_request, + target_project: canonical, + source_project: forked_project, + source_branch: 'feature', + allow_collaboration: true) + end +end