diff options
Diffstat (limited to 'spec/lib/gitlab')
5 files changed, 259 insertions, 2 deletions
diff --git a/spec/lib/gitlab/background_migration/mailers/unconfirm_mailer_spec.rb b/spec/lib/gitlab/background_migration/mailers/unconfirm_mailer_spec.rb index f430009989b..05bd020d4e2 100644 --- a/spec/lib/gitlab/background_migration/mailers/unconfirm_mailer_spec.rb +++ b/spec/lib/gitlab/background_migration/mailers/unconfirm_mailer_spec.rb @@ -7,6 +7,6 @@ RSpec.describe Gitlab::BackgroundMigration::Mailers::UnconfirmMailer do let(:subject) { described_class.unconfirm_notification_email(user) } it 'contains abuse report url' do - expect(subject.body.encoded).to include(Rails.application.routes.url_helpers.new_abuse_report_url(user_id: user.id)) + expect(subject.body.encoded).to include(Gitlab::Routing.url_helpers.user_url(user.id)) end end diff --git a/spec/lib/gitlab/checks/tag_check_spec.rb b/spec/lib/gitlab/checks/tag_check_spec.rb index 50ffa5fad10..e75b0459337 100644 --- a/spec/lib/gitlab/checks/tag_check_spec.rb +++ b/spec/lib/gitlab/checks/tag_check_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Gitlab::Checks::TagCheck do +RSpec.describe Gitlab::Checks::TagCheck, feature_category: :source_code_management do include_context 'change access checks context' describe '#validate!' do @@ -14,6 +14,29 @@ RSpec.describe Gitlab::Checks::TagCheck do expect { subject.validate! }.to raise_error(Gitlab::GitAccess::ForbiddenError, 'You are not allowed to change existing tags on this project.') end + context "prohibited tags check" do + it "prohibits tag names that include refs/tags/ at the head" do + allow(subject).to receive(:tag_name).and_return("refs/tags/foo") + + expect { subject.validate! }.to raise_error(Gitlab::GitAccess::ForbiddenError, "You cannot create a tag with a prohibited pattern.") + end + + it "doesn't prohibit a nested refs/tags/ string in a tag name" do + allow(subject).to receive(:tag_name).and_return("fix-for-refs/tags/foo") + + expect { subject.validate! }.not_to raise_error + end + + context "deleting a refs/tags headed tag" do + let(:newrev) { "0000000000000000000000000000000000000000" } + let(:ref) { "refs/tags/refs/tags/267208abfe40e546f5e847444276f7d43a39503e" } + + it "doesn't prohibit the deletion of a refs/tags/ tag name" do + expect { subject.validate! }.not_to raise_error + end + end + end + context 'with protected tag' do let!(:protected_tag) { create(:protected_tag, project: project, name: 'v*') } diff --git a/spec/lib/gitlab/ci/artifacts/decompressed_artifact_size_validator_spec.rb b/spec/lib/gitlab/ci/artifacts/decompressed_artifact_size_validator_spec.rb new file mode 100644 index 00000000000..ef39a431d63 --- /dev/null +++ b/spec/lib/gitlab/ci/artifacts/decompressed_artifact_size_validator_spec.rb @@ -0,0 +1,95 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Gitlab::Ci::Artifacts::DecompressedArtifactSizeValidator, feature_category: :build_artifacts do + include WorkhorseHelpers + + let_it_be(:file_path) { File.join(Dir.tmpdir, 'decompressed_archive_size_validator_spec.gz') } + let(:file) { File.open(file_path) } + let(:file_format) { :gzip } + let(:max_bytes) { 20 } + let(:gzip_valid?) { true } + let(:validator) { instance_double(::Gitlab::Ci::DecompressedGzipSizeValidator, valid?: gzip_valid?) } + + before(:all) do + Zlib::GzipWriter.open(file_path) do |gz| + gz.write('Hello World!') + end + end + + after(:all) do + FileUtils.rm(file_path) + end + + before do + allow(::Gitlab::Ci::DecompressedGzipSizeValidator) + .to receive(:new) + .and_return(validator) + end + + subject { described_class.new(file: file, file_format: file_format, max_bytes: max_bytes) } + + shared_examples 'when file does not exceed allowed compressed size' do + let(:gzip_valid?) { true } + + it 'passes validation' do + expect { subject.validate! }.not_to raise_error + end + end + + shared_examples 'when file exceeds allowed decompressed size' do + let(:gzip_valid?) { false } + + it 'raises an exception' do + expect { subject.validate! } + .to raise_error(Gitlab::Ci::Artifacts::DecompressedArtifactSizeValidator::FileDecompressionError) + end + end + + describe '#validate!' do + it_behaves_like 'when file does not exceed allowed compressed size' + + it_behaves_like 'when file exceeds allowed decompressed size' + end + + context 'when file is not provided' do + let(:file) { nil } + + it 'passes validation' do + expect { subject.validate! }.not_to raise_error + end + end + + context 'when the file is located in the cloud' do + let(:remote_path) { File.join(remote_store_path, remote_id) } + + let(:file_url) { "http://s3.amazonaws.com/#{remote_path}" } + let(:file) do + instance_double(JobArtifactUploader, + path: file_path, + url: file_url, + object_store: ObjectStorage::Store::REMOTE) + end + + let(:remote_id) { 'generated-remote-id-12345' } + let(:remote_store_path) { ObjectStorage::TMP_UPLOAD_PATH } + + before do + stub_request(:get, %r{s3.amazonaws.com/#{remote_path}}) + .to_return(status: 200, body: File.read('spec/fixtures/build.env.gz')) + end + + it_behaves_like 'when file does not exceed allowed compressed size' + + it_behaves_like 'when file exceeds allowed decompressed size' + end + + context 'when file_format is not on the list' do + let_it_be(:file_format) { 'rar' } + + it 'passes validation' do + expect { subject.validate! }.not_to raise_error + end + end +end diff --git a/spec/lib/gitlab/ci/decompressed_gzip_size_validator_spec.rb b/spec/lib/gitlab/ci/decompressed_gzip_size_validator_spec.rb new file mode 100644 index 00000000000..6ca3f4d415e --- /dev/null +++ b/spec/lib/gitlab/ci/decompressed_gzip_size_validator_spec.rb @@ -0,0 +1,127 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Gitlab::Ci::DecompressedGzipSizeValidator, feature_category: :importers do + let_it_be(:filepath) { File.join(Dir.tmpdir, 'decompressed_gzip_size_validator_spec.gz') } + + before(:all) do + create_compressed_file + end + + after(:all) do + FileUtils.rm(filepath) + end + + subject { described_class.new(archive_path: filepath, max_bytes: max_bytes) } + + describe '#valid?' do + let(:max_bytes) { 20 } + + context 'when file does not exceed allowed decompressed size' do + it 'returns true' do + expect(subject.valid?).to eq(true) + end + + context 'when the waiter thread no longer exists due to being terminated or crashing' do + it 'gracefully handles the absence of the waiter without raising exception' do + allow(Process).to receive(:getpgid).and_raise(Errno::ESRCH) + + expect(subject.valid?).to eq(true) + end + end + end + + context 'when file exceeds allowed decompressed size' do + let(:max_bytes) { 1 } + + it 'returns false' do + expect(subject.valid?).to eq(false) + end + end + + context 'when exception occurs during header readings' do + shared_examples 'raises exception and terminates validator process group' do + let(:std) { instance_double(IO, close: nil) } + let(:wait_thr) { double } + let(:wait_threads) { [wait_thr, wait_thr] } + + before do + allow(Process).to receive(:getpgid).and_return(2) + allow(Open3).to receive(:pipeline_r).and_return([std, wait_threads]) + allow(wait_thr).to receive(:[]).with(:pid).and_return(1) + allow(wait_thr).to receive(:value).and_raise(exception) + end + + it 'terminates validator process group' do + expect(Process).to receive(:kill).with(-1, 2).twice + expect(subject.valid?).to eq(false) + end + end + + context 'when timeout occurs' do + let(:exception) { Timeout::Error } + + include_examples 'raises exception and terminates validator process group' + end + + context 'when exception occurs' do + let(:error_message) { 'Error!' } + let(:exception) { StandardError.new(error_message) } + + include_examples 'raises exception and terminates validator process group' + end + end + + describe 'archive path validation' do + let(:filesize) { nil } + + context 'when archive path is traversed' do + let(:filepath) { '/foo/../bar' } + + it 'does not pass validation' do + expect(subject.valid?).to eq(false) + end + end + end + + context 'when archive path is not a string' do + let(:filepath) { 123 } + + it 'returns false' do + expect(subject.valid?).to eq(false) + end + end + + context 'when archive path is a symlink' do + let(:filepath) { File.join(Dir.tmpdir, 'symlink') } + + before do + FileUtils.ln_s(filepath, filepath, force: true) + end + + it 'returns false' do + expect(subject.valid?).to eq(false) + end + end + + context 'when archive path is not a file' do + let(:filepath) { Dir.mktmpdir } + let(:filesize) { File.size(filepath) } + + after do + FileUtils.rm_rf(filepath) + end + + it 'returns false' do + expect(subject.valid?).to eq(false) + end + end + end + + def create_compressed_file + Zlib::GzipWriter.open(filepath) do |gz| + gz.write('Hello World!') + end + end +end diff --git a/spec/lib/gitlab/import_export/project/tree_saver_spec.rb b/spec/lib/gitlab/import_export/project/tree_saver_spec.rb index 4166eba4e8e..d8b8903c8ca 100644 --- a/spec/lib/gitlab/import_export/project/tree_saver_spec.rb +++ b/spec/lib/gitlab/import_export/project/tree_saver_spec.rb @@ -7,6 +7,8 @@ RSpec.describe Gitlab::ImportExport::Project::TreeSaver, :with_license, feature_ let_it_be(:exportable_path) { 'project' } let_it_be(:user) { create(:user) } let_it_be(:group) { create(:group) } + let_it_be(:private_project) { create(:project, :private, group: group) } + let_it_be(:private_mr) { create(:merge_request, source_project: private_project, project: private_project) } let_it_be(:project) { setup_project } shared_examples 'saves project tree successfully' do @@ -118,6 +120,13 @@ RSpec.describe Gitlab::ImportExport::Project::TreeSaver, :with_license, feature_ expect(reviewer).not_to be_nil expect(reviewer['user_id']).to eq(user.id) end + + it 'has merge requests system notes' do + system_notes = subject.first['notes'].select { |note| note['system'] } + + expect(system_notes.size).to eq(1) + expect(system_notes.first['note']).to eq('merged') + end end context 'with snippets' do @@ -492,6 +501,9 @@ RSpec.describe Gitlab::ImportExport::Project::TreeSaver, :with_license, feature_ create(:milestone, project: project) discussion_note = create(:discussion_note, noteable: issue, project: project) mr_note = create(:note, noteable: merge_request, project: project) + create(:system_note, noteable: merge_request, project: project, author: user, note: 'merged') + private_system_note = "mentioned in merge request #{private_mr.to_reference(project)}" + create(:system_note, noteable: merge_request, project: project, author: user, note: private_system_note) create(:note, noteable: snippet, project: project) create(:note_on_commit, author: user, |