Commit 35a49922 authored by Bob Van Landuyt's avatar Bob Van Landuyt

Allow admins to push to empty repos

parent aeed6b5a
...@@ -31,7 +31,7 @@ module ProtectedRef ...@@ -31,7 +31,7 @@ module ProtectedRef
end end
end end
def protected_ref_accessible_to?(ref, user, action:, protected_refs: nil) def protected_ref_accessible_to?(ref, user, project:, action:, protected_refs: nil)
access_levels_for_ref(ref, action: action, protected_refs: protected_refs).any? do |access_level| access_levels_for_ref(ref, action: action, protected_refs: protected_refs).any? do |access_level|
access_level.check_access(user) access_level.check_access(user)
end end
......
...@@ -1041,13 +1041,6 @@ class Project < ActiveRecord::Base ...@@ -1041,13 +1041,6 @@ class Project < ActiveRecord::Base
"#{web_url}.git" "#{web_url}.git"
end end
def user_can_push_to_empty_repo?(user)
return false unless empty_repo?
return false unless Ability.allowed?(user, :push_code, self)
!ProtectedBranch.default_branch_protected? || team.max_member_access(user.id) > Gitlab::Access::DEVELOPER
end
def forked? def forked?
return true if fork_network && fork_network.root_project != self return true if fork_network && fork_network.root_project != self
...@@ -2008,10 +2001,11 @@ class Project < ActiveRecord::Base ...@@ -2008,10 +2001,11 @@ class Project < ActiveRecord::Base
def fetch_branch_allows_maintainer_push?(user, branch_name) def fetch_branch_allows_maintainer_push?(user, branch_name)
check_access = -> do check_access = -> do
next false if empty_repo?
merge_request = source_of_merge_requests.opened merge_request = source_of_merge_requests.opened
.where(allow_maintainer_to_push: true) .where(allow_maintainer_to_push: true)
.find_by(source_branch: branch_name) .find_by(source_branch: branch_name)
merge_request&.can_be_merged_by?(user) merge_request&.can_be_merged_by?(user)
end end
......
...@@ -4,6 +4,15 @@ class ProtectedBranch < ActiveRecord::Base ...@@ -4,6 +4,15 @@ class ProtectedBranch < ActiveRecord::Base
protected_ref_access_levels :merge, :push protected_ref_access_levels :merge, :push
def self.protected_ref_accessible_to?(ref, user, project:, action:, protected_refs: nil)
# Masters, owners and admins are allowed to create the default branch
if default_branch_protected? && project.empty_repo?
return true if user.admin? || project.team.max_member_access(user.id) > Gitlab::Access::DEVELOPER
end
super
end
# Check if branch name is marked as protected in the system # Check if branch name is marked as protected in the system
def self.protected?(project, ref_name) def self.protected?(project, ref_name)
return true if project.empty_repo? && default_branch_protected? return true if project.empty_repo? && default_branch_protected?
......
---
title: Fix errors on pushing to an empty repository
merge_request: 18462
author:
type: fixed
...@@ -63,10 +63,12 @@ module Gitlab ...@@ -63,10 +63,12 @@ module Gitlab
request_cache def can_push_to_branch?(ref) request_cache def can_push_to_branch?(ref)
return false unless can_access_git? return false unless can_access_git?
return false unless user.can?(:push_code, project) || project.branch_allows_maintainer_push?(user, ref) return false unless project
return false if !user.can?(:push_code, project) && !project.branch_allows_maintainer_push?(user, ref)
if protected?(ProtectedBranch, project, ref) if protected?(ProtectedBranch, project, ref)
project.user_can_push_to_empty_repo?(user) || protected_branch_accessible_to?(ref, action: :push) protected_branch_accessible_to?(ref, action: :push)
else else
true true
end end
...@@ -101,6 +103,7 @@ module Gitlab ...@@ -101,6 +103,7 @@ module Gitlab
def protected_branch_accessible_to?(ref, action:) def protected_branch_accessible_to?(ref, action:)
ProtectedBranch.protected_ref_accessible_to?( ProtectedBranch.protected_ref_accessible_to?(
ref, user, ref, user,
project: project,
action: action, action: action,
protected_refs: project.protected_branches) protected_refs: project.protected_branches)
end end
...@@ -108,6 +111,7 @@ module Gitlab ...@@ -108,6 +111,7 @@ module Gitlab
def protected_tag_accessible_to?(ref, action:) def protected_tag_accessible_to?(ref, action:)
ProtectedTag.protected_ref_accessible_to?( ProtectedTag.protected_ref_accessible_to?(
ref, user, ref, user,
project: project,
action: action, action: action,
protected_refs: project.protected_tags) protected_refs: project.protected_tags)
end end
......
...@@ -151,6 +151,13 @@ FactoryBot.define do ...@@ -151,6 +151,13 @@ FactoryBot.define do
end end
end end
trait :stubbed_repository do
after(:build) do |project|
allow(project).to receive(:empty_repo?).and_return(false)
allow(project.repository).to receive(:empty?).and_return(false)
end
end
trait :wiki_repo do trait :wiki_repo do
after(:create) do |project| after(:create) do |project|
raise 'Failed to create wiki repository!' unless project.create_wiki raise 'Failed to create wiki repository!' unless project.create_wiki
......
require 'spec_helper'
feature 'User creates blob in new project', :js do
let(:user) { create(:user) }
let(:project) { create(:project, :empty_repo) }
shared_examples 'creating a file' do
before do
sign_in(user)
visit project_path(project)
end
it 'allows the user to add a new file' do
click_link 'New file'
find('#editor')
execute_script('ace.edit("editor").setValue("Hello world")')
fill_in(:file_name, with: 'dummy-file')
click_button('Commit changes')
expect(page).to have_content('The file has been successfully created')
end
end
describe 'as a master' do
before do
project.add_master(user)
end
it_behaves_like 'creating a file'
end
describe 'as an admin' do
let(:user) { create(:user, :admin) }
it_behaves_like 'creating a file'
end
describe 'as a developer' do
before do
project.add_developer(user)
sign_in(user)
visit project_path(project)
end
it 'does not allow pushing to the default branch' do
expect(page).not_to have_content('New file')
end
end
end
...@@ -2,8 +2,8 @@ require 'spec_helper' ...@@ -2,8 +2,8 @@ require 'spec_helper'
describe Gitlab::Ci::Status::Build::Play do describe Gitlab::Ci::Status::Build::Play do
let(:user) { create(:user) } let(:user) { create(:user) }
let(:project) { build.project } let(:project) { create(:project, :stubbed_repository) }
let(:build) { create(:ci_build, :manual) } let(:build) { create(:ci_build, :manual, project: project) }
let(:status) { Gitlab::Ci::Status::Core.new(build, user) } let(:status) { Gitlab::Ci::Status::Core.new(build, user) }
subject { described_class.new(status) } subject { described_class.new(status) }
...@@ -46,6 +46,8 @@ describe Gitlab::Ci::Status::Build::Play do ...@@ -46,6 +46,8 @@ describe Gitlab::Ci::Status::Build::Play do
context 'when user can not push to the branch' do context 'when user can not push to the branch' do
before do before do
build.project.add_developer(user) build.project.add_developer(user)
create(:protected_branch, :masters_can_push,
name: build.ref, project: project)
end end
it { is_expected.not_to have_action } it { is_expected.not_to have_action }
......
...@@ -32,6 +32,12 @@ describe Gitlab::UserAccess do ...@@ -32,6 +32,12 @@ describe Gitlab::UserAccess do
let(:empty_project) { create(:project_empty_repo) } let(:empty_project) { create(:project_empty_repo) }
let(:project_access) { described_class.new(user, project: empty_project) } let(:project_access) { described_class.new(user, project: empty_project) }
it 'returns true for admins' do
user.update!(admin: true)
expect(access.can_push_to_branch?('master')).to be_truthy
end
it 'returns true if user is master' do it 'returns true if user is master' do
empty_project.add_master(user) empty_project.add_master(user)
...@@ -71,6 +77,12 @@ describe Gitlab::UserAccess do ...@@ -71,6 +77,12 @@ describe Gitlab::UserAccess do
let(:branch) { create :protected_branch, project: project, name: "test" } let(:branch) { create :protected_branch, project: project, name: "test" }
let(:not_existing_branch) { create :protected_branch, :developers_can_merge, project: project } let(:not_existing_branch) { create :protected_branch, :developers_can_merge, project: project }
it 'returns true for admins' do
user.update!(admin: true)
expect(access.can_push_to_branch?(branch.name)).to be_truthy
end
it 'returns true if user is a master' do it 'returns true if user is a master' do
project.add_master(user) project.add_master(user)
......
require 'spec_helper' require 'spec_helper'
describe Environment do describe Environment do
let(:project) { create(:project) } let(:project) { create(:project, :stubbed_repository) }
subject(:environment) { create(:environment, project: project) } subject(:environment) { create(:environment, project: project) }
it { is_expected.to belong_to(:project) } it { is_expected.to belong_to(:project) }
...@@ -201,7 +201,7 @@ describe Environment do ...@@ -201,7 +201,7 @@ describe Environment do
end end
describe '#stop_with_action!' do describe '#stop_with_action!' do
let(:user) { create(:admin) } let(:user) { create(:user) }
subject { environment.stop_with_action!(user) } subject { environment.stop_with_action!(user) }
......
...@@ -1483,52 +1483,6 @@ describe Project do ...@@ -1483,52 +1483,6 @@ describe Project do
end end
end end
describe '#user_can_push_to_empty_repo?' do
let(:project) { create(:project) }
let(:user) { create(:user) }
it 'returns false when default_branch_protection is in full protection and user is developer' do
project.add_developer(user)
stub_application_setting(default_branch_protection: Gitlab::Access::PROTECTION_FULL)
expect(project.user_can_push_to_empty_repo?(user)).to be_falsey
end
it 'returns false when default_branch_protection only lets devs merge and user is dev' do
project.add_developer(user)
stub_application_setting(default_branch_protection: Gitlab::Access::PROTECTION_DEV_CAN_MERGE)
expect(project.user_can_push_to_empty_repo?(user)).to be_falsey
end
it 'returns true when default_branch_protection lets devs push and user is developer' do
project.add_developer(user)
stub_application_setting(default_branch_protection: Gitlab::Access::PROTECTION_DEV_CAN_PUSH)
expect(project.user_can_push_to_empty_repo?(user)).to be_truthy
end
it 'returns true when default_branch_protection is unprotected and user is developer' do
project.add_developer(user)
stub_application_setting(default_branch_protection: Gitlab::Access::PROTECTION_NONE)
expect(project.user_can_push_to_empty_repo?(user)).to be_truthy
end
it 'returns true when user is master' do
project.add_master(user)
expect(project.user_can_push_to_empty_repo?(user)).to be_truthy
end
it 'returns false when the repo is not empty' do
project.add_master(user)
expect(project).to receive(:empty_repo?).and_return(false)
expect(project.user_can_push_to_empty_repo?(user)).to be_falsey
end
end
describe '#container_registry_url' do describe '#container_registry_url' do
let(:project) { create(:project) } let(:project) { create(:project) }
......
...@@ -235,6 +235,8 @@ describe Ci::RetryPipelineService, '#execute' do ...@@ -235,6 +235,8 @@ describe Ci::RetryPipelineService, '#execute' do
context 'when user is not allowed to trigger manual action' do context 'when user is not allowed to trigger manual action' do
before do before do
project.add_developer(user) project.add_developer(user)
create(:protected_branch, :masters_can_push,
name: pipeline.ref, project: project)
end end
context 'when there is a failed manual action present' do context 'when there is a failed manual action present' do
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment