diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2023-08-18 13:50:51 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2023-08-18 13:50:51 +0300 |
commit | db384e6b19af03b4c3c82a5760d83a3fd79f7982 (patch) | |
tree | 34beaef37df5f47ccbcf5729d7583aae093cffa0 /lib/gitlab/checks | |
parent | 54fd7b1bad233e3944434da91d257fa7f63c3996 (diff) |
Add latest changes from gitlab-org/gitlab@16-3-stable-eev16.3.0-rc42
Diffstat (limited to 'lib/gitlab/checks')
5 files changed, 103 insertions, 49 deletions
diff --git a/lib/gitlab/checks/branch_check.rb b/lib/gitlab/checks/branch_check.rb index aa89c2711f9..b675eca826a 100644 --- a/lib/gitlab/checks/branch_check.rb +++ b/lib/gitlab/checks/branch_check.rb @@ -43,7 +43,7 @@ module Gitlab def prohibited_branch_checks return if deletion? - if branch_name =~ %r{\A\h{40}(-/|/|\z)} + if %r{\A#{Gitlab::Git::Commit::RAW_FULL_SHA_PATTERN}(-/|/|\z)}o.match?(branch_name) raise GitAccess::ForbiddenError, ERROR_MESSAGES[:prohibited_hex_branch_name] end diff --git a/lib/gitlab/checks/diff_check.rb b/lib/gitlab/checks/diff_check.rb index bce4f969284..15b38188f13 100644 --- a/lib/gitlab/checks/diff_check.rb +++ b/lib/gitlab/checks/diff_check.rb @@ -18,10 +18,7 @@ module Gitlab return unless should_run_validations? return if commits.empty? - paths = project.repository.find_changed_paths( - commits.map(&:sha), merge_commit_diff_mode: :all_parents - ) - + paths = project.repository.find_changed_paths(treeish_objects, merge_commit_diff_mode: :all_parents) paths.each do |path| validate_path(path) end @@ -31,6 +28,29 @@ module Gitlab private + def treeish_objects + objects = commits + + return objects unless project.repository.empty? && + Feature.enabled?(:verify_push_rules_for_first_commit, project) + + # It's a special case for the push to the empty repository + # + # Git doesn't display a diff of the initial commit of the repository + # if we just provide a commit sha. + # + # To fix that we can use TreeRequest to check the difference + # between empty tree sha and the tree sha of the initial commit + # + # `commits` are sorted in reverse order, the initial commit is the last one. + init_commit = objects.last + + diff_tree = Gitlab::Git::DiffTree.from_commit(init_commit) + return [diff_tree] + objects if diff_tree + + objects + end + def validate_lfs_file_locks? strong_memoize(:validate_lfs_file_locks) do project.lfs_enabled? && project.any_lfs_file_locks? diff --git a/lib/gitlab/checks/file_size_check/allow_existing_oversized_blobs.rb b/lib/gitlab/checks/file_size_check/allow_existing_oversized_blobs.rb deleted file mode 100644 index 78f1716274e..00000000000 --- a/lib/gitlab/checks/file_size_check/allow_existing_oversized_blobs.rb +++ /dev/null @@ -1,38 +0,0 @@ -# frozen_string_literal: true - -module Gitlab - module Checks - module FileSizeCheck - class AllowExistingOversizedBlobs - def initialize(project:, changes:, file_size_limit_megabytes:) - @project = project - @changes = changes - @oldrevs = changes.pluck(:oldrev).compact # rubocop:disable CodeReuse/ActiveRecord just plucking from an array - @file_size_limit_megabytes = file_size_limit_megabytes - end - - def find(timeout: nil) - oversize_blobs = any_oversize_blobs.find(timeout: timeout) - - return oversize_blobs unless oldrevs.present? - - revs_paths = oldrevs.product(oversize_blobs.map(&:path)) - existing_blobs = project.repository.blobs_at(revs_paths, blob_size_limit: 1) - map_existing_path_to_size = existing_blobs.group_by(&:path).transform_values { |blobs| blobs.map(&:size).max } - - # return blobs that are going to be over the limit that were previously within the limit - oversize_blobs.select { |blob| map_existing_path_to_size.fetch(blob.path, 0) <= file_size_limit_megabytes } - end - - private - - attr_reader :project, :changes, :newrevs, :oldrevs, :file_size_limit_megabytes - - def any_oversize_blobs - AnyOversizedBlobs.new(project: project, changes: changes, - file_size_limit_megabytes: file_size_limit_megabytes) - end - end - end - end -end diff --git a/lib/gitlab/checks/file_size_check/hook_environment_aware_any_oversized_blobs.rb b/lib/gitlab/checks/file_size_check/hook_environment_aware_any_oversized_blobs.rb new file mode 100644 index 00000000000..952def83658 --- /dev/null +++ b/lib/gitlab/checks/file_size_check/hook_environment_aware_any_oversized_blobs.rb @@ -0,0 +1,54 @@ +# frozen_string_literal: true + +module Gitlab + module Checks + module FileSizeCheck + class HookEnvironmentAwareAnyOversizedBlobs + def initialize(project:, changes:, file_size_limit_megabytes:) + @project = project + @repository = project.repository + @changes = changes + @file_size_limit_megabytes = file_size_limit_megabytes + end + + def find(timeout: nil) + if ignore_alternate_directories? + blobs = repository.list_all_blobs(bytes_limit: 0, dynamic_timeout: timeout, + ignore_alternate_object_directories: true).to_a + + blobs.select! do |blob| + ::Gitlab::Utils.bytes_to_megabytes(blob.size) > file_size_limit_megabytes + end + filter_existing(blobs) + else + any_oversize_blobs.find(timeout: timeout) + end + end + + private + + attr_reader :project, :repository, :changes, :file_size_limit_megabytes + + def filter_existing(blobs) + gitaly_repo = repository.gitaly_repository.dup.tap { |repo| repo.git_object_directory = "" } + + map_blob_id_to_existence = repository.gitaly_commit_client.object_existence_map(blobs.map(&:id), + gitaly_repo: gitaly_repo) + + blobs.reject { |blob| map_blob_id_to_existence[blob.id].present? } + end + + def ignore_alternate_directories? + git_env = ::Gitlab::Git::HookEnv.all(repository.gl_repository) + + git_env['GIT_OBJECT_DIRECTORY_RELATIVE'].present? + end + + def any_oversize_blobs + AnyOversizedBlobs.new(project: project, changes: changes, + file_size_limit_megabytes: file_size_limit_megabytes) + end + end + end + end +end diff --git a/lib/gitlab/checks/global_file_size_check.rb b/lib/gitlab/checks/global_file_size_check.rb index 418d2d32b57..62facf52239 100644 --- a/lib/gitlab/checks/global_file_size_check.rb +++ b/lib/gitlab/checks/global_file_size_check.rb @@ -3,7 +3,6 @@ module Gitlab module Checks class GlobalFileSizeCheck < BaseBulkChecker - MAX_FILE_SIZE_MB = 100 LOG_MESSAGE = 'Checking for blobs over the file size limit' def validate! @@ -11,19 +10,38 @@ module Gitlab Gitlab::AppJsonLogger.info(LOG_MESSAGE) logger.log_timed(LOG_MESSAGE) do - Gitlab::Checks::FileSizeCheck::AllowExistingOversizedBlobs.new( + oversized_blobs = Gitlab::Checks::FileSizeCheck::HookEnvironmentAwareAnyOversizedBlobs.new( project: project, changes: changes, - file_size_limit_megabytes: MAX_FILE_SIZE_MB + file_size_limit_megabytes: file_size_limit ).find - # TODO: https://gitlab.com/gitlab-org/gitlab/-/issues/393535 - # - set limit per plan tier - # - raise an error if large blobs are found + if oversized_blobs.present? + Gitlab::AppJsonLogger.info( + message: 'Found blob over global limit', + blob_sizes: oversized_blobs.map(&:size) + ) + + if enforce_global_file_size_limit? + raise ::Gitlab::GitAccess::ForbiddenError, + "Changes include a file that is larger than the allowed size of #{file_size_limit} MiB. " \ + "Use Git LFS to manage this file.)" + end + end end true end + + private + + def file_size_limit + project.actual_limits.file_size_limit_mb + end + + def enforce_global_file_size_limit? + Feature.enabled?(:enforce_global_file_size_limit, project) + end end end end |