diff options
Diffstat (limited to 'spec/lib/gitlab')
-rw-r--r-- | spec/lib/gitlab/auth/request_authenticator_spec.rb | 43 | ||||
-rw-r--r-- | spec/lib/gitlab/ci/pipeline/chain/helpers_spec.rb | 25 | ||||
-rw-r--r-- | spec/lib/gitlab/conan_token_spec.rb | 14 | ||||
-rw-r--r-- | spec/lib/gitlab/git_access_wiki_spec.rb | 138 | ||||
-rw-r--r-- | spec/lib/gitlab/import_export/project/relation_factory_spec.rb | 18 | ||||
-rw-r--r-- | spec/lib/gitlab/import_export/project/tree_restorer_spec.rb | 4 | ||||
-rw-r--r-- | spec/lib/gitlab/metrics/subscribers/rack_attack_spec.rb | 152 | ||||
-rw-r--r-- | spec/lib/gitlab/regex_spec.rb | 15 |
8 files changed, 301 insertions, 108 deletions
diff --git a/spec/lib/gitlab/auth/request_authenticator_spec.rb b/spec/lib/gitlab/auth/request_authenticator_spec.rb index 5e9d07a8bf7..fa20fd22886 100644 --- a/spec/lib/gitlab/auth/request_authenticator_spec.rb +++ b/spec/lib/gitlab/auth/request_authenticator_spec.rb @@ -44,6 +44,38 @@ RSpec.describe Gitlab::Auth::RequestAuthenticator do end end + describe '#find_authenticated_requester' do + let_it_be(:api_user) { create(:user) } + let_it_be(:deploy_token_user) { create(:user) } + + it 'returns the deploy token if it exists' do + allow_next_instance_of(described_class) do |authenticator| + expect(authenticator).to receive(:deploy_token_from_request).and_return(deploy_token_user) + allow(authenticator).to receive(:user).and_return(nil) + end + + expect(subject.find_authenticated_requester([:api])).to eq deploy_token_user + end + + it 'returns the user id if it exists' do + allow_next_instance_of(described_class) do |authenticator| + allow(authenticator).to receive(:deploy_token_from_request).and_return(deploy_token_user) + expect(authenticator).to receive(:user).and_return(api_user) + end + + expect(subject.find_authenticated_requester([:api])).to eq api_user + end + + it 'rerturns nil if no match is found' do + allow_next_instance_of(described_class) do |authenticator| + expect(authenticator).to receive(:deploy_token_from_request).and_return(nil) + expect(authenticator).to receive(:user).and_return(nil) + end + + expect(subject.find_authenticated_requester([:api])).to eq nil + end + end + describe '#find_sessionless_user' do let_it_be(:dependency_proxy_user) { build(:user) } let_it_be(:access_token_user) { build(:user) } @@ -348,10 +380,10 @@ RSpec.describe Gitlab::Auth::RequestAuthenticator do describe '#route_authentication_setting' do using RSpec::Parameterized::TableSyntax - where(:script_name, :expected_job_token_allowed, :expected_basic_auth_personal_access_token) do - '/api/endpoint' | true | true - '/namespace/project.git' | false | true - '/web/endpoint' | false | false + where(:script_name, :expected_job_token_allowed, :expected_basic_auth_personal_access_token, :expected_deploy_token_allowed) do + '/api/endpoint' | true | true | true + '/namespace/project.git' | false | true | true + '/web/endpoint' | false | false | false end with_them do @@ -362,7 +394,8 @@ RSpec.describe Gitlab::Auth::RequestAuthenticator do it 'returns correct settings' do expect(subject.send(:route_authentication_setting)).to eql({ job_token_allowed: expected_job_token_allowed, - basic_auth_personal_access_token: expected_basic_auth_personal_access_token + basic_auth_personal_access_token: expected_basic_auth_personal_access_token, + deploy_token_allowed: expected_deploy_token_allowed }) end end diff --git a/spec/lib/gitlab/ci/pipeline/chain/helpers_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/helpers_spec.rb index bcea6462790..96ada90b4e1 100644 --- a/spec/lib/gitlab/ci/pipeline/chain/helpers_spec.rb +++ b/spec/lib/gitlab/ci/pipeline/chain/helpers_spec.rb @@ -22,6 +22,19 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Helpers do let(:command) { double(save_incompleted: true) } let(:message) { 'message' } + describe '.warning' do + context 'when the warning includes malicious HTML' do + let(:message) { '<div>gimme your password</div>' } + let(:sanitized_message) { 'gimme your password' } + + it 'sanitizes' do + subject.warning(message) + + expect(pipeline.warning_messages[0].content).to include(sanitized_message) + end + end + end + describe '.error' do shared_examples 'error function' do specify do @@ -36,6 +49,18 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Helpers do end end + context 'when the error includes malicious HTML' do + let(:message) { '<div>gimme your password</div>' } + let(:sanitized_message) { 'gimme your password' } + + it 'sanitizes the error and removes the HTML tags' do + subject.error(message, config_error: true, drop_reason: :config_error) + + expect(pipeline.yaml_errors).to eq(sanitized_message) + expect(pipeline.errors[:base]).to include(sanitized_message) + end + end + context 'when given a drop reason' do context 'when config error is true' do context 'sets the yaml error and overrides the drop reason' do diff --git a/spec/lib/gitlab/conan_token_spec.rb b/spec/lib/gitlab/conan_token_spec.rb index b6180f69044..c8bda0a5cf0 100644 --- a/spec/lib/gitlab/conan_token_spec.rb +++ b/spec/lib/gitlab/conan_token_spec.rb @@ -25,13 +25,17 @@ RSpec.describe Gitlab::ConanToken do end describe '.from_personal_access_token' do - it 'sets access token id and user id' do - access_token = double(id: 123, user_id: 456) + it 'sets access token and user id and does not use the token id' do + personal_access_token = double(id: 999, token: 123, user_id: 456) - token = described_class.from_personal_access_token(access_token) + token = described_class.from_personal_access_token( + personal_access_token.user_id, + personal_access_token.token + ) - expect(token.access_token_id).to eq(123) - expect(token.user_id).to eq(456) + expect(token.access_token_id).not_to eq(personal_access_token.id) + expect(token.access_token_id).to eq(personal_access_token.token) + expect(token.user_id).to eq(personal_access_token.user_id) end end diff --git a/spec/lib/gitlab/git_access_wiki_spec.rb b/spec/lib/gitlab/git_access_wiki_spec.rb index 27175dc8c44..de3e674c3a7 100644 --- a/spec/lib/gitlab/git_access_wiki_spec.rb +++ b/spec/lib/gitlab/git_access_wiki_spec.rb @@ -4,8 +4,9 @@ require 'spec_helper' RSpec.describe Gitlab::GitAccessWiki do let_it_be(:user) { create(:user) } - let_it_be(:project) { create(:project, :wiki_repo) } - let_it_be(:wiki) { create(:project_wiki, project: project) } + let_it_be_with_reload(:project) { create(:project, :wiki_repo) } + + let(:wiki) { create(:project_wiki, project: project) } let(:changes) { ['6f6d7e7ed 570e7b2ab refs/heads/master'] } let(:authentication_abilities) { %i[read_project download_code push_code] } @@ -17,6 +18,61 @@ RSpec.describe Gitlab::GitAccessWiki do redirected_path: redirected_path) end + RSpec.shared_examples 'wiki access by level' do + where(:project_visibility, :project_member?, :wiki_access_level, :wiki_repo?, :expected_behavior) do + [ + # Private project - is a project member + [Gitlab::VisibilityLevel::PRIVATE, true, ProjectFeature::ENABLED, true, :no_error], + [Gitlab::VisibilityLevel::PRIVATE, true, ProjectFeature::PRIVATE, true, :no_error], + [Gitlab::VisibilityLevel::PRIVATE, true, ProjectFeature::DISABLED, true, :forbidden_wiki], + [Gitlab::VisibilityLevel::PRIVATE, true, ProjectFeature::ENABLED, false, :not_found_wiki], + [Gitlab::VisibilityLevel::PRIVATE, true, ProjectFeature::DISABLED, false, :not_found_wiki], + [Gitlab::VisibilityLevel::PRIVATE, true, ProjectFeature::PRIVATE, false, :not_found_wiki], + # Private project - is NOT a project member + [Gitlab::VisibilityLevel::PRIVATE, false, ProjectFeature::ENABLED, true, :not_found_wiki], + [Gitlab::VisibilityLevel::PRIVATE, false, ProjectFeature::PRIVATE, true, :not_found_wiki], + [Gitlab::VisibilityLevel::PRIVATE, false, ProjectFeature::DISABLED, true, :not_found_wiki], + [Gitlab::VisibilityLevel::PRIVATE, false, ProjectFeature::ENABLED, false, :not_found_wiki], + [Gitlab::VisibilityLevel::PRIVATE, false, ProjectFeature::DISABLED, false, :not_found_wiki], + [Gitlab::VisibilityLevel::PRIVATE, false, ProjectFeature::PRIVATE, false, :not_found_wiki], + # Public project - is a project member + [Gitlab::VisibilityLevel::PUBLIC, true, ProjectFeature::ENABLED, true, :no_error], + [Gitlab::VisibilityLevel::PUBLIC, true, ProjectFeature::PRIVATE, true, :no_error], + [Gitlab::VisibilityLevel::PUBLIC, true, ProjectFeature::DISABLED, true, :forbidden_wiki], + [Gitlab::VisibilityLevel::PUBLIC, true, ProjectFeature::ENABLED, false, :not_found_wiki], + [Gitlab::VisibilityLevel::PUBLIC, true, ProjectFeature::DISABLED, false, :not_found_wiki], + [Gitlab::VisibilityLevel::PUBLIC, true, ProjectFeature::PRIVATE, false, :not_found_wiki], + # Public project - is NOT a project member + [Gitlab::VisibilityLevel::PUBLIC, false, ProjectFeature::ENABLED, true, :no_error], + [Gitlab::VisibilityLevel::PUBLIC, false, ProjectFeature::PRIVATE, true, :forbidden_wiki], + [Gitlab::VisibilityLevel::PUBLIC, false, ProjectFeature::DISABLED, true, :forbidden_wiki], + [Gitlab::VisibilityLevel::PUBLIC, false, ProjectFeature::ENABLED, false, :not_found_wiki], + [Gitlab::VisibilityLevel::PUBLIC, false, ProjectFeature::DISABLED, false, :not_found_wiki], + [Gitlab::VisibilityLevel::PUBLIC, false, ProjectFeature::PRIVATE, false, :not_found_wiki] + ] + end + + with_them do + before do + project.update!(visibility_level: project_visibility) + project.add_developer(user) if project_member? + project.project_feature.update_attribute(:wiki_access_level, wiki_access_level) + allow(wiki.repository).to receive(:exists?).and_return(wiki_repo?) + end + + it 'provides access by level' do + case expected_behavior + when :no_error + expect { subject }.not_to raise_error + when :forbidden_wiki + expect { subject }.to raise_wiki_forbidden + when :not_found_wiki + expect { subject }.to raise_wiki_not_found + end + end + end + end + describe '#push_access_check' do subject { access.check('git-receive-pack', changes) } @@ -28,56 +84,26 @@ RSpec.describe Gitlab::GitAccessWiki do it { expect { subject }.not_to raise_error } context 'when in a read-only GitLab instance' do - let(:message) { "You can't push code to a read-only GitLab instance." } - before do allow(Gitlab::Database).to receive(:read_only?) { true } end - it_behaves_like 'forbidden git access' + it_behaves_like 'forbidden git access' do + let(:message) { "You can't push code to a read-only GitLab instance." } + end end end context 'the user cannot :create_wiki' do - it_behaves_like 'not-found git access' do - let(:message) { 'The wiki you were looking for could not be found.' } - end + it { expect { subject }.to raise_wiki_not_found } end end describe '#check_download_access!' do subject { access.check('git-upload-pack', Gitlab::GitAccess::ANY) } - context 'the user can :download_wiki_code' do - before do - project.add_developer(user) - end - - context 'when wiki feature is disabled' do - before do - project.project_feature.update_attribute(:wiki_access_level, ProjectFeature::DISABLED) - end - - it_behaves_like 'forbidden git access' do - let(:message) { include('wiki') } - end - end - - context 'when the repository does not exist' do - before do - allow(wiki.repository).to receive(:exists?).and_return(false) - end - - it_behaves_like 'not-found git access' do - let(:message) { include('for this wiki') } - end - end - end - - context 'the user cannot :download_wiki_code' do - it_behaves_like 'not-found git access' do - let(:message) { include('wiki') } - end + context 'when actor is a user' do + it_behaves_like 'wiki access by level' end context 'when the actor is a deploy token' do @@ -99,10 +125,40 @@ RSpec.describe Gitlab::GitAccessWiki do context 'when the wiki is disabled' do let(:wiki_access_level) { ProjectFeature::DISABLED } - it_behaves_like 'forbidden git access' do - let(:message) { 'You are not allowed to download files from this wiki.' } - end + it { expect { subject }.to raise_wiki_forbidden } end end + + describe 'when actor is a user provided by build via CI_JOB_TOKEN' do + let(:protocol) { 'http' } + let(:authentication_abilities) { [:build_download_code] } + let(:auth_result_type) { :build } + + before do + project.project_feature.update_attribute(:wiki_access_level, wiki_access_level) + end + + subject { access.check('git-upload-pack', changes) } + + it_behaves_like 'wiki access by level' + end + end + + RSpec::Matchers.define :raise_wiki_not_found do + match do |actual| + expect { actual.call }.to raise_error(Gitlab::GitAccess::NotFoundError, include('wiki')) + end + def supports_block_expectations? + true + end + end + + RSpec::Matchers.define :raise_wiki_forbidden do + match do |actual| + expect { subject }.to raise_error(Gitlab::GitAccess::ForbiddenError, include('wiki')) + end + def supports_block_expectations? + true + end end end diff --git a/spec/lib/gitlab/import_export/project/relation_factory_spec.rb b/spec/lib/gitlab/import_export/project/relation_factory_spec.rb index ffbbf9326ec..8477300c318 100644 --- a/spec/lib/gitlab/import_export/project/relation_factory_spec.rb +++ b/spec/lib/gitlab/import_export/project/relation_factory_spec.rb @@ -401,4 +401,22 @@ RSpec.describe Gitlab::ImportExport::Project::RelationFactory, :use_clean_rails_ expect(created_object.value).to be_nil end end + + context 'merge request access level object' do + let(:relation_sym) { :'ProtectedBranch::MergeAccessLevel' } + let(:relation_hash) { { 'access_level' => 30, 'created_at' => '2022-03-29T09:53:13.457Z', 'updated_at' => '2022-03-29T09:54:13.457Z' } } + + it 'sets access level to maintainer' do + expect(created_object.access_level).to equal(Gitlab::Access::MAINTAINER) + end + end + + context 'push access level object' do + let(:relation_sym) { :'ProtectedBranch::PushAccessLevel' } + let(:relation_hash) { { 'access_level' => 30, 'created_at' => '2022-03-29T09:53:13.457Z', 'updated_at' => '2022-03-29T09:54:13.457Z' } } + + it 'sets access level to maintainer' do + expect(created_object.access_level).to equal(Gitlab::Access::MAINTAINER) + end + end end diff --git a/spec/lib/gitlab/import_export/project/tree_restorer_spec.rb b/spec/lib/gitlab/import_export/project/tree_restorer_spec.rb index 8884722254d..33291f5eebf 100644 --- a/spec/lib/gitlab/import_export/project/tree_restorer_spec.rb +++ b/spec/lib/gitlab/import_export/project/tree_restorer_spec.rb @@ -111,6 +111,10 @@ RSpec.describe Gitlab::ImportExport::Project::TreeRestorer do end end + it 'does not import ci config path' do + expect(@project.ci_config_path).to be_nil + end + it 'creates a valid pipeline note' do expect(Ci::Pipeline.find_by_sha('sha-notes').notes).not_to be_empty end diff --git a/spec/lib/gitlab/metrics/subscribers/rack_attack_spec.rb b/spec/lib/gitlab/metrics/subscribers/rack_attack_spec.rb index 2d595632772..fda4b94bd78 100644 --- a/spec/lib/gitlab/metrics/subscribers/rack_attack_spec.rb +++ b/spec/lib/gitlab/metrics/subscribers/rack_attack_spec.rb @@ -91,72 +91,110 @@ RSpec.describe Gitlab::Metrics::Subscribers::RackAttack, :request_store do end end - context 'when matched throttle requires user information' do - context 'when user not found' do - let(:event) do - ActiveSupport::Notifications::Event.new( - event_name, Time.current, Time.current + 2.seconds, '1', request: double( - :request, - ip: '1.2.3.4', - request_method: 'GET', - fullpath: '/api/v4/internal/authorized_keys', - env: { - 'rack.attack.match_type' => match_type, - 'rack.attack.matched' => 'throttle_authenticated_api', - 'rack.attack.match_discriminator' => 'not_exist_user_id' - } + context 'matching user or deploy token authenticated information' do + context 'when matching for user' do + context 'when user not found' do + let(:event) do + ActiveSupport::Notifications::Event.new( + event_name, Time.current, Time.current + 2.seconds, '1', request: double( + :request, + ip: '1.2.3.4', + request_method: 'GET', + fullpath: '/api/v4/internal/authorized_keys', + env: { + 'rack.attack.match_type' => match_type, + 'rack.attack.matched' => 'throttle_authenticated_api', + 'rack.attack.match_discriminator' => "user:#{non_existing_record_id}" + } + ) ) - ) + end + + it 'logs request information and user id' do + expect(Gitlab::AuthLogger).to receive(:error).with( + include( + message: 'Rack_Attack', + env: match_type, + remote_ip: '1.2.3.4', + request_method: 'GET', + path: '/api/v4/internal/authorized_keys', + matched: 'throttle_authenticated_api', + user_id: non_existing_record_id + ) + ) + subscriber.send(match_type, event) + end end - it 'logs request information and user id' do - expect(Gitlab::AuthLogger).to receive(:error).with( - include( - message: 'Rack_Attack', - env: match_type, - remote_ip: '1.2.3.4', - request_method: 'GET', - path: '/api/v4/internal/authorized_keys', - matched: 'throttle_authenticated_api', - user_id: 'not_exist_user_id' + context 'when user found' do + let(:user) { create(:user) } + let(:event) do + ActiveSupport::Notifications::Event.new( + event_name, Time.current, Time.current + 2.seconds, '1', request: double( + :request, + ip: '1.2.3.4', + request_method: 'GET', + fullpath: '/api/v4/internal/authorized_keys', + env: { + 'rack.attack.match_type' => match_type, + 'rack.attack.matched' => 'throttle_authenticated_api', + 'rack.attack.match_discriminator' => "user:#{user.id}" + } + ) ) - ) - subscriber.send(match_type, event) + end + + it 'logs request information and user meta' do + expect(Gitlab::AuthLogger).to receive(:error).with( + include( + message: 'Rack_Attack', + env: match_type, + remote_ip: '1.2.3.4', + request_method: 'GET', + path: '/api/v4/internal/authorized_keys', + matched: 'throttle_authenticated_api', + user_id: user.id, + 'meta.user' => user.username + ) + ) + subscriber.send(match_type, event) + end end end - context 'when user found' do - let(:user) { create(:user) } - let(:event) do - ActiveSupport::Notifications::Event.new( - event_name, Time.current, Time.current + 2.seconds, '1', request: double( - :request, - ip: '1.2.3.4', - request_method: 'GET', - fullpath: '/api/v4/internal/authorized_keys', - env: { - 'rack.attack.match_type' => match_type, - 'rack.attack.matched' => 'throttle_authenticated_api', - 'rack.attack.match_discriminator' => user.id - } + context 'when matching for deploy token' do + context 'when deploy token found' do + let(:deploy_token) { create(:deploy_token) } + let(:event) do + ActiveSupport::Notifications::Event.new( + event_name, Time.current, Time.current + 2.seconds, '1', request: double( + :request, + ip: '1.2.3.4', + request_method: 'GET', + fullpath: '/api/v4/internal/authorized_keys', + env: { + 'rack.attack.match_type' => match_type, + 'rack.attack.matched' => 'throttle_authenticated_api', + 'rack.attack.match_discriminator' => "deploy_token:#{deploy_token.id}" + } + ) ) - ) - end - - it 'logs request information and user meta' do - expect(Gitlab::AuthLogger).to receive(:error).with( - include( - message: 'Rack_Attack', - env: match_type, - remote_ip: '1.2.3.4', - request_method: 'GET', - path: '/api/v4/internal/authorized_keys', - matched: 'throttle_authenticated_api', - user_id: user.id, - 'meta.user' => user.username + end + + it 'logs request information and user meta' do + expect(Gitlab::AuthLogger).to receive(:error).with( + include( + message: 'Rack_Attack', + env: match_type, + remote_ip: '1.2.3.4', + request_method: 'GET', + path: '/api/v4/internal/authorized_keys', + matched: 'throttle_authenticated_api', + deploy_token_id: deploy_token.id + ) ) - ) - subscriber.send(match_type, event) + subscriber.send(match_type, event) + end end end end diff --git a/spec/lib/gitlab/regex_spec.rb b/spec/lib/gitlab/regex_spec.rb index 54a0b282e99..5d5f6ebb817 100644 --- a/spec/lib/gitlab/regex_spec.rb +++ b/spec/lib/gitlab/regex_spec.rb @@ -990,4 +990,19 @@ RSpec.describe Gitlab::Regex do it { is_expected.not_to match('../../../../../1.2.3') } it { is_expected.not_to match('%2e%2e%2f1.2.3') } end + + describe '.sha256_regex' do + subject { described_class.sha256_regex } + + it { is_expected.to match('a' * 64) } + it { is_expected.to match('abcdefABCDEF1234567890abcdefABCDEF1234567890abcdefABCDEF12345678') } + it { is_expected.not_to match('a' * 63) } + it { is_expected.not_to match('a' * 65) } + it { is_expected.not_to match('a' * 63 + 'g') } + it { is_expected.not_to match('a' * 63 + '{') } + it { is_expected.not_to match('a' * 63 + '%') } + it { is_expected.not_to match('a' * 63 + '*') } + it { is_expected.not_to match('a' * 63 + '#') } + it { is_expected.not_to match('') } + end end |