Commit 01b5c0ce authored by Nick Thomas's avatar Nick Thomas

Merge branch '30769-add-deploy-key-id' into 'master'

[RUN AS-IF-FOSS] Add association between DeployKey and PushAccessLevel

See merge request gitlab-org/gitlab!47305
parents 43d5be5f 86f72fc3
......@@ -13,9 +13,13 @@ module BranchesHelper
return [] unless access_levels
access_levels.map do |level|
if level.type == :deploy_key
{ id: level.id, type: level.type, deploy_key_id: level.deploy_key_id }
else
{ id: level.id, type: :role, access_level: level.access_level }
end
end
end
end
BranchesHelper.prepend_if_ee('EE::BranchesHelper')
......@@ -36,10 +36,12 @@ module ProtectedRefAccess
HUMAN_ACCESS_LEVELS[self.access_level]
end
# CE access levels are always role-based,
# where as EE allows groups and users too
def type
:role
end
def role?
true
type == :role
end
def check_access(user)
......
......@@ -6,6 +6,7 @@ class DeployKey < Key
has_many :deploy_keys_projects, inverse_of: :deploy_key, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
has_many :projects, through: :deploy_keys_projects
has_many :protected_branch_push_access_levels, class_name: '::ProtectedBranch::PushAccessLevel'
scope :in_projects, ->(projects) { joins(:deploy_keys_projects).where(deploy_keys_projects: { project_id: projects }) }
scope :with_write_access, -> { joins(:deploy_keys_projects).merge(DeployKeysProject.with_write_access) }
......
......@@ -2,4 +2,29 @@
class ProtectedBranch::PushAccessLevel < ApplicationRecord
include ProtectedBranchAccess
belongs_to :deploy_key
validates :access_level, uniqueness: { scope: :protected_branch_id, if: :role?,
conditions: -> { where(user_id: nil, group_id: nil, deploy_key_id: nil) } }
validates :deploy_key_id, uniqueness: { scope: :protected_branch_id, allow_nil: true }
validate :validate_deploy_key_membership
def type
if self.deploy_key.present?
:deploy_key
else
super
end
end
private
def validate_deploy_key_membership
return unless deploy_key
unless project.deploy_keys_projects.where(deploy_key: deploy_key).exists?
self.errors.add(:deploy_key, 'is not enabled for this project')
end
end
end
......@@ -26,6 +26,8 @@ module EE
name: level.user.name,
avatar_url: level.user.avatar_url
}
elsif level.type == :deploy_key
{ id: level.id, type: level.type, deploy_key_id: level.deploy_key_id }
elsif level.type == :group
{ id: level.id, type: level.type, group_id: level.group_id }
else
......
......@@ -44,20 +44,15 @@ module EE
end
end
override :type
def type
if self.user.present?
:user
elsif self.group.present?
:group
else
:role
end
super
end
# Is this a role-based access level?
override :role?
def role?
type == :role
end
override :humanize
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe BranchesHelper do
describe '#access_levels_data' do
subject { helper.access_levels_data(access_levels) }
context 'when access_levels is nil' do
let(:access_levels) { nil }
it { is_expected.to be_empty }
end
context 'when access levels are provided' do
let(:group) { create(:group) }
let!(:project) { create(:project) }
let!(:protected_branch) { create(:protected_branch, :developers_can_merge, :maintainers_can_push, project: project) }
let!(:deploy_key) { create(:deploy_key, deploy_keys_projects: [create(:deploy_keys_project, :write_access, project: project)]) }
let(:user) { create(:user, maintainer_projects: [project]) }
let(:merge_level) { protected_branch.merge_access_levels.first }
let(:push_level) { protected_branch.push_access_levels.first }
let(:deploy_key_push_level) { create(:protected_branch_push_access_level, protected_branch: protected_branch, deploy_key: deploy_key) }
let(:user_push_level) { create(:protected_branch_push_access_level, protected_branch: protected_branch, user: user) }
let(:group_push_level) { create(:protected_branch_push_access_level, protected_branch: protected_branch, group: group) }
let(:access_levels) { [merge_level, push_level, deploy_key_push_level, user_push_level, group_push_level] }
before do
create(:project_group_link, group: group, project: project)
end
it 'returns the correct array' do
expected_array = [
{ id: merge_level.id, type: :role, access_level: Gitlab::Access::DEVELOPER },
{ id: push_level.id, type: :role, access_level: Gitlab::Access::MAINTAINER },
{ id: deploy_key_push_level.id, type: :deploy_key, deploy_key_id: deploy_key.id },
{ id: user_push_level.id, type: :user, user_id: user.id, username: user.username, name: user.name, avatar_url: user.avatar_url },
{ id: group_push_level.id, type: :group, group_id: group.id }
]
expect(subject).to eq(expected_array)
end
end
end
end
......@@ -3,6 +3,7 @@
FactoryBot.define do
factory :protected_branch_push_access_level, class: 'ProtectedBranch::PushAccessLevel' do
protected_branch
deploy_key { nil }
access_level { Gitlab::Access::DEVELOPER }
end
end
......@@ -28,5 +28,23 @@ RSpec.describe BranchesHelper do
expect(subject).to eq(expected_array)
end
end
context 'when an access level tied to a deploy key is provided' do
let!(:protected_branch) { create(:protected_branch, :no_one_can_push) }
let!(:deploy_key) { create(:deploy_key, deploy_keys_projects: [create(:deploy_keys_project, :write_access, project: protected_branch.project)]) }
let(:push_level) { protected_branch.push_access_levels.first }
let(:deploy_key_push_level) { create(:protected_branch_push_access_level, protected_branch: protected_branch, deploy_key: deploy_key) }
let(:access_levels) { [push_level, deploy_key_push_level] }
it 'returns the correct array' do
expected_array = [
{ id: push_level.id, type: :role, access_level: Gitlab::Access::NO_ACCESS },
{ id: deploy_key_push_level.id, type: :deploy_key, deploy_key_id: deploy_key.id }
]
expect(subject).to eq(expected_array)
end
end
end
end
......@@ -321,6 +321,7 @@ push_access_levels:
- protected_branch
- user
- group
- deploy_key
create_access_levels:
- user
- protected_tag
......
......@@ -6,6 +6,7 @@ RSpec.describe DeployKey, :mailer do
describe "Associations" do
it { is_expected.to have_many(:deploy_keys_projects) }
it { is_expected.to have_many(:projects) }
it { is_expected.to have_many(:protected_branch_push_access_levels) }
end
describe 'notification' do
......
......@@ -4,4 +4,34 @@ require 'spec_helper'
RSpec.describe ProtectedBranch::PushAccessLevel do
it { is_expected.to validate_inclusion_of(:access_level).in_array([Gitlab::Access::MAINTAINER, Gitlab::Access::DEVELOPER, Gitlab::Access::NO_ACCESS]) }
describe 'associations' do
it { is_expected.to belong_to(:deploy_key) }
end
describe 'validations' do
it 'is not valid when a record exists with the same access level' do
protected_branch = create(:protected_branch)
create(:protected_branch_push_access_level, protected_branch: protected_branch)
level = build(:protected_branch_push_access_level, protected_branch: protected_branch)
expect(level).to be_invalid
end
it 'is not valid when a record exists with the same access level' do
protected_branch = create(:protected_branch)
deploy_key = create(:deploy_key, projects: [protected_branch.project])
create(:protected_branch_push_access_level, protected_branch: protected_branch, deploy_key: deploy_key)
level = build(:protected_branch_push_access_level, protected_branch: protected_branch, deploy_key: deploy_key)
expect(level).to be_invalid
end
it 'checks that a deploy key is enabled for the same project as the protected branch\'s' do
level = build(:protected_branch_push_access_level, deploy_key: create(:deploy_key))
expect { level.save! }.to raise_error
expect(level.errors.full_messages).to contain_exactly('Deploy key is not enabled for this project')
end
end
end
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