Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/spec
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2021-02-02 03:09:14 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2021-02-02 03:09:14 +0300
commitd8714cf67ce4db786b26b64f0f0bef50fb6976e6 (patch)
tree9a3cc1da29cb2a16113b6b8a1a48b82f368cbb22 /spec
parent3feea9b6078811d20b42548ba98272eeed5af9e4 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
-rw-r--r--spec/controllers/admin/runners_controller_spec.rb3
-rw-r--r--spec/controllers/projects/releases_controller_spec.rb9
-rw-r--r--spec/factories/packages.rb18
-rw-r--r--spec/factories/token_with_ivs.rb9
-rw-r--r--spec/fixtures/packages/composer/package.json1
-rw-r--r--spec/frontend/vue_mr_widget/components/mr_widget_pipeline_container_spec.js12
-rw-r--r--spec/lib/gitlab/composer/cache_spec.rb133
-rw-r--r--spec/lib/gitlab/composer/version_index_spec.rb16
-rw-r--r--spec/lib/gitlab/crypto_helper_spec.rb78
-rw-r--r--spec/lib/gitlab/current_settings_spec.rb28
-rw-r--r--spec/lib/gitlab/graphql/query_analyzers/logger_analyzer_spec.rb18
-rw-r--r--spec/lib/gitlab/url_blocker_spec.rb15
-rw-r--r--spec/lib/gitlab_spec.rb24
-rw-r--r--spec/migrations/encrypt_feature_flags_clients_tokens_spec.rb2
-rw-r--r--spec/models/active_session_spec.rb2
-rw-r--r--spec/models/concerns/token_authenticatable_spec.rb4
-rw-r--r--spec/models/concerns/token_authenticatable_strategies/encrypted_spec.rb8
-rw-r--r--spec/models/packages/composer/cache_file_spec.rb32
-rw-r--r--spec/models/packages/composer/metadatum_spec.rb16
-rw-r--r--spec/models/token_with_iv_spec.rb29
-rw-r--r--spec/presenters/release_presenter_spec.rb6
-rw-r--r--spec/requests/git_http_spec.rb8
-rw-r--r--spec/routing/git_http_routing_spec.rb21
-rw-r--r--spec/routing/project_routing_spec.rb69
-rw-r--r--spec/spec_helper.rb2
-rw-r--r--spec/support/helpers/stub_configuration.rb6
-rw-r--r--spec/support/helpers/stub_object_storage.rb7
-rw-r--r--spec/support/matchers/route_to_route_not_found_matcher.rb15
-rw-r--r--spec/support/shared_examples/routing/git_http_routing_shared_examples.rb54
-rw-r--r--spec/uploaders/packages/composer/cache_uploader_spec.rb45
30 files changed, 664 insertions, 26 deletions
diff --git a/spec/controllers/admin/runners_controller_spec.rb b/spec/controllers/admin/runners_controller_spec.rb
index 3fffc50475c..cba25dbff95 100644
--- a/spec/controllers/admin/runners_controller_spec.rb
+++ b/spec/controllers/admin/runners_controller_spec.rb
@@ -27,7 +27,8 @@ RSpec.describe Admin::RunnersController do
# There is still an N+1 query for `runner.builds.count`
# We also need to add 1 because it takes 2 queries to preload tags
- expect { get :index }.not_to exceed_query_limit(control_count + 6)
+ # also looking for token nonce requires database queries
+ expect { get :index }.not_to exceed_query_limit(control_count + 16)
expect(response).to have_gitlab_http_status(:ok)
expect(response.body).to have_content('tag1')
diff --git a/spec/controllers/projects/releases_controller_spec.rb b/spec/controllers/projects/releases_controller_spec.rb
index c1f1373ddc2..fc7ab88bbe0 100644
--- a/spec/controllers/projects/releases_controller_spec.rb
+++ b/spec/controllers/projects/releases_controller_spec.rb
@@ -9,6 +9,7 @@ RSpec.describe Projects::ReleasesController do
let_it_be(:private_project) { create(:project, :repository, :private) }
let_it_be(:developer) { create(:user) }
let_it_be(:reporter) { create(:user) }
+ let_it_be(:guest) { create(:user) }
let_it_be(:user) { developer }
let!(:release_1) { create(:release, project: project, released_at: Time.zone.parse('2018-10-18')) }
let!(:release_2) { create(:release, project: project, released_at: Time.zone.parse('2019-10-19')) }
@@ -16,6 +17,7 @@ RSpec.describe Projects::ReleasesController do
before do
project.add_developer(developer)
project.add_reporter(reporter)
+ project.add_guest(guest)
end
shared_examples_for 'successful request' do
@@ -199,6 +201,13 @@ RSpec.describe Projects::ReleasesController do
it_behaves_like 'not found'
end
+
+ context 'when user is a guest' do
+ let(:project) { private_project }
+ let(:user) { guest }
+
+ it_behaves_like 'not found'
+ end
end
# `GET #downloads` is addressed in spec/requests/projects/releases_controller_spec.rb
diff --git a/spec/factories/packages.rb b/spec/factories/packages.rb
index 31f1aabe5dd..ca38793ac08 100644
--- a/spec/factories/packages.rb
+++ b/spec/factories/packages.rb
@@ -176,6 +176,24 @@ FactoryBot.define do
composer_json { { name: 'foo' } }
end
+ factory :composer_cache_file, class: 'Packages::Composer::CacheFile' do
+ group
+
+ file_sha256 { '1' * 64 }
+
+ transient do
+ file_fixture { 'spec/fixtures/packages/composer/package.json' }
+ end
+
+ after(:build) do |cache_file, evaluator|
+ cache_file.file = fixture_file_upload(evaluator.file_fixture)
+ end
+
+ trait(:object_storage) do
+ file_store { Packages::Composer::CacheUploader::Store::REMOTE }
+ end
+ end
+
factory :maven_metadatum, class: 'Packages::Maven::Metadatum' do
association :package, package_type: :maven
path { 'my/company/app/my-app/1.0-SNAPSHOT' }
diff --git a/spec/factories/token_with_ivs.rb b/spec/factories/token_with_ivs.rb
new file mode 100644
index 00000000000..68989f6c5bc
--- /dev/null
+++ b/spec/factories/token_with_ivs.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+FactoryBot.define do
+ factory :token_with_iv do
+ hashed_token { ::Digest::SHA256.digest(SecureRandom.hex(50)) }
+ iv { ::Digest::SHA256.digest(SecureRandom.hex(50)) }
+ hashed_plaintext_token { ::Digest::SHA256.digest(SecureRandom.hex(50)) }
+ end
+end
diff --git a/spec/fixtures/packages/composer/package.json b/spec/fixtures/packages/composer/package.json
new file mode 100644
index 00000000000..0967ef424bc
--- /dev/null
+++ b/spec/fixtures/packages/composer/package.json
@@ -0,0 +1 @@
+{}
diff --git a/spec/frontend/vue_mr_widget/components/mr_widget_pipeline_container_spec.js b/spec/frontend/vue_mr_widget/components/mr_widget_pipeline_container_spec.js
index f4890c857d1..bc192a7d9d8 100644
--- a/spec/frontend/vue_mr_widget/components/mr_widget_pipeline_container_spec.js
+++ b/spec/frontend/vue_mr_widget/components/mr_widget_pipeline_container_spec.js
@@ -78,6 +78,18 @@ describe('MrWidgetPipelineContainer', () => {
});
});
+ it('sanitizes the targetBranch', () => {
+ factory({
+ isPostMerge: true,
+ mr: {
+ ...mockStore,
+ targetBranch: 'Foo<script>alert("XSS")</script>',
+ },
+ });
+
+ expect(wrapper.find(MrWidgetPipeline).props().sourceBranchLink).toBe('Foo');
+ });
+
it('renders deployments', () => {
const expectedProps = mockStore.postMergeDeployments.map((dep) =>
expect.objectContaining({
diff --git a/spec/lib/gitlab/composer/cache_spec.rb b/spec/lib/gitlab/composer/cache_spec.rb
new file mode 100644
index 00000000000..00318ac14f9
--- /dev/null
+++ b/spec/lib/gitlab/composer/cache_spec.rb
@@ -0,0 +1,133 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Composer::Cache do
+ let_it_be(:package_name) { 'sample-project' }
+ let_it_be(:json) { { 'name' => package_name } }
+ let_it_be(:group) { create(:group) }
+ let_it_be(:project) { create(:project, :custom_repo, files: { 'composer.json' => json.to_json }, group: group) }
+ let(:branch) { project.repository.find_branch('master') }
+ let(:sha_regex) { /^[A-Fa-f0-9]{64}$/ }
+
+ shared_examples 'Composer create cache page' do
+ let(:expected_json) { ::Gitlab::Composer::VersionIndex.new(packages).to_json }
+
+ before do
+ stub_composer_cache_object_storage
+ end
+
+ it 'creates the cached page' do
+ expect { subject }.to change { Packages::Composer::CacheFile.count }.by(1)
+ cache_file = Packages::Composer::CacheFile.last
+ expect(cache_file.file_sha256).to eq package.reload.composer_metadatum.version_cache_sha
+ expect(cache_file.file.read).to eq expected_json
+ end
+ end
+
+ shared_examples 'Composer marks cache page for deletion' do
+ it 'marks the page for deletion' do
+ cache_file = Packages::Composer::CacheFile.last
+
+ freeze_time do
+ expect { subject }.to change { cache_file.reload.delete_at}.from(nil).to(1.day.from_now)
+ end
+ end
+ end
+
+ describe '#execute' do
+ subject { described_class.new(project: project, name: package_name).execute }
+
+ context 'creating packages' do
+ context 'with a pre-existing package' do
+ let(:package) { create(:composer_package, :with_metadatum, project: project, name: package_name, version: '1.0.0', json: json) }
+ let(:package2) { create(:composer_package, :with_metadatum, project: project, name: package_name, version: '2.0.0', json: json) }
+ let(:packages) { [package, package2] }
+
+ before do
+ package
+ described_class.new(project: project, name: package_name).execute
+ package.reload
+ package2
+ end
+
+ it 'updates the sha and creates the cache page' do
+ expect { subject }.to change { package2.reload.composer_metadatum.version_cache_sha }.from(nil).to(sha_regex)
+ .and change { package.reload.composer_metadatum.version_cache_sha }.to(sha_regex)
+ end
+
+ it_behaves_like 'Composer create cache page'
+ it_behaves_like 'Composer marks cache page for deletion'
+ end
+
+ context 'first package' do
+ let!(:package) { create(:composer_package, :with_metadatum, project: project, name: package_name, version: '1.0.0', json: json) }
+ let(:packages) { [package] }
+
+ it 'updates the sha and creates the cache page' do
+ expect { subject }.to change { package.reload.composer_metadatum.version_cache_sha }.from(nil).to(sha_regex)
+ end
+
+ it_behaves_like 'Composer create cache page'
+ end
+ end
+
+ context 'updating packages' do
+ let(:package) { create(:composer_package, :with_metadatum, project: project, name: package_name, version: '1.0.0', json: json) }
+ let(:package2) { create(:composer_package, :with_metadatum, project: project, name: package_name, version: '2.0.0', json: json) }
+ let(:packages) { [package, package2] }
+
+ before do
+ packages
+
+ described_class.new(project: project, name: package_name).execute
+
+ package.update!(version: '1.2.0')
+ package.reload
+ end
+
+ it_behaves_like 'Composer create cache page'
+ it_behaves_like 'Composer marks cache page for deletion'
+ end
+
+ context 'deleting packages' do
+ context 'when it is not the last package' do
+ let(:package) { create(:composer_package, :with_metadatum, project: project, name: package_name, version: '1.0.0', json: json) }
+ let(:package2) { create(:composer_package, :with_metadatum, project: project, name: package_name, version: '2.0.0', json: json) }
+ let(:packages) { [package] }
+
+ before do
+ package
+ package2
+
+ described_class.new(project: project, name: package_name).execute
+
+ package2.destroy!
+ end
+
+ it_behaves_like 'Composer create cache page'
+ it_behaves_like 'Composer marks cache page for deletion'
+ end
+
+ context 'when it is the last package' do
+ let!(:package) { create(:composer_package, :with_metadatum, project: project, name: package_name, version: '1.0.0', json: json) }
+ let!(:last_sha) do
+ described_class.new(project: project, name: package_name).execute
+ package.reload.composer_metadatum.version_cache_sha
+ end
+
+ before do
+ package.destroy!
+ end
+
+ subject { described_class.new(project: project, name: package_name, last_page_sha: last_sha).execute }
+
+ it_behaves_like 'Composer marks cache page for deletion'
+
+ it 'does not create a new page' do
+ expect { subject }.not_to change { Packages::Composer::CacheFile.count }
+ end
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/composer/version_index_spec.rb b/spec/lib/gitlab/composer/version_index_spec.rb
index 4c4742d9f59..7b0ed703f42 100644
--- a/spec/lib/gitlab/composer/version_index_spec.rb
+++ b/spec/lib/gitlab/composer/version_index_spec.rb
@@ -15,7 +15,9 @@ RSpec.describe Gitlab::Composer::VersionIndex do
let(:packages) { [package1, package2] }
describe '#as_json' do
- subject(:index) { described_class.new(packages).as_json }
+ subject(:package_index) { index['packages'][package_name] }
+
+ let(:index) { described_class.new(packages).as_json }
def expected_json(package)
{
@@ -32,10 +34,16 @@ RSpec.describe Gitlab::Composer::VersionIndex do
end
it 'returns the packages json' do
- packages = index['packages'][package_name]
+ expect(package_index['1.0.0']).to eq(expected_json(package1))
+ expect(package_index['2.0.0']).to eq(expected_json(package2))
+ end
+
+ context 'with an unordered list of packages' do
+ let(:packages) { [package2, package1] }
- expect(packages['1.0.0']).to eq(expected_json(package1))
- expect(packages['2.0.0']).to eq(expected_json(package2))
+ it 'returns the packages sorted by version' do
+ expect(package_index.keys).to eq ['1.0.0', '2.0.0']
+ end
end
end
diff --git a/spec/lib/gitlab/crypto_helper_spec.rb b/spec/lib/gitlab/crypto_helper_spec.rb
index c07089d8ef0..024564ea213 100644
--- a/spec/lib/gitlab/crypto_helper_spec.rb
+++ b/spec/lib/gitlab/crypto_helper_spec.rb
@@ -19,21 +19,85 @@ RSpec.describe Gitlab::CryptoHelper do
expect(encrypted).to match %r{\A[A-Za-z0-9+/=]+\z}
expect(encrypted).not_to include "\n"
end
+
+ it 'does not save hashed token with iv value in database' do
+ expect { described_class.aes256_gcm_encrypt('some-value') }.not_to change { TokenWithIv.count }
+ end
+
+ it 'encrypts using static iv' do
+ expect(Encryptor).to receive(:encrypt).with(described_class::AES256_GCM_OPTIONS.merge(value: 'some-value', iv: described_class::AES256_GCM_IV_STATIC)).and_return('hashed_value')
+
+ described_class.aes256_gcm_encrypt('some-value')
+ end
end
describe '.aes256_gcm_decrypt' do
- let(:encrypted) { described_class.aes256_gcm_encrypt('some-value') }
+ before do
+ stub_feature_flags(dynamic_nonce_creation: false)
+ end
+
+ context 'when token was encrypted using static nonce' do
+ let(:encrypted) { described_class.aes256_gcm_encrypt('some-value', nonce: described_class::AES256_GCM_IV_STATIC) }
+
+ it 'correctly decrypts encrypted string' do
+ decrypted = described_class.aes256_gcm_decrypt(encrypted)
+
+ expect(decrypted).to eq 'some-value'
+ end
+
+ it 'decrypts a value when it ends with a new line character' do
+ decrypted = described_class.aes256_gcm_decrypt(encrypted + "\n")
- it 'correctly decrypts encrypted string' do
- decrypted = described_class.aes256_gcm_decrypt(encrypted)
+ expect(decrypted).to eq 'some-value'
+ end
- expect(decrypted).to eq 'some-value'
+ it 'does not save hashed token with iv value in database' do
+ expect { described_class.aes256_gcm_decrypt(encrypted) }.not_to change { TokenWithIv.count }
+ end
+
+ context 'with feature flag switched on' do
+ before do
+ stub_feature_flags(dynamic_nonce_creation: true)
+ end
+
+ it 'correctly decrypts encrypted string' do
+ decrypted = described_class.aes256_gcm_decrypt(encrypted)
+
+ expect(decrypted).to eq 'some-value'
+ end
+ end
end
- it 'decrypts a value when it ends with a new line character' do
- decrypted = described_class.aes256_gcm_decrypt(encrypted + "\n")
+ context 'when token was encrypted using random nonce' do
+ let(:value) { 'random-value' }
+
+ # for compatibility with tokens encrypted using dynamic nonce
+ let!(:encrypted) do
+ iv = create_nonce
+ encrypted_token = described_class.create_encrypted_token(value, iv)
+ TokenWithIv.create!(hashed_token: Digest::SHA256.digest(encrypted_token), hashed_plaintext_token: Digest::SHA256.digest(encrypted_token), iv: iv)
+ encrypted_token
+ end
+
+ before do
+ stub_feature_flags(dynamic_nonce_creation: true)
+ end
- expect(decrypted).to eq 'some-value'
+ it 'correctly decrypts encrypted string' do
+ decrypted = described_class.aes256_gcm_decrypt(encrypted)
+
+ expect(decrypted).to eq value
+ end
+
+ it 'does not save hashed token with iv value in database' do
+ expect { described_class.aes256_gcm_decrypt(encrypted) }.not_to change { TokenWithIv.count }
+ end
end
end
+
+ def create_nonce
+ cipher = OpenSSL::Cipher.new('aes-256-gcm')
+ cipher.encrypt # Required before '#random_iv' can be called
+ cipher.random_iv # Ensures that the IV is the correct length respective to the algorithm used.
+ end
end
diff --git a/spec/lib/gitlab/current_settings_spec.rb b/spec/lib/gitlab/current_settings_spec.rb
index 786db23ffc4..01aceec12c5 100644
--- a/spec/lib/gitlab/current_settings_spec.rb
+++ b/spec/lib/gitlab/current_settings_spec.rb
@@ -194,4 +194,32 @@ RSpec.describe Gitlab::CurrentSettings do
end
end
end
+
+ describe '#current_application_settings?', :use_clean_rails_memory_store_caching do
+ before do
+ allow(Gitlab::CurrentSettings).to receive(:current_application_settings?).and_call_original
+ end
+
+ it 'returns true when settings exist' do
+ create(:application_setting,
+ home_page_url: 'http://mydomain.com',
+ signup_enabled: false)
+
+ expect(described_class.current_application_settings?).to eq(true)
+ end
+
+ it 'returns false when settings do not exist' do
+ expect(described_class.current_application_settings?).to eq(false)
+ end
+
+ context 'with cache', :request_store do
+ include_context 'with settings in cache'
+
+ it 'returns an in-memory ApplicationSetting object' do
+ expect(ApplicationSetting).not_to receive(:current)
+
+ expect(described_class.current_application_settings?).to eq(true)
+ end
+ end
+ end
end
diff --git a/spec/lib/gitlab/graphql/query_analyzers/logger_analyzer_spec.rb b/spec/lib/gitlab/graphql/query_analyzers/logger_analyzer_spec.rb
index c8432513185..138765afd8a 100644
--- a/spec/lib/gitlab/graphql/query_analyzers/logger_analyzer_spec.rb
+++ b/spec/lib/gitlab/graphql/query_analyzers/logger_analyzer_spec.rb
@@ -40,4 +40,22 @@ RSpec.describe Gitlab::Graphql::QueryAnalyzers::LoggerAnalyzer do
end
end
end
+
+ describe '#initial_value' do
+ it 'filters out sensitive variables' do
+ doc = GraphQL.parse <<-GRAPHQL
+ mutation createNote($body: String!) {
+ createNote(input: {noteableId: "1", body: $body}) {
+ note {
+ id
+ }
+ }
+ }
+ GRAPHQL
+
+ query = GraphQL::Query.new(GitlabSchema, document: doc, context: {}, variables: { body: "some note" })
+
+ expect(subject.initial_value(query)[:variables]).to eq('{:body=>"[FILTERED]"}')
+ end
+ end
end
diff --git a/spec/lib/gitlab/url_blocker_spec.rb b/spec/lib/gitlab/url_blocker_spec.rb
index f466d117851..686382dc262 100644
--- a/spec/lib/gitlab/url_blocker_spec.rb
+++ b/spec/lib/gitlab/url_blocker_spec.rb
@@ -91,6 +91,21 @@ RSpec.describe Gitlab::UrlBlocker, :stub_invalid_dns_only do
end
end
+ context 'DNS rebinding protection with IP allowed' do
+ let(:import_url) { 'http://a.192.168.0.120.3times.127.0.0.1.1time.repeat.rebind.network:9121/scrape?target=unix:///var/opt/gitlab/redis/redis.socket&amp;check-keys=*' }
+
+ before do
+ stub_dns(import_url, ip_address: '192.168.0.120')
+
+ allow(Gitlab::UrlBlockers::UrlAllowlist).to receive(:ip_allowed?).and_return(true)
+ end
+
+ it_behaves_like 'validates URI and hostname' do
+ let(:expected_uri) { 'http://192.168.0.120:9121/scrape?target=unix:///var/opt/gitlab/redis/redis.socket&amp;check-keys=*' }
+ let(:expected_hostname) { 'a.192.168.0.120.3times.127.0.0.1.1time.repeat.rebind.network' }
+ end
+ end
+
context 'disabled DNS rebinding protection' do
subject { described_class.validate!(import_url, dns_rebind_protection: false) }
diff --git a/spec/lib/gitlab_spec.rb b/spec/lib/gitlab_spec.rb
index e1b8323eb8e..5f945d5b9fc 100644
--- a/spec/lib/gitlab_spec.rb
+++ b/spec/lib/gitlab_spec.rb
@@ -95,6 +95,26 @@ RSpec.describe Gitlab do
end
end
+ describe '.com' do
+ subject { described_class.com { true } }
+
+ before do
+ allow(described_class).to receive(:com?).and_return(gl_com)
+ end
+
+ context 'when on GitLab.com' do
+ let(:gl_com) { true }
+
+ it { is_expected.to be true }
+ end
+
+ context 'when not on GitLab.com' do
+ let(:gl_com) { false }
+
+ it { is_expected.to be_nil }
+ end
+ end
+
describe '.staging?' do
subject { described_class.staging? }
@@ -332,13 +352,13 @@ RSpec.describe Gitlab do
describe '.maintenance_mode?' do
it 'returns true when maintenance mode is enabled' do
- stub_application_setting(maintenance_mode: true)
+ stub_maintenance_mode_setting(true)
expect(described_class.maintenance_mode?).to eq(true)
end
it 'returns false when maintenance mode is disabled' do
- stub_application_setting(maintenance_mode: false)
+ stub_maintenance_mode_setting(false)
expect(described_class.maintenance_mode?).to eq(false)
end
diff --git a/spec/migrations/encrypt_feature_flags_clients_tokens_spec.rb b/spec/migrations/encrypt_feature_flags_clients_tokens_spec.rb
index ad83119f324..c705515ce98 100644
--- a/spec/migrations/encrypt_feature_flags_clients_tokens_spec.rb
+++ b/spec/migrations/encrypt_feature_flags_clients_tokens_spec.rb
@@ -8,7 +8,7 @@ RSpec.describe EncryptFeatureFlagsClientsTokens do
let(:feature_flags_clients) { table(:operations_feature_flags_clients) }
let(:projects) { table(:projects) }
let(:plaintext) { "secret-token" }
- let(:ciphertext) { Gitlab::CryptoHelper.aes256_gcm_encrypt(plaintext) }
+ let(:ciphertext) { Gitlab::CryptoHelper.aes256_gcm_encrypt(plaintext, nonce: Gitlab::CryptoHelper::AES256_GCM_IV_STATIC) }
describe '#up' do
it 'keeps plaintext token the same and populates token_encrypted if not present' do
diff --git a/spec/models/active_session_spec.rb b/spec/models/active_session_spec.rb
index f0bae3f29c0..51435cc4342 100644
--- a/spec/models/active_session_spec.rb
+++ b/spec/models/active_session_spec.rb
@@ -358,7 +358,7 @@ RSpec.describe ActiveSession, :clean_gitlab_redis_shared_state do
it 'calls .destroy_sessions' do
expect(ActiveSession).to(
receive(:destroy_sessions)
- .with(anything, user, [active_session.public_id, rack_session.public_id, rack_session.private_id]))
+ .with(anything, user, [encrypted_active_session_id, rack_session.public_id, rack_session.private_id]))
subject
end
diff --git a/spec/models/concerns/token_authenticatable_spec.rb b/spec/models/concerns/token_authenticatable_spec.rb
index d8b77e1cd0d..2df76684d71 100644
--- a/spec/models/concerns/token_authenticatable_spec.rb
+++ b/spec/models/concerns/token_authenticatable_spec.rb
@@ -54,7 +54,7 @@ RSpec.describe ApplicationSetting, 'TokenAuthenticatable' do
it 'persists new token as an encrypted string' do
expect(subject).to eq settings.reload.runners_registration_token
expect(settings.read_attribute('runners_registration_token_encrypted'))
- .to eq Gitlab::CryptoHelper.aes256_gcm_encrypt(subject)
+ .to eq Gitlab::CryptoHelper.aes256_gcm_encrypt(subject, nonce: Gitlab::CryptoHelper::AES256_GCM_IV_STATIC)
expect(settings).to be_persisted
end
@@ -243,7 +243,7 @@ RSpec.describe Ci::Build, 'TokenAuthenticatable' do
it 'persists new token as an encrypted string' do
build.ensure_token!
- encrypted = Gitlab::CryptoHelper.aes256_gcm_encrypt(build.token)
+ encrypted = Gitlab::CryptoHelper.aes256_gcm_encrypt(build.token, nonce: Gitlab::CryptoHelper::AES256_GCM_IV_STATIC)
expect(build.read_attribute('token_encrypted')).to eq encrypted
end
diff --git a/spec/models/concerns/token_authenticatable_strategies/encrypted_spec.rb b/spec/models/concerns/token_authenticatable_strategies/encrypted_spec.rb
index f6b8cf7def4..1e1cd97e410 100644
--- a/spec/models/concerns/token_authenticatable_strategies/encrypted_spec.rb
+++ b/spec/models/concerns/token_authenticatable_strategies/encrypted_spec.rb
@@ -68,6 +68,10 @@ RSpec.describe TokenAuthenticatableStrategies::Encrypted do
context 'when using optional strategy' do
let(:options) { { encrypted: :optional } }
+ before do
+ stub_feature_flags(dynamic_nonce_creation: false)
+ end
+
it 'returns decrypted token when an encrypted token is present' do
allow(instance).to receive(:read_attribute)
.with('some_field_encrypted')
@@ -124,7 +128,7 @@ RSpec.describe TokenAuthenticatableStrategies::Encrypted do
it 'writes encrypted token and removes plaintext token and returns it' do
expect(instance).to receive(:[]=)
- .with('some_field_encrypted', encrypted)
+ .with('some_field_encrypted', any_args)
expect(instance).to receive(:[]=)
.with('some_field', nil)
@@ -137,7 +141,7 @@ RSpec.describe TokenAuthenticatableStrategies::Encrypted do
it 'writes encrypted token and writes plaintext token' do
expect(instance).to receive(:[]=)
- .with('some_field_encrypted', encrypted)
+ .with('some_field_encrypted', any_args)
expect(instance).to receive(:[]=)
.with('some_field', 'my-value')
diff --git a/spec/models/packages/composer/cache_file_spec.rb b/spec/models/packages/composer/cache_file_spec.rb
new file mode 100644
index 00000000000..ef9818f0930
--- /dev/null
+++ b/spec/models/packages/composer/cache_file_spec.rb
@@ -0,0 +1,32 @@
+# frozen_string_literal: true
+require 'spec_helper'
+
+RSpec.describe Packages::Composer::CacheFile, type: :model do
+ describe 'relationships' do
+ it { is_expected.to belong_to(:group) }
+ it { is_expected.to belong_to(:namespace) }
+ end
+
+ describe 'validations' do
+ it { is_expected.to validate_presence_of(:namespace) }
+ end
+
+ describe 'scopes' do
+ let_it_be(:group1) { create(:group) }
+ let_it_be(:group2) { create(:group) }
+ let_it_be(:cache_file1) { create(:composer_cache_file, file_sha256: '123456', group: group1) }
+ let_it_be(:cache_file2) { create(:composer_cache_file, file_sha256: '456778', group: group2) }
+
+ describe '.with_namespace' do
+ subject { described_class.with_namespace(group1) }
+
+ it { is_expected.to eq [cache_file1] }
+ end
+
+ describe '.with_sha' do
+ subject { described_class.with_sha('123456') }
+
+ it { is_expected.to eq [cache_file1] }
+ end
+ end
+end
diff --git a/spec/models/packages/composer/metadatum_spec.rb b/spec/models/packages/composer/metadatum_spec.rb
index ae53532696b..1c888f1563c 100644
--- a/spec/models/packages/composer/metadatum_spec.rb
+++ b/spec/models/packages/composer/metadatum_spec.rb
@@ -11,4 +11,20 @@ RSpec.describe Packages::Composer::Metadatum, type: :model do
it { is_expected.to validate_presence_of(:target_sha) }
it { is_expected.to validate_presence_of(:composer_json) }
end
+
+ describe 'scopes' do
+ let_it_be(:package_name) { 'sample-project' }
+ let_it_be(:json) { { 'name' => package_name } }
+ let_it_be(:group) { create(:group) }
+ let_it_be(:project) { create(:project, :custom_repo, files: { 'composer.json' => json.to_json }, group: group) }
+ let_it_be(:package1) { create(:composer_package, :with_metadatum, project: project, name: package_name, version: '1.0.0', json: json) }
+ let_it_be(:package2) { create(:composer_package, :with_metadatum, project: project, name: 'other-name', version: '1.0.0', json: json) }
+ let_it_be(:package3) { create(:pypi_package, name: package_name, project: project) }
+
+ describe '.for_package' do
+ subject { described_class.for_package(package_name, project.id) }
+
+ it { is_expected.to eq [package1.composer_metadatum] }
+ end
+ end
end
diff --git a/spec/models/token_with_iv_spec.rb b/spec/models/token_with_iv_spec.rb
new file mode 100644
index 00000000000..8dbccc19217
--- /dev/null
+++ b/spec/models/token_with_iv_spec.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe TokenWithIv do
+ describe 'validations' do
+ it { is_expected.to validate_presence_of :hashed_token }
+ it { is_expected.to validate_presence_of :iv }
+ it { is_expected.to validate_presence_of :hashed_plaintext_token }
+ end
+
+ describe '.find_by_hashed_token' do
+ it 'only includes matching record' do
+ matching_record = create(:token_with_iv, hashed_token: ::Digest::SHA256.digest('hashed-token'))
+ create(:token_with_iv)
+
+ expect(described_class.find_by_hashed_token('hashed-token')).to eq(matching_record)
+ end
+ end
+
+ describe '.find_by_plaintext_token' do
+ it 'only includes matching record' do
+ matching_record = create(:token_with_iv, hashed_plaintext_token: ::Digest::SHA256.digest('hashed-token'))
+ create(:token_with_iv)
+
+ expect(described_class.find_by_plaintext_token('hashed-token')).to eq(matching_record)
+ end
+ end
+end
diff --git a/spec/presenters/release_presenter_spec.rb b/spec/presenters/release_presenter_spec.rb
index b518584569b..4bf12183eff 100644
--- a/spec/presenters/release_presenter_spec.rb
+++ b/spec/presenters/release_presenter_spec.rb
@@ -62,6 +62,12 @@ RSpec.describe ReleasePresenter do
it 'returns its own url' do
is_expected.to eq(project_release_url(project, release))
end
+
+ context 'when user is guest' do
+ let(:user) { guest }
+
+ it { is_expected.to be_nil }
+ end
end
describe '#opened_merge_requests_url' do
diff --git a/spec/requests/git_http_spec.rb b/spec/requests/git_http_spec.rb
index bc89dc2fa77..1ee3e36be8b 100644
--- a/spec/requests/git_http_spec.rb
+++ b/spec/requests/git_http_spec.rb
@@ -159,13 +159,17 @@ RSpec.describe 'Git HTTP requests' do
context "POST git-upload-pack" do
it "fails to find a route" do
- expect { clone_post(repository_path) }.to raise_error(ActionController::RoutingError)
+ clone_post(repository_path) do |response|
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
end
end
context "POST git-receive-pack" do
it "fails to find a route" do
- expect { push_post(repository_path) }.to raise_error(ActionController::RoutingError)
+ push_post(repository_path) do |response|
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
end
end
end
diff --git a/spec/routing/git_http_routing_spec.rb b/spec/routing/git_http_routing_spec.rb
index e3cc1440a9e..79d392e4132 100644
--- a/spec/routing/git_http_routing_spec.rb
+++ b/spec/routing/git_http_routing_spec.rb
@@ -7,6 +7,10 @@ RSpec.describe 'git_http routing' do
it_behaves_like 'git repository routes' do
let(:path) { '/gitlab-org/gitlab-test.git' }
end
+
+ it_behaves_like 'git repository routes with fallback for git-upload-pack' do
+ let(:path) { '/gitlab-org/gitlab-test.git' }
+ end
end
describe 'wiki repositories' do
@@ -14,6 +18,7 @@ RSpec.describe 'git_http routing' do
let(:path) { '/gitlab-org/gitlab-test.wiki.git' }
it_behaves_like 'git repository routes'
+ it_behaves_like 'git repository routes with fallback for git-upload-pack'
describe 'redirects', type: :request do
let(:web_path) { '/gitlab-org/gitlab-test/-/wikis' }
@@ -37,12 +42,20 @@ RSpec.describe 'git_http routing' do
it_behaves_like 'git repository routes' do
let(:path) { '/gitlab-org.wiki.git' }
end
+
+ it_behaves_like 'git repository routes with fallback for git-upload-pack' do
+ let(:path) { '/gitlab-org.wiki.git' }
+ end
end
context 'in child group' do
it_behaves_like 'git repository routes' do
let(:path) { '/gitlab-org/child.wiki.git' }
end
+
+ it_behaves_like 'git repository routes with fallback for git-upload-pack' do
+ let(:path) { '/gitlab-org/child.wiki.git' }
+ end
end
end
@@ -51,12 +64,20 @@ RSpec.describe 'git_http routing' do
it_behaves_like 'git repository routes' do
let(:path) { '/snippets/123.git' }
end
+
+ it_behaves_like 'git repository routes without fallback' do
+ let(:path) { '/snippets/123.git' }
+ end
end
context 'project snippet' do
it_behaves_like 'git repository routes' do
let(:path) { '/gitlab-org/gitlab-test/snippets/123.git' }
end
+
+ it_behaves_like 'git repository routes with fallback' do
+ let(:path) { '/gitlab-org/gitlab-test/snippets/123.git' }
+ end
end
end
end
diff --git a/spec/routing/project_routing_spec.rb b/spec/routing/project_routing_spec.rb
index 29e5c1b4bae..f7ed8d7d5dc 100644
--- a/spec/routing/project_routing_spec.rb
+++ b/spec/routing/project_routing_spec.rb
@@ -876,4 +876,73 @@ RSpec.describe 'project routing' do
)
end
end
+
+ context 'with a non-existent project' do
+ it 'routes to 404 with get request' do
+ expect(get: "/gitlab/not_exist").to route_to(
+ 'application#route_not_found',
+ unmatched_route: 'gitlab/not_exist'
+ )
+ end
+
+ it 'routes to 404 with delete request' do
+ expect(delete: "/gitlab/not_exist").to route_to(
+ 'application#route_not_found',
+ namespace_id: 'gitlab',
+ project_id: 'not_exist'
+ )
+ end
+
+ it 'routes to 404 with post request' do
+ expect(post: "/gitlab/not_exist").to route_to(
+ 'application#route_not_found',
+ namespace_id: 'gitlab',
+ project_id: 'not_exist'
+ )
+ end
+
+ it 'routes to 404 with put request' do
+ expect(put: "/gitlab/not_exist").to route_to(
+ 'application#route_not_found',
+ namespace_id: 'gitlab',
+ project_id: 'not_exist'
+ )
+ end
+
+ context 'with route to some action' do
+ it 'routes to 404 with get request to' do
+ expect(get: "/gitlab/not_exist/some_action").to route_to(
+ 'application#route_not_found',
+ unmatched_route: 'gitlab/not_exist/some_action'
+ )
+ end
+
+ it 'routes to 404 with delete request' do
+ expect(delete: "/gitlab/not_exist/some_action").to route_to(
+ 'application#route_not_found',
+ namespace_id: 'gitlab',
+ project_id: 'not_exist',
+ all: 'some_action'
+ )
+ end
+
+ it 'routes to 404 with post request' do
+ expect(post: "/gitlab/not_exist/some_action").to route_to(
+ 'application#route_not_found',
+ namespace_id: 'gitlab',
+ project_id: 'not_exist',
+ all: 'some_action'
+ )
+ end
+
+ it 'routes to 404 with put request' do
+ expect(put: "/gitlab/not_exist/some_action").to route_to(
+ 'application#route_not_found',
+ namespace_id: 'gitlab',
+ project_id: 'not_exist',
+ all: 'some_action'
+ )
+ end
+ end
+ end
end
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index b986777b361..b1b106f58ff 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -284,6 +284,8 @@ RSpec.configure do |config|
current_user_mode.send(:user)&.admin?
end
end
+
+ allow(Gitlab::CurrentSettings).to receive(:current_application_settings?).and_return(false)
end
config.around(:example, :quarantine) do |example|
diff --git a/spec/support/helpers/stub_configuration.rb b/spec/support/helpers/stub_configuration.rb
index 3b733a2e57a..9851a3de9e9 100644
--- a/spec/support/helpers/stub_configuration.rb
+++ b/spec/support/helpers/stub_configuration.rb
@@ -121,6 +121,12 @@ module StubConfiguration
allow(::Gitlab.config.packages).to receive_messages(to_settings(messages))
end
+ def stub_maintenance_mode_setting(value)
+ allow(Gitlab::CurrentSettings).to receive(:current_application_settings?).and_return(true)
+
+ stub_application_setting(maintenance_mode: value)
+ end
+
private
# Modifies stubbed messages to also stub possible predicate versions
diff --git a/spec/support/helpers/stub_object_storage.rb b/spec/support/helpers/stub_object_storage.rb
index dc54a21d0fa..0d0ac171baa 100644
--- a/spec/support/helpers/stub_object_storage.rb
+++ b/spec/support/helpers/stub_object_storage.rb
@@ -85,6 +85,13 @@ module StubObjectStorage
**params)
end
+ def stub_composer_cache_object_storage(**params)
+ stub_object_storage_uploader(config: Gitlab.config.packages.object_store,
+ uploader: ::Packages::Composer::CacheUploader,
+ remote_directory: 'packages',
+ **params)
+ end
+
def stub_uploads_object_storage(uploader = described_class, **params)
stub_object_storage_uploader(config: Gitlab.config.uploads.object_store,
uploader: uploader,
diff --git a/spec/support/matchers/route_to_route_not_found_matcher.rb b/spec/support/matchers/route_to_route_not_found_matcher.rb
new file mode 100644
index 00000000000..4105f0f9191
--- /dev/null
+++ b/spec/support/matchers/route_to_route_not_found_matcher.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+RSpec::Matchers.define :route_to_route_not_found do
+ match do |actual|
+ expect(actual).to route_to(controller: 'application', action: 'route_not_found')
+ rescue RSpec::Expectations::ExpectationNotMetError => e
+ # `route_to` matcher requires providing all params for exact match. As we use it in shared examples and we provide different paths,
+ # this matcher checks if provided route matches controller and action, without checking params.
+ expect(e.message).to include("-{\"controller\"=>\"application\", \"action\"=>\"route_not_found\"}\n+{\"controller\"=>\"application\", \"action\"=>\"route_not_found\",")
+ end
+
+ failure_message do |_|
+ "expected #{actual} to route to route_not_found"
+ end
+end
diff --git a/spec/support/shared_examples/routing/git_http_routing_shared_examples.rb b/spec/support/shared_examples/routing/git_http_routing_shared_examples.rb
index b0e1e942d81..f924da37f4f 100644
--- a/spec/support/shared_examples/routing/git_http_routing_shared_examples.rb
+++ b/spec/support/shared_examples/routing/git_http_routing_shared_examples.rb
@@ -16,10 +16,6 @@ RSpec.shared_examples 'git repository routes' do
expect(get("#{container_path}/info/refs?service=git-upload-pack")).to redirect_to("#{container_path}.git/info/refs?service=git-upload-pack")
expect(get("#{container_path}/info/refs?service=git-receive-pack")).to redirect_to("#{container_path}.git/info/refs?service=git-receive-pack")
end
-
- it 'does not redirect other requests' do
- expect(post("#{container_path}/git-upload-pack")).not_to be_routable
- end
end
it 'routes LFS endpoints' do
@@ -35,6 +31,56 @@ RSpec.shared_examples 'git repository routes' do
expect(get("#{path}/gitlab-lfs/objects/#{oid}")).to route_to('repositories/lfs_storage#download', oid: oid, **params)
expect(put("#{path}/gitlab-lfs/objects/#{oid}/456/authorize")).to route_to('repositories/lfs_storage#upload_authorize', oid: oid, size: '456', **params)
expect(put("#{path}/gitlab-lfs/objects/#{oid}/456")).to route_to('repositories/lfs_storage#upload_finalize', oid: oid, size: '456', **params)
+ end
+end
+
+RSpec.shared_examples 'git repository routes without fallback' do
+ let(:container_path) { path.delete_suffix('.git') }
+
+ context 'requests without .git format' do
+ it 'does not redirect other requests' do
+ expect(post("#{container_path}/git-upload-pack")).not_to be_routable
+ end
+ end
+
+ it 'routes LFS endpoints for unmatched routes' do
+ oid = generate(:oid)
+
+ expect(put("#{path}/gitlab-lfs/objects/foo")).not_to be_routable
+ expect(put("#{path}/gitlab-lfs/objects/#{oid}/foo")).not_to be_routable
+ expect(put("#{path}/gitlab-lfs/objects/#{oid}/foo/authorize")).not_to be_routable
+ end
+end
+
+RSpec.shared_examples 'git repository routes with fallback' do
+ let(:container_path) { path.delete_suffix('.git') }
+
+ context 'requests without .git format' do
+ it 'does not redirect other requests' do
+ expect(post("#{container_path}/git-upload-pack")).to route_to_route_not_found
+ end
+ end
+
+ it 'routes LFS endpoints' do
+ oid = generate(:oid)
+
+ expect(put("#{path}/gitlab-lfs/objects/foo")).to route_to_route_not_found
+ expect(put("#{path}/gitlab-lfs/objects/#{oid}/foo")).to route_to_route_not_found
+ expect(put("#{path}/gitlab-lfs/objects/#{oid}/foo/authorize")).to route_to_route_not_found
+ end
+end
+
+RSpec.shared_examples 'git repository routes with fallback for git-upload-pack' do
+ let(:container_path) { path.delete_suffix('.git') }
+
+ context 'requests without .git format' do
+ it 'does not redirect other requests' do
+ expect(post("#{container_path}/git-upload-pack")).to route_to_route_not_found
+ end
+ end
+
+ it 'routes LFS endpoints for unmatched routes' do
+ oid = generate(:oid)
expect(put("#{path}/gitlab-lfs/objects/foo")).not_to be_routable
expect(put("#{path}/gitlab-lfs/objects/#{oid}/foo")).not_to be_routable
diff --git a/spec/uploaders/packages/composer/cache_uploader_spec.rb b/spec/uploaders/packages/composer/cache_uploader_spec.rb
new file mode 100644
index 00000000000..a4ba4cc2a1e
--- /dev/null
+++ b/spec/uploaders/packages/composer/cache_uploader_spec.rb
@@ -0,0 +1,45 @@
+# frozen_string_literal: true
+require 'spec_helper'
+
+RSpec.describe Packages::Composer::CacheUploader do
+ let(:cache_file) { create(:composer_cache_file) } # rubocop:disable Rails/SaveBang
+ let(:uploader) { described_class.new(cache_file, :file) }
+ let(:path) { Gitlab.config.packages.storage_path }
+
+ subject { uploader }
+
+ it_behaves_like "builds correct paths",
+ store_dir: %r[^\h{2}/\h{2}/\h{64}/packages/composer_cache/\d+$],
+ cache_dir: %r[/packages/tmp/cache],
+ work_dir: %r[/packages/tmp/work]
+
+ context 'object store is remote' do
+ before do
+ stub_composer_cache_object_storage
+ end
+
+ include_context 'with storage', described_class::Store::REMOTE
+
+ it_behaves_like "builds correct paths",
+ store_dir: %r[^\h{2}/\h{2}/\h{64}/packages/composer_cache/\d+$]
+ end
+
+ describe 'remote file' do
+ let(:cache_file) { create(:composer_cache_file, :object_storage) }
+
+ context 'with object storage enabled' do
+ before do
+ stub_composer_cache_object_storage
+ end
+
+ it 'can store file remotely' do
+ allow(ObjectStorage::BackgroundMoveWorker).to receive(:perform_async)
+
+ cache_file
+
+ expect(cache_file.file_store).to eq(described_class::Store::REMOTE)
+ expect(cache_file.file.path).not_to be_blank
+ end
+ end
+ end
+end