From 1e0697db8b97129ee6e88e9806f9b0a0d49dc4fa Mon Sep 17 00:00:00 2001 From: Joe Woodward <jwoodward@gitlab.com> Date: Sat, 2 Dec 2023 10:15:49 +0000 Subject: [PATCH] Refactor TagCheck logic This cleans refactors the logic in TagCheck to improve readability and code structure. --- .../layout/line_continuation_spacing.yml | 1 - ...e_end_string_concatenation_indentation.yml | 1 - .rubocop_todo/style/if_unless_modifier.yml | 1 - .../style/inline_disable_annotation.yml | 1 - lib/gitlab/checks/tag_check.rb | 108 ++++++++++-------- 5 files changed, 62 insertions(+), 50 deletions(-) diff --git a/.rubocop_todo/layout/line_continuation_spacing.yml b/.rubocop_todo/layout/line_continuation_spacing.yml index c406fd1cae9fa..46e997246ea06 100644 --- a/.rubocop_todo/layout/line_continuation_spacing.yml +++ b/.rubocop_todo/layout/line_continuation_spacing.yml @@ -107,7 +107,6 @@ Layout/LineContinuationSpacing: - 'lib/api/metrics/dashboard/annotations.rb' - 'lib/gitlab/auth/user_access_denied_reason.rb' - 'lib/gitlab/background_migration/populate_operation_visibility_permissions_from_operations.rb' - - 'lib/gitlab/checks/tag_check.rb' - 'lib/gitlab/ci/parsers/security/validators/schema_validator.rb' - 'lib/gitlab/database/background_migration/batched_migration_runner.rb' - 'lib/gitlab/database/load_balancing/sidekiq_server_middleware.rb' diff --git a/.rubocop_todo/layout/line_end_string_concatenation_indentation.yml b/.rubocop_todo/layout/line_end_string_concatenation_indentation.yml index e38219963fdfa..68d0f57006e21 100644 --- a/.rubocop_todo/layout/line_end_string_concatenation_indentation.yml +++ b/.rubocop_todo/layout/line_end_string_concatenation_indentation.yml @@ -155,7 +155,6 @@ Layout/LineEndStringConcatenationIndentation: - 'lib/gitlab/auth.rb' - 'lib/gitlab/background_migration/populate_operation_visibility_permissions_from_operations.rb' - 'lib/gitlab/changelog/config.rb' - - 'lib/gitlab/checks/tag_check.rb' - 'lib/gitlab/ci/parsers/security/validators/schema_validator.rb' - 'lib/gitlab/ci/pipeline/chain/populate.rb' - 'lib/gitlab/ci/pipeline/seed/build.rb' diff --git a/.rubocop_todo/style/if_unless_modifier.yml b/.rubocop_todo/style/if_unless_modifier.yml index bf767c1701e88..6c52c2d9f8e7e 100644 --- a/.rubocop_todo/style/if_unless_modifier.yml +++ b/.rubocop_todo/style/if_unless_modifier.yml @@ -730,7 +730,6 @@ Style/IfUnlessModifier: - 'lib/gitlab/checks/matching_merge_request.rb' - 'lib/gitlab/checks/push_check.rb' - 'lib/gitlab/checks/push_file_count_check.rb' - - 'lib/gitlab/checks/tag_check.rb' - 'lib/gitlab/ci/ansi2html.rb' - 'lib/gitlab/ci/ansi2json/converter.rb' - 'lib/gitlab/ci/ansi2json/style.rb' diff --git a/.rubocop_todo/style/inline_disable_annotation.yml b/.rubocop_todo/style/inline_disable_annotation.yml index f5a4378575608..d86a6772ee2f9 100644 --- a/.rubocop_todo/style/inline_disable_annotation.yml +++ b/.rubocop_todo/style/inline_disable_annotation.yml @@ -2411,7 +2411,6 @@ Style/InlineDisableAnnotation: - 'lib/gitlab/checks/branch_check.rb' - 'lib/gitlab/checks/diff_check.rb' - 'lib/gitlab/checks/matching_merge_request.rb' - - 'lib/gitlab/checks/tag_check.rb' - 'lib/gitlab/ci/ansi2html.rb' - 'lib/gitlab/ci/ansi2json/parser.rb' - 'lib/gitlab/ci/badge/pipeline/status.rb' diff --git a/lib/gitlab/checks/tag_check.rb b/lib/gitlab/checks/tag_check.rb index d5addab74b8fc..5684b89725666 100644 --- a/lib/gitlab/checks/tag_check.rb +++ b/lib/gitlab/checks/tag_check.rb @@ -6,8 +6,8 @@ class TagCheck < BaseSingleChecker ERROR_MESSAGES = { change_existing_tags: 'You are not allowed to change existing tags on this project.', update_protected_tag: 'Protected tags cannot be updated.', - delete_protected_tag: 'You are not allowed to delete protected tags from this project. '\ - 'Only a project maintainer or owner can delete a protected tag.', + delete_protected_tag: 'You are not allowed to delete protected tags from this project. ' \ + 'Only a project maintainer or owner can delete a protected tag.', delete_protected_tag_non_web: 'You can only delete protected tags using the web interface.', create_protected_tag: 'You are not allowed to create this tag as it is protected.', default_branch_collision: 'You cannot use default branch name to create a tag', @@ -24,69 +24,85 @@ class TagCheck < BaseSingleChecker def validate! return unless tag_name - logger.log_timed(LOG_MESSAGES[:tag_checks]) do - if tag_exists? && user_access.cannot_do_action?(:admin_tag) - raise GitAccess::ForbiddenError, ERROR_MESSAGES[:change_existing_tags] - end - end - - default_branch_collision_check + logger.log_timed(LOG_MESSAGES[:tag_checks]) { tag_checks } + logger.log_timed(LOG_MESSAGES[:default_branch_collision_check]) { default_branch_collision_check } prohibited_tag_checks - protected_tag_checks + logger.log_timed(LOG_MESSAGES[:protected_tag_checks]) { protected_tag_checks } end private + def tag_checks + return unless tag_exists? && user_access.cannot_do_action?(:admin_tag) + + raise GitAccess::ForbiddenError, ERROR_MESSAGES[:change_existing_tags] + end + + def default_branch_collision_check + return unless creation? && tag_name == project.default_branch + + raise GitAccess::ForbiddenError, ERROR_MESSAGES[:default_branch_collision] + end + def prohibited_tag_checks return if deletion? - unless Gitlab::GitRefValidator.validate(tag_name) - raise GitAccess::ForbiddenError, ERROR_MESSAGES[:prohibited_tag_name] - end + # Incorrectly encoded tags names may raise during other checks so we + # need to validate the encoding first + validate_encoding! + validate_valid_tag_name! + validate_tag_name_not_fully_qualified! + end - if tag_name.start_with?("refs/tags/") # rubocop: disable Style/GuardClause - raise GitAccess::ForbiddenError, ERROR_MESSAGES[:prohibited_tag_name] - end + def protected_tag_checks + return unless ProtectedTag.protected?(project, tag_name) - # rubocop: disable Style/GuardClause - # rubocop: disable Style/SoleNestedConditional - if Feature.enabled?(:prohibited_tag_name_encoding_check, project) - unless Gitlab::EncodingHelper.force_encode_utf8(tag_name).valid_encoding? - raise GitAccess::ForbiddenError, ERROR_MESSAGES[:prohibited_tag_name_encoding] - end - end - # rubocop: enable Style/SoleNestedConditional - # rubocop: enable Style/GuardClause + validate_protected_tag_update! + validate_protected_tag_deletion! + validate_protected_tag_creation! end - def protected_tag_checks - logger.log_timed(LOG_MESSAGES[__method__]) do - return unless ProtectedTag.protected?(project, tag_name) # rubocop:disable Cop/AvoidReturnFromBlocks + def validate_encoding! + return unless Feature.enabled?(:prohibited_tag_name_encoding_check, project) + return if Gitlab::EncodingHelper.force_encode_utf8(tag_name).valid_encoding? - raise(GitAccess::ForbiddenError, ERROR_MESSAGES[:update_protected_tag]) if update? + raise GitAccess::ForbiddenError, ERROR_MESSAGES[:prohibited_tag_name_encoding] + end + + def validate_valid_tag_name! + return if Gitlab::GitRefValidator.validate(tag_name) - if deletion? - unless user_access.user.can?(:maintainer_access, project) - raise(GitAccess::ForbiddenError, ERROR_MESSAGES[:delete_protected_tag]) - end + raise GitAccess::ForbiddenError, ERROR_MESSAGES[:prohibited_tag_name] + end - unless updated_from_web? - raise GitAccess::ForbiddenError, ERROR_MESSAGES[:delete_protected_tag_non_web] - end - end + def validate_tag_name_not_fully_qualified! + return unless tag_name.start_with?("refs/tags/") - unless user_access.can_create_tag?(tag_name) - raise GitAccess::ForbiddenError, ERROR_MESSAGES[:create_protected_tag] - end - end + raise GitAccess::ForbiddenError, ERROR_MESSAGES[:prohibited_tag_name] end - def default_branch_collision_check - logger.log_timed(LOG_MESSAGES[:default_branch_collision_check]) do - if creation? && tag_name == project.default_branch - raise GitAccess::ForbiddenError, ERROR_MESSAGES[:default_branch_collision] - end + def validate_protected_tag_update! + return unless update? + + raise(GitAccess::ForbiddenError, ERROR_MESSAGES[:update_protected_tag]) + end + + def validate_protected_tag_deletion! + return unless deletion? + + unless user_access.user.can?(:maintainer_access, project) + raise(GitAccess::ForbiddenError, ERROR_MESSAGES[:delete_protected_tag]) end + + return if updated_from_web? + + raise GitAccess::ForbiddenError, ERROR_MESSAGES[:delete_protected_tag_non_web] + end + + def validate_protected_tag_creation! + return if user_access.can_create_tag?(tag_name) + + raise GitAccess::ForbiddenError, ERROR_MESSAGES[:create_protected_tag] end end end -- GitLab