2019-02-15 15:39:39 +05:30
# frozen_string_literal: true
module Gitlab
module Checks
2021-09-04 01:27:46 +05:30
class BranchCheck < BaseSingleChecker
2019-02-15 15:39:39 +05:30
ERROR_MESSAGES = {
delete_default_branch : 'The default branch of a project cannot be deleted.' ,
force_push_protected_branch : 'You are not allowed to force push code to a protected branch on this project.' ,
non_master_delete_protected_branch : 'You are not allowed to delete protected branches from this project. Only a project maintainer or owner can delete a protected branch.' ,
non_web_delete_protected_branch : 'You can only delete protected branches using the web interface.' ,
merge_protected_branch : 'You are not allowed to merge code into protected branches on this project.' ,
2019-07-07 11:18:12 +05:30
push_protected_branch : 'You are not allowed to push code to protected branches on this project.' ,
create_protected_branch : 'You are not allowed to create protected branches on this project.' ,
invalid_commit_create_protected_branch : 'You can only use an existing protected branch ref as the basis of a new protected branch.' ,
2020-08-18 19:51:02 +05:30
non_web_create_protected_branch : 'You can only create protected branches using the web interface and API.' ,
prohibited_hex_branch_name : 'You cannot create a branch with a 40-character hexadecimal branch name.'
2019-02-15 15:39:39 +05:30
} . freeze
LOG_MESSAGES = {
delete_default_branch_check : " Checking if default branch is being deleted... " ,
protected_branch_checks : " Checking if you are force pushing to a protected branch... " ,
protected_branch_push_checks : " Checking if you are allowed to push to the protected branch... " ,
2019-07-07 11:18:12 +05:30
protected_branch_creation_checks : " Checking if you are allowed to create a protected branch... " ,
2019-02-15 15:39:39 +05:30
protected_branch_deletion_checks : " Checking if you are allowed to delete the protected branch... "
} . freeze
def validate!
return unless branch_name
logger . log_timed ( LOG_MESSAGES [ :delete_default_branch_check ] ) do
if deletion? && branch_name == project . default_branch
2020-04-08 14:13:33 +05:30
raise GitAccess :: ForbiddenError , ERROR_MESSAGES [ :delete_default_branch ]
2019-02-15 15:39:39 +05:30
end
end
2020-08-18 19:51:02 +05:30
prohibited_branch_checks
2019-02-15 15:39:39 +05:30
protected_branch_checks
end
private
2020-08-18 19:51:02 +05:30
def prohibited_branch_checks
2021-12-07 22:27:20 +05:30
return if deletion?
2020-08-18 19:51:02 +05:30
2023-05-08 21:46:49 +05:30
if branch_name =~ %r{ \ A \ h { 40 } (/| \ z) }
2020-08-18 19:51:02 +05:30
raise GitAccess :: ForbiddenError , ERROR_MESSAGES [ :prohibited_hex_branch_name ]
end
end
2019-02-15 15:39:39 +05:30
def protected_branch_checks
logger . log_timed ( LOG_MESSAGES [ :protected_branch_checks ] ) do
return unless ProtectedBranch . protected? ( project , branch_name ) # rubocop:disable Cop/AvoidReturnFromBlocks
2021-04-17 20:07:23 +05:30
if forced_push? && ! ProtectedBranch . allow_force_push? ( project , branch_name )
2020-04-08 14:13:33 +05:30
raise GitAccess :: ForbiddenError , ERROR_MESSAGES [ :force_push_protected_branch ]
2019-02-15 15:39:39 +05:30
end
end
2019-07-07 11:18:12 +05:30
if project . empty_repo?
protected_branch_push_checks
2019-07-31 22:56:46 +05:30
elsif creation?
2019-07-07 11:18:12 +05:30
protected_branch_creation_checks
elsif deletion?
2019-02-15 15:39:39 +05:30
protected_branch_deletion_checks
else
protected_branch_push_checks
end
end
2019-07-07 11:18:12 +05:30
def protected_branch_creation_checks
logger . log_timed ( LOG_MESSAGES [ :protected_branch_creation_checks ] ) do
break if user_access . can_push_to_branch? ( branch_name )
unless user_access . can_merge_to_branch? ( branch_name )
2020-04-08 14:13:33 +05:30
raise GitAccess :: ForbiddenError , ERROR_MESSAGES [ :create_protected_branch ]
2019-07-07 11:18:12 +05:30
end
unless safe_commit_for_new_protected_branch?
2020-04-08 14:13:33 +05:30
raise GitAccess :: ForbiddenError , ERROR_MESSAGES [ :invalid_commit_create_protected_branch ]
2019-07-07 11:18:12 +05:30
end
unless updated_from_web?
2020-04-08 14:13:33 +05:30
raise GitAccess :: ForbiddenError , ERROR_MESSAGES [ :non_web_create_protected_branch ]
2019-07-07 11:18:12 +05:30
end
end
end
2019-02-15 15:39:39 +05:30
def protected_branch_deletion_checks
logger . log_timed ( LOG_MESSAGES [ :protected_branch_deletion_checks ] ) do
unless user_access . can_delete_branch? ( branch_name )
2020-04-08 14:13:33 +05:30
raise GitAccess :: ForbiddenError , ERROR_MESSAGES [ :non_master_delete_protected_branch ]
2019-02-15 15:39:39 +05:30
end
unless updated_from_web?
2020-04-08 14:13:33 +05:30
raise GitAccess :: ForbiddenError , ERROR_MESSAGES [ :non_web_delete_protected_branch ]
2019-02-15 15:39:39 +05:30
end
end
end
def protected_branch_push_checks
logger . log_timed ( LOG_MESSAGES [ :protected_branch_push_checks ] ) do
if matching_merge_request?
unless user_access . can_merge_to_branch? ( branch_name ) || user_access . can_push_to_branch? ( branch_name )
2020-04-08 14:13:33 +05:30
raise GitAccess :: ForbiddenError , ERROR_MESSAGES [ :merge_protected_branch ]
2019-02-15 15:39:39 +05:30
end
else
unless user_access . can_push_to_branch? ( branch_name )
2020-04-08 14:13:33 +05:30
raise GitAccess :: ForbiddenError , push_to_protected_branch_rejected_message
2019-02-15 15:39:39 +05:30
end
end
end
end
def push_to_protected_branch_rejected_message
if project . empty_repo?
empty_project_push_message
else
ERROR_MESSAGES [ :push_protected_branch ]
end
end
def empty_project_push_message
<< ~ MESSAGE
2021-10-27 15:23:28 +05:30
A default branch ( e . g . main ) does not yet exist for #{project.full_path}
2019-02-15 15:39:39 +05:30
Ask a project Owner or Maintainer to create a default branch :
#{project_members_url}
MESSAGE
end
def project_members_url
Gitlab :: Routing . url_helpers . project_project_members_url ( project )
end
def matching_merge_request?
Checks :: MatchingMergeRequest . new ( newrev , branch_name , project ) . match?
end
def forced_push?
Gitlab :: Checks :: ForcePush . force_push? ( project , oldrev , newrev )
end
2019-07-07 11:18:12 +05:30
def safe_commit_for_new_protected_branch?
ProtectedBranch . any_protected? ( project , project . repository . branch_names_contains_sha ( newrev ) )
end
2019-02-15 15:39:39 +05:30
end
end
end