From 2b427d3361e2cfeedea1c81c9262e68512116625 Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Mon, 1 May 2023 12:15:33 +0000 Subject: Add latest changes from gitlab-org/security/gitlab@15-9-stable-ee --- lib/gitlab/git/repository.rb | 26 ++++++++++++- spec/lib/gitlab/git/repository_spec.rb | 70 +++++++++++++++++++++++++++++++++- 2 files changed, 94 insertions(+), 2 deletions(-) diff --git a/lib/gitlab/git/repository.rb b/lib/gitlab/git/repository.rb index e054b6df98f..e1399b6642b 100644 --- a/lib/gitlab/git/repository.rb +++ b/lib/gitlab/git/repository.rb @@ -262,7 +262,11 @@ module Gitlab def archive_metadata(ref, storage_path, project_path, format = "tar.gz", append_sha:, path: nil) ref ||= root_ref - commit = Gitlab::Git::Commit.find(self, ref) + + commit_id = extract_commit_id_from_ref(ref) + return {} if commit_id.nil? + + commit = Gitlab::Git::Commit.find(self, commit_id) return {} if commit.nil? prefix = archive_prefix(ref, commit.id, project_path, append_sha: append_sha, path: path) @@ -1233,6 +1237,26 @@ module Gitlab def gitaly_delete_refs(*ref_names) gitaly_ref_client.delete_refs(refs: ref_names) if ref_names.any? end + + # The order is based on git priority to resolve ambiguous references + # + # `git show ` + # + # In case of name clashes, it uses this order: + # 1. Commit + # 2. Tag + # 3. Branch + def extract_commit_id_from_ref(ref) + return ref if Gitlab::Git.commit_id?(ref) + + tag = find_tag(ref) + return tag.dereferenced_target.sha if tag + + branch = find_branch(ref) + return branch.dereferenced_target.sha if branch + + ref + end end end end diff --git a/spec/lib/gitlab/git/repository_spec.rb b/spec/lib/gitlab/git/repository_spec.rb index 72043ba2a21..a8423703716 100644 --- a/spec/lib/gitlab/git/repository_spec.rb +++ b/spec/lib/gitlab/git/repository_spec.rb @@ -116,7 +116,8 @@ RSpec.describe Gitlab::Git::Repository, feature_category: :source_code_managemen let(:expected_extension) { 'tar.gz' } let(:expected_filename) { "#{expected_prefix}.#{expected_extension}" } let(:expected_path) { File.join(storage_path, cache_key, "@v2", expected_filename) } - let(:expected_prefix) { "gitlab-git-test-#{ref}-#{TestEnv::BRANCH_SHA['master']}" } + let(:expected_prefix) { "gitlab-git-test-#{ref.tr('/', '-')}-#{expected_prefix_sha}" } + let(:expected_prefix_sha) { TestEnv::BRANCH_SHA['master'] } subject(:metadata) { repository.archive_metadata(ref, storage_path, 'gitlab-git-test', format, append_sha: append_sha, path: path) } @@ -173,6 +174,73 @@ RSpec.describe Gitlab::Git::Repository, feature_category: :source_code_managemen it { expect(metadata['ArchivePath']).to eq(expected_path) } end end + + context 'when references are ambiguous' do + let_it_be(:ambiguous_project) { create(:project, :repository) } + let_it_be(:repository) { ambiguous_project.repository.raw } + let_it_be(:branch_merged_commit_id) { ambiguous_project.repository.find_branch('branch-merged').dereferenced_target.id } + let_it_be(:branch_master_commit_id) { ambiguous_project.repository.find_branch('master').dereferenced_target.id } + let_it_be(:tag_1_0_0_commit_id) { ambiguous_project.repository.find_tag('v1.0.0').dereferenced_target.id } + + context 'when tag is ambiguous' do + before do + ambiguous_project.repository.add_tag(user, ref, 'master', 'foo') + end + + after do + ambiguous_project.repository.rm_tag(user, ref) + end + + where(:ref, :expected_commit_id, :desc) do + 'refs/heads/branch-merged' | ref(:branch_master_commit_id) | 'when tag looks like a branch' + 'branch-merged' | ref(:branch_master_commit_id) | 'when tag has the same name as a branch' + ref(:branch_merged_commit_id) | ref(:branch_merged_commit_id) | 'when tag looks like a commit id' + 'v0.0.0' | ref(:branch_master_commit_id) | 'when tag looks like a normal tag' + end + + with_them do + it 'selects the correct commit' do + expect(metadata['CommitId']).to eq(expected_commit_id) + end + end + end + + context 'when branch is ambiguous' do + before do + ambiguous_project.repository.add_branch(user, ref, 'master') + end + + where(:ref, :expected_commit_id, :desc) do + 'refs/tags/v1.0.0' | ref(:branch_master_commit_id) | 'when branch looks like a tag' + 'v1.0.0' | ref(:tag_1_0_0_commit_id) | 'when branch has the same name as a tag' + ref(:branch_merged_commit_id) | ref(:branch_merged_commit_id) | 'when branch looks like a commit id' + 'just-a-normal-branch' | ref(:branch_master_commit_id) | 'when branch looks like a normal branch' + end + + with_them do + it 'selects the correct commit' do + expect(metadata['CommitId']).to eq(expected_commit_id) + end + end + end + + context 'when ref is HEAD' do + let(:ref) { 'HEAD' } + + it 'selects commit id from HEAD ref' do + expect(metadata['CommitId']).to eq(branch_master_commit_id) + expect(metadata['ArchivePrefix']).to eq(expected_prefix) + end + end + + context 'when ref is not found' do + let(:ref) { 'unknown-ref-cannot-be-found' } + + it 'returns empty metadata' do + expect(metadata).to eq({}) + end + end + end end describe '#size' do -- cgit v1.2.1