Commit 6e35cb37 authored by Heinrich Lee Yu's avatar Heinrich Lee Yu

Merge branch '30769-deploy-key-access' into 'master'

Added DeployKeyAccess class

See merge request gitlab-org/gitlab!48226
parents 71e64878 821cf240
......@@ -18,6 +18,14 @@ class ProtectedBranch::PushAccessLevel < ApplicationRecord
end
end
def check_access(user)
if Feature.enabled?(:deploy_keys_on_protected_branches, project) && user && deploy_key.present?
return true if user.can?(:read_project, project) && enabled_deploy_key_for_user?(deploy_key, user)
end
super
end
private
def validate_deploy_key_membership
......@@ -27,4 +35,10 @@ class ProtectedBranch::PushAccessLevel < ApplicationRecord
self.errors.add(:deploy_key, 'is not enabled for this project')
end
end
def enabled_deploy_key_for_user?(deploy_key, user)
return false unless deploy_key.user_id == user.id
DeployKey.with_write_access_for_project(protected_branch.project, deploy_key: deploy_key).any?
end
end
# frozen_string_literal: true
module Gitlab
class DeployKeyAccess < UserAccess
def initialize(deploy_key, container: nil)
@deploy_key = deploy_key
@user = deploy_key.user
@container = container
end
private
attr_reader :deploy_key
def protected_tag_accessible_to?(ref, action:)
assert_project!
# a deploy key can always push a protected tag
# (which is not always the case when pushing to a protected branch)
true
end
def can_collaborate?(_ref)
assert_project!
project_has_active_user_keys?
end
def project_has_active_user_keys?
user.can?(:read_project, project) && DeployKey.with_write_access_for_project(project).id_in(deploy_key.id).exists?
end
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Gitlab::DeployKeyAccess do
let_it_be(:user) { create(:user) }
let_it_be(:deploy_key) { create(:deploy_key, user: user) }
let(:project) { create(:project, :repository) }
let(:protected_branch) { create(:protected_branch, :no_one_can_push, project: project) }
subject(:access) { described_class.new(deploy_key, container: project) }
before do
project.add_guest(user)
create(:deploy_keys_project, :write_access, project: project, deploy_key: deploy_key)
end
describe '#can_create_tag?' do
context 'push tag that matches a protected tag pattern via a deploy key' do
it 'still pushes that tag' do
create(:protected_tag, project: project, name: 'v*')
expect(access.can_create_tag?('v0.1.2')).to be_truthy
end
end
end
describe '#can_push_to_branch?' do
context 'push to a protected branch of this project via a deploy key' do
before do
create(:protected_branch_push_access_level, protected_branch: protected_branch, deploy_key: deploy_key)
end
context 'when the project has active deploy key owned by this user' do
it 'returns true' do
expect(access.can_push_to_branch?(protected_branch.name)).to be_truthy
end
end
context 'when the project has active deploy keys, but not by this user' do
let(:deploy_key) { create(:deploy_key, user: create(:user)) }
it 'returns false' do
expect(access.can_push_to_branch?(protected_branch.name)).to be_falsey
end
end
context 'when there is another branch no one can push to' do
let(:another_branch) { create(:protected_branch, :no_one_can_push, name: 'another_branch', project: project) }
it 'returns false when trying to push to that other branch' do
expect(access.can_push_to_branch?(another_branch.name)).to be_falsey
end
context 'and the deploy key added for the first protected branch is also added for this other branch' do
it 'returns true for both protected branches' do
create(:protected_branch_push_access_level, protected_branch: another_branch, deploy_key: deploy_key)
expect(access.can_push_to_branch?(protected_branch.name)).to be_truthy
expect(access.can_push_to_branch?(another_branch.name)).to be_truthy
end
end
end
end
end
end
......@@ -34,4 +34,45 @@ RSpec.describe ProtectedBranch::PushAccessLevel do
expect(level.errors.full_messages).to contain_exactly('Deploy key is not enabled for this project')
end
end
describe '#check_access' do
let_it_be(:project) { create(:project) }
let_it_be(:protected_branch) { create(:protected_branch, :no_one_can_push, project: project) }
let_it_be(:user) { create(:user) }
let_it_be(:deploy_key) { create(:deploy_key, user: user) }
let!(:deploy_keys_project) { create(:deploy_keys_project, project: project, deploy_key: deploy_key, can_push: can_push) }
let(:can_push) { true }
before_all do
project.add_guest(user)
end
context 'when this push_access_level is tied to a deploy key' do
let(:push_access_level) { create(:protected_branch_push_access_level, protected_branch: protected_branch, deploy_key: deploy_key) }
context 'when the deploy key is among the active keys for this project' do
specify do
expect(push_access_level.check_access(user)).to be_truthy
end
context 'when the deploy_keys_on_protected_branches FF is false' do
before do
stub_feature_flags(deploy_keys_on_protected_branches: false)
end
it 'is false' do
expect(push_access_level.check_access(user)).to be_falsey
end
end
end
context 'when the deploy key is not among the active keys of this project' do
let(:can_push) { false }
it 'is false' do
expect(push_access_level.check_access(user)).to be_falsey
end
end
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