diff options
Diffstat (limited to 'lib/gitlab/user_access.rb')
-rw-r--r-- | lib/gitlab/user_access.rb | 77 |
1 files changed, 48 insertions, 29 deletions
diff --git a/lib/gitlab/user_access.rb b/lib/gitlab/user_access.rb index 1551548d9b4..1c6ddc2e70f 100644 --- a/lib/gitlab/user_access.rb +++ b/lib/gitlab/user_access.rb @@ -5,15 +5,16 @@ module Gitlab extend Gitlab::Cache::RequestCache request_cache_key do - [user&.id, project&.id] + [user&.id, container&.to_global_id] end - attr_reader :user - attr_accessor :project + attr_reader :user, :push_ability + attr_accessor :container - def initialize(user, project: nil) + def initialize(user, container: nil, push_ability: :push_code) @user = user - @project = project + @container = container + @push_ability = push_ability end def can_do_action?(action) @@ -21,7 +22,7 @@ module Gitlab permission_cache[action] = permission_cache.fetch(action) do - user.can?(action, project) + user.can?(action, container) end end @@ -42,20 +43,20 @@ module Gitlab request_cache def can_create_tag?(ref) return false unless can_access_git? - if protected?(ProtectedTag, project, ref) + if protected?(ProtectedTag, ref) protected_tag_accessible_to?(ref, action: :create) else - user.can?(:admin_tag, project) + user.can?(:admin_tag, container) end end request_cache def can_delete_branch?(ref) return false unless can_access_git? - if protected?(ProtectedBranch, project, ref) - user.can?(:push_to_delete_protected_branch, project) + if protected?(ProtectedBranch, ref) + user.can?(:push_to_delete_protected_branch, container) else - user.can?(:push_code, project) + can_push? end end @@ -64,36 +65,36 @@ module Gitlab end request_cache def can_push_to_branch?(ref) - return false unless can_access_git? - return false unless project - - # Checking for an internal project to prevent an infinite loop: - # https://gitlab.com/gitlab-org/gitlab/issues/36805 - if project.internal? - return false unless user.can?(:push_code, project) - else - return false if !user.can?(:push_code, project) && !project.branch_allows_collaboration?(user, ref) - end + return false unless can_access_git? && container && can_collaborate?(ref) + return true unless protected?(ProtectedBranch, ref) - if protected?(ProtectedBranch, project, ref) - protected_branch_accessible_to?(ref, action: :push) - else - true - end + protected_branch_accessible_to?(ref, action: :push) end request_cache def can_merge_to_branch?(ref) return false unless can_access_git? - if protected?(ProtectedBranch, project, ref) + if protected?(ProtectedBranch, ref) protected_branch_accessible_to?(ref, action: :merge) else - user.can?(:push_code, project) + can_push? end end private + def can_push? + user.can?(push_ability, container) + end + + def can_collaborate?(ref) + assert_project! + + # Checking for an internal project or group to prevent an infinite loop: + # https://gitlab.com/gitlab-org/gitlab/issues/36805 + can_push? || (!project.internal? && project.branch_allows_collaboration?(user, ref)) + end + def permission_cache @permission_cache ||= {} end @@ -103,6 +104,8 @@ module Gitlab end def protected_branch_accessible_to?(ref, action:) + assert_project! + ProtectedBranch.protected_ref_accessible_to?( ref, user, project: project, @@ -111,6 +114,8 @@ module Gitlab end def protected_tag_accessible_to?(ref, action:) + assert_project! + ProtectedTag.protected_ref_accessible_to?( ref, user, project: project, @@ -118,8 +123,22 @@ module Gitlab protected_refs: project.protected_tags) end - request_cache def protected?(kind, project, refs) + request_cache def protected?(kind, refs) + assert_project! + kind.protected?(project, refs) end + + def project + container + end + + # Any method that assumes that it is operating on a project should make this + # explicit by calling `#assert_project!`. + # TODO: remove when we make this class polymorphic enough not to care about projects + # See: https://gitlab.com/gitlab-org/gitlab/-/issues/227635 + def assert_project! + raise "No project! #{project.inspect} is not a Project" unless project.is_a?(::Project) + end end end |