Commit 950b64ca authored by James Edwards-Jones's avatar James Edwards-Jones

ProtectedBranchPolicy checks unprotect access levels

parent 557c6628
......@@ -4,7 +4,8 @@ module ProtectedRefAccess
ALLOWED_ACCESS_LEVELS = [
Gitlab::Access::MASTER,
Gitlab::Access::DEVELOPER,
Gitlab::Access::NO_ACCESS
Gitlab::Access::NO_ACCESS,
Gitlab::Access::ADMIN
].freeze
HUMAN_ACCESS_LEVELS = {
......
......@@ -2,6 +2,7 @@ class ProtectedBranch < ActiveRecord::Base
include Gitlab::ShellAdapter
include ProtectedRef
prepend EE::ProtectedRef
prepend EE::ProtectedBranch
protected_ref_access_levels :merge, :push
......
class ProtectedBranchPolicy < BasePolicy
prepend EE::ProtectedBranchPolicy
delegate { @subject.project }
rule { can?(:admin_project) }.policy do
......
......@@ -5,5 +5,13 @@ module EE
included do
protected_ref_access_levels :unprotect
end
def can_unprotect?(user)
return true if unprotect_access_levels.empty?
unprotect_access_levels.any? do |access_level|
access_level.check_access(user)
end
end
end
end
......@@ -29,8 +29,9 @@ module EE
has_many :approvers, dependent: :destroy # rubocop: disable Cop/ActiveRecordDependent
# Protected Branch Access
has_many :protected_branch_merge_access_levels, dependent: :destroy, class_name: ProtectedBranch::MergeAccessLevel # rubocop:disable Cop/ActiveRecordDependent
has_many :protected_branch_push_access_levels, dependent: :destroy, class_name: ProtectedBranch::PushAccessLevel # rubocop:disable Cop/ActiveRecordDependent
has_many :protected_branch_merge_access_levels, dependent: :destroy, class_name: ::ProtectedBranch::MergeAccessLevel # rubocop:disable Cop/ActiveRecordDependent
has_many :protected_branch_push_access_levels, dependent: :destroy, class_name: ::ProtectedBranch::PushAccessLevel # rubocop:disable Cop/ActiveRecordDependent
has_many :protected_branch_unprotect_access_levels, dependent: :destroy, class_name: ::ProtectedBranch::UnprotectAccessLevel # rubocop:disable Cop/ActiveRecordDependent
end
module ClassMethods
......
......@@ -53,6 +53,7 @@ class License < ActiveRecord::Base
object_storage
group_saml
service_desk
unprotection_restrictions
variable_environment_scope
reject_unsigned_commits
commit_committer_check
......
module EE
module ProtectedBranchPolicy
extend ActiveSupport::Concern
prepended do
condition(:can_unprotect) do
@subject.can_unprotect?(@user)
end
condition(:unprotect_restrictions_enabled, scope: :subject) do
@subject.project.feature_available?(:unprotection_restrictions)
end
rule { unprotect_restrictions_enabled & ~can_unprotect }.policy do
prevent :create_protected_branch # Prevent a user creating a rule they wouldn't be able to update or destroy
prevent :update_protected_branch
prevent :destroy_protected_branch
end
end
end
end
require 'spec_helper'
describe ProtectedBranch do
subject { create(:protected_branch) }
let(:project) { subject.project }
describe '#can_unprotect?' do
let(:user) { create(:user) }
let(:admin) { create(:user, :admin) }
let(:master) do
create(:user).tap { |user| project.add_master(user) }
end
context 'without unprotect_access_levels' do
it "doesn't add any additional restriction" do
expect(subject.can_unprotect?(user)).to eq true
end
end
context 'with access level set to MASTER' do
before do
subject.unprotect_access_levels.create!(access_level: Gitlab::Access::MASTER)
end
it 'defaults to requiring master access' do
expect(subject.can_unprotect?(user)).to eq false
expect(subject.can_unprotect?(master)).to eq true
expect(subject.can_unprotect?(admin)).to eq true
end
end
context 'with access level set to ADMIN' do
before do
subject.unprotect_access_levels.create!(access_level: Gitlab::Access::ADMIN)
end
it 'prevents access to masters' do
expect(subject.can_unprotect?(master)).to eq false
end
it 'grants access to admins' do
expect(subject.can_unprotect?(admin)).to eq true
end
end
context 'multiple access levels' do
before do
subject.unprotect_access_levels.create!(user: master)
subject.unprotect_access_levels.create!(user: user)
end
it 'grants access if any grant access' do
expect(subject.can_unprotect?(user)).to eq true
end
end
end
end
require 'spec_helper'
describe ProtectedBranchPolicy do
let(:user) { create(:user) }
let(:name) { 'feature' }
let(:protected_branch) { create(:protected_branch, name: name) }
let(:project) { protected_branch.project }
let(:allowed_group) { create(:group) }
subject { described_class.new(user, protected_branch) }
before do
project.add_master(user)
end
context 'when unprotection is limited by access levels' do
before do
protected_branch.unprotect_access_levels.create!(group: allowed_group)
end
context 'when unprotection restriction feature is unlicensed' do
it "users can remove protections" do
is_expected.to be_allowed(:update_protected_branch)
is_expected.to be_allowed(:destroy_protected_branch)
end
end
context 'when unprotection restriction feature is licensed' do
before do
stub_licensed_features(unprotection_restrictions: true)
end
it "users can't remove protections without specific access" do
is_expected.not_to be_allowed(:update_protected_branch)
is_expected.not_to be_allowed(:destroy_protected_branch)
end
context "and access levels grant the user control" do
before do
allowed_group.add_user(user, :guest)
end
it 'users can manage protections' do
is_expected.to be_allowed(:update_protected_branch)
is_expected.to be_allowed(:update_protected_branch)
is_expected.to be_allowed(:destroy_protected_branch)
end
end
end
end
context 'creating restrictions' do
let(:unprotect_access_levels) { [{ group_id: allowed_group.id }] }
let(:protected_branch) { build(:protected_branch, name: name, unprotect_access_levels_attributes: unprotect_access_levels) }
before do
stub_licensed_features(unprotection_restrictions: true)
end
it "is prevented if the user wouldn't be able to remove the restriction" do
is_expected.not_to be_allowed(:create_protected_branch)
end
context 'when the user can remove the restriction' do
before do
allowed_group.add_user(user, :guest)
end
it "is allowed" do
is_expected.to be_allowed(:create_protected_branch)
end
end
end
end
......@@ -15,6 +15,7 @@ module Gitlab
DEVELOPER = 30
MASTER = 40
OWNER = 50
ADMIN = 60
# Branch protection settings
PROTECTION_NONE = 0
......
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