diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2023-07-27 18:10:15 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2023-07-27 18:10:15 +0300 |
commit | 9979d2afd66e12d938ea55372dcf2d8105b5eaca (patch) | |
tree | 88df8f6a2f2ffba2fa1318dee83f58d6fe76d40d /spec | |
parent | fdf32113c3924f7faec91101282fc28ec42fc869 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
23 files changed, 582 insertions, 87 deletions
diff --git a/spec/features/admin/admin_users_impersonation_tokens_spec.rb b/spec/features/admin/admin_users_impersonation_tokens_spec.rb index 0350c8ab066..543dc2cc2a6 100644 --- a/spec/features/admin/admin_users_impersonation_tokens_spec.rb +++ b/spec/features/admin/admin_users_impersonation_tokens_spec.rb @@ -19,6 +19,7 @@ RSpec.describe 'Admin > Users > Impersonation Tokens', :js, feature_category: :s name = 'Hello World' visit admin_user_impersonation_tokens_path(user_id: user.username) + click_button 'Add new token' fill_in "Token name", with: name # Set date to 1st of next month diff --git a/spec/features/profiles/personal_access_tokens_spec.rb b/spec/features/profiles/personal_access_tokens_spec.rb index 65fe1330be2..094855393be 100644 --- a/spec/features/profiles/personal_access_tokens_spec.rb +++ b/spec/features/profiles/personal_access_tokens_spec.rb @@ -18,6 +18,8 @@ RSpec.describe 'Profile > Personal Access Tokens', :js, feature_category: :user_ name = 'My PAT' visit profile_personal_access_tokens_path + + click_button 'Add new token' fill_in "Token name", with: name # Set date to 1st of next month @@ -43,6 +45,8 @@ RSpec.describe 'Profile > Personal Access Tokens', :js, feature_category: :user_ it "displays an error message" do number_tokens_before = PersonalAccessToken.count visit profile_personal_access_tokens_path + + click_button 'Add new token' fill_in "Token name", with: 'My PAT' click_on "Create personal access token" @@ -145,6 +149,7 @@ RSpec.describe 'Profile > Personal Access Tokens', :js, feature_category: :user_ visit profile_personal_access_tokens_path({ name: name, scopes: scopes }) + click_button 'Add new token' expect(page).to have_field("Token name", with: name) expect(find("#personal_access_token_scopes_api")).to be_checked expect(find("#personal_access_token_scopes_read_user")).to be_checked diff --git a/spec/features/projects/settings/access_tokens_spec.rb b/spec/features/projects/settings/access_tokens_spec.rb index 210815f341c..9025bd9052e 100644 --- a/spec/features/projects/settings/access_tokens_spec.rb +++ b/spec/features/projects/settings/access_tokens_spec.rb @@ -49,6 +49,7 @@ RSpec.describe 'Project > Settings > Access Tokens', :js, feature_category: :use it 'shows Owner option' do visit resource_settings_access_tokens_path + click_button 'Add new token' expect(role_dropdown_options).to include('Owner') end end @@ -63,6 +64,7 @@ RSpec.describe 'Project > Settings > Access Tokens', :js, feature_category: :use it 'does not show Owner option for a maintainer' do visit resource_settings_access_tokens_path + click_button 'Add new token' expect(role_dropdown_options).not_to include('Owner') end end @@ -81,6 +83,7 @@ RSpec.describe 'Project > Settings > Access Tokens', :js, feature_category: :use it 'shows access token creation form and text' do visit project_settings_access_tokens_path(personal_project) + click_button 'Add new token' expect(page).to have_selector('#js-new-access-token-form') end end diff --git a/spec/features/projects/settings/user_searches_in_settings_spec.rb b/spec/features/projects/settings/user_searches_in_settings_spec.rb index 978b678c334..1ca4b761788 100644 --- a/spec/features/projects/settings/user_searches_in_settings_spec.rb +++ b/spec/features/projects/settings/user_searches_in_settings_spec.rb @@ -31,7 +31,7 @@ RSpec.describe 'User searches project settings', :js, feature_category: :groups_ visit project_settings_access_tokens_path(project) end - it_behaves_like 'can highlight results', 'Expiration date' + it_behaves_like 'can highlight results', 'Token name' end context 'in Repository page' do diff --git a/spec/frontend/access_tokens/components/access_token_table_app_spec.js b/spec/frontend/access_tokens/components/access_token_table_app_spec.js index 2fa14810578..5236f38dc35 100644 --- a/spec/frontend/access_tokens/components/access_token_table_app_spec.js +++ b/spec/frontend/access_tokens/components/access_token_table_app_spec.js @@ -91,24 +91,6 @@ describe('~/access_tokens/components/access_token_table_app', () => { expect(cells.at(0).text()).toBe(noTokensMessage); }); - it('should show a title indicating the amount of tokens', () => { - createComponent(); - - expect(wrapper.find('h5').text()).toBe( - sprintf(__('Active %{accessTokenTypePlural} (%{totalAccessTokens})'), { - accessTokenTypePlural, - totalAccessTokens: defaultActiveAccessTokens.length, - }), - ); - }); - - it('should render information section', () => { - const info = 'This is my information'; - createComponent({ information: info }); - - expect(wrapper.findByTestId('information-section').text()).toBe(info); - }); - describe('table headers', () => { it('should include `Action` column', () => { createComponent(); diff --git a/spec/frontend/access_tokens/components/new_access_token_app_spec.js b/spec/frontend/access_tokens/components/new_access_token_app_spec.js index 70f77932ccf..d51ac638f0e 100644 --- a/spec/frontend/access_tokens/components/new_access_token_app_spec.js +++ b/spec/frontend/access_tokens/components/new_access_token_app_spec.js @@ -23,6 +23,8 @@ describe('~/access_tokens/components/new_access_token_app', () => { }; const findButtonEl = () => document.querySelector('[type=submit]'); + const findGlAlertError = () => wrapper.findByTestId('error-message'); + const findGlAlertSuccess = () => wrapper.findByTestId('success-message'); const triggerSuccess = async (newToken = 'new token') => { wrapper @@ -57,7 +59,7 @@ describe('~/access_tokens/components/new_access_token_app', () => { it('should render nothing', () => { expect(wrapper.findComponent(InputCopyToggleVisibility).exists()).toBe(false); - expect(wrapper.findComponent(GlAlert).exists()).toBe(false); + expect(findGlAlertError().exists()).toBe(false); }); describe('on success', () => { @@ -65,7 +67,8 @@ describe('~/access_tokens/components/new_access_token_app', () => { const newToken = '12345'; await triggerSuccess(newToken); - expect(wrapper.findComponent(GlAlert).exists()).toBe(false); + expect(findGlAlertError().exists()).toBe(false); + expect(findGlAlertSuccess().exists()).toBe(true); const InputCopyToggleVisibilityComponent = wrapper.findComponent(InputCopyToggleVisibility); expect(InputCopyToggleVisibilityComponent.props('value')).toBe(newToken); @@ -82,7 +85,7 @@ describe('~/access_tokens/components/new_access_token_app', () => { const newToken = '12345'; await triggerSuccess(newToken); - expect(wrapper.findComponent(GlAlert).exists()).toBe(false); + expect(findGlAlertError().exists()).toBe(false); const inputAttributes = wrapper .findByLabelText(sprintf(__('Your new %{accessTokenType}'), { accessTokenType })) @@ -135,7 +138,7 @@ describe('~/access_tokens/components/new_access_token_app', () => { expect(wrapper.findComponent(InputCopyToggleVisibility).exists()).toBe(false); - let GlAlertComponent = wrapper.findComponent(GlAlert); + let GlAlertComponent = findGlAlertError(); expect(GlAlertComponent.props('title')).toBe(__('The form contains the following errors:')); expect(GlAlertComponent.props('variant')).toBe('danger'); let itemEls = wrapper.findAll('li'); diff --git a/spec/frontend/access_tokens/index_spec.js b/spec/frontend/access_tokens/index_spec.js index c1158e0d124..7d4d73b00b2 100644 --- a/spec/frontend/access_tokens/index_spec.js +++ b/spec/frontend/access_tokens/index_spec.js @@ -50,7 +50,6 @@ describe('access tokens', () => { initialActiveAccessTokens, // Default values - information: undefined, noActiveTokensMessage: sprintf(__('This user has no active %{accessTokenTypePlural}.'), { accessTokenTypePlural, }), @@ -59,14 +58,12 @@ describe('access tokens', () => { }); it('mounts the component and provides all values', () => { - const information = 'Additional information'; const noActiveTokensMessage = 'This group has no active access tokens.'; setHTMLFixture( `<div id="js-access-token-table-app" data-access-token-type="${accessTokenType}" data-access-token-type-plural="${accessTokenTypePlural}" data-initial-active-access-tokens=${JSON.stringify(initialActiveAccessTokens)} - data-information="${information}" data-no-active-tokens-message="${noActiveTokensMessage}" data-show-role > @@ -82,7 +79,6 @@ describe('access tokens', () => { accessTokenType, accessTokenTypePlural, initialActiveAccessTokens, - information, noActiveTokensMessage, showRole: true, }); diff --git a/spec/frontend/vue_merge_request_widget/components/widget/__snapshots__/dynamic_content_spec.js.snap b/spec/frontend/vue_merge_request_widget/components/widget/__snapshots__/dynamic_content_spec.js.snap index bb520cd7a47..9c5f9db9762 100644 --- a/spec/frontend/vue_merge_request_widget/components/widget/__snapshots__/dynamic_content_spec.js.snap +++ b/spec/frontend/vue_merge_request_widget/components/widget/__snapshots__/dynamic_content_spec.js.snap @@ -18,10 +18,12 @@ exports[`~/vue_merge_request_widget/components/widget/dynamic_content.vue render <status-icon-stub level=\\"2\\" name=\\"MyWidget\\" iconname=\\"success\\"></status-icon-stub> <div class=\\"gl-w-full gl-display-flex\\"> <div class=\\"gl-display-flex gl-flex-grow-1\\"> - <div class=\\"gl-display-flex gl-flex-grow-1 gl-flex-direction-column\\"> - <p class=\\"gl-mb-0 gl-mr-1\\">Main text for the row</p> - <gl-link-stub href=\\"https://gitlab.com\\">Optional link to display after text</gl-link-stub> - <!----> + <div class=\\"gl-display-flex gl-flex-grow-1 gl-align-items-baseline\\"> + <div> + <p class=\\"gl-mb-0 gl-mr-1\\">Main text for the row</p> + <gl-link-stub href=\\"https://gitlab.com\\">Optional link to display after text</gl-link-stub> + <!----> + </div> <gl-badge-stub size=\\"md\\" variant=\\"info\\" iconsize=\\"md\\"> Badge is optional. Text to be displayed inside badge </gl-badge-stub> @@ -44,10 +46,12 @@ exports[`~/vue_merge_request_widget/components/widget/dynamic_content.vue render <!----> <div class=\\"gl-w-full gl-display-flex\\"> <div class=\\"gl-display-flex gl-flex-grow-1\\"> - <div class=\\"gl-display-flex gl-flex-grow-1 gl-flex-direction-column\\"> - <p class=\\"gl-mb-0 gl-mr-1\\">This is recursive. It will be listed in level 3.</p> - <!----> - <!----> + <div class=\\"gl-display-flex gl-flex-grow-1 gl-align-items-baseline\\"> + <div> + <p class=\\"gl-mb-0 gl-mr-1\\">This is recursive. It will be listed in level 3.</p> + <!----> + <!----> + </div> <!----> </div> <actions-stub widget=\\"MyWidget\\" tertiarybuttons=\\"\\" class=\\"gl-ml-auto gl-pl-3\\"></actions-stub> diff --git a/spec/graphql/types/custom_emoji_type_spec.rb b/spec/graphql/types/custom_emoji_type_spec.rb index 7f3c99e4b63..17697321602 100644 --- a/spec/graphql/types/custom_emoji_type_spec.rb +++ b/spec/graphql/types/custom_emoji_type_spec.rb @@ -3,9 +3,20 @@ require 'spec_helper' RSpec.describe GitlabSchema.types['CustomEmoji'] do + expected_fields = %w[ + id + name + url + external + created_at + user_permissions + ] + specify { expect(described_class.graphql_name).to eq('CustomEmoji') } specify { expect(described_class).to require_graphql_authorizations(:read_custom_emoji) } - specify { expect(described_class).to have_graphql_fields(:id, :name, :url, :external) } + specify { expect(described_class).to have_graphql_fields(*expected_fields) } + + specify { expect(described_class).to expose_permissions_using(Types::PermissionTypes::CustomEmoji) } end diff --git a/spec/lib/api/validations/validators/git_sha_spec.rb b/spec/lib/api/validations/validators/git_sha_spec.rb index ae6be52a4c7..2ae3fca7a6e 100644 --- a/spec/lib/api/validations/validators/git_sha_spec.rb +++ b/spec/lib/api/validations/validators/git_sha_spec.rb @@ -8,6 +8,7 @@ RSpec.describe API::Validations::Validators::GitSha do let(:sha) { RepoHelpers.sample_commit.id } let(:short_sha) { sha[0, Gitlab::Git::Commit::MIN_SHA_LENGTH] } let(:too_short_sha) { sha[0, Gitlab::Git::Commit::MIN_SHA_LENGTH - 1] } + let(:too_long_sha) { "a" * (Gitlab::Git::Commit::MAX_SHA_LENGTH + 1) } subject do described_class.new(['test'], {}, false, scope.new) @@ -29,7 +30,7 @@ RSpec.describe API::Validations::Validators::GitSha do context 'invalid sha' do it 'raises a validation error' do - expect_validation_error('test' => "#{sha}2") # Sha length > 40 + expect_validation_error('test' => too_long_sha) # too long SHA expect_validation_error('test' => 'somestring') expect_validation_error('test' => too_short_sha) # sha length < MIN_SHA_LENGTH (7) end diff --git a/spec/lib/gitlab/background_migration/backfill_default_branch_protection_namespace_setting_spec.rb b/spec/lib/gitlab/background_migration/backfill_default_branch_protection_namespace_setting_spec.rb new file mode 100644 index 00000000000..62c9e240b7a --- /dev/null +++ b/spec/lib/gitlab/background_migration/backfill_default_branch_protection_namespace_setting_spec.rb @@ -0,0 +1,65 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Gitlab::BackgroundMigration::BackfillDefaultBranchProtectionNamespaceSetting, + schema: 20230724071541, + feature_category: :database do + let(:namespaces_table) { table(:namespaces) } + let(:namespace_settings_table) { table(:namespace_settings) } + + subject(:perform_migration) do + described_class.new( + start_id: 1, + end_id: 30, + batch_table: :namespace_settings, + batch_column: :namespace_id, + sub_batch_size: 2, + pause_ms: 0, + connection: ActiveRecord::Base.connection + ).perform + end + + before do + namespaces_table.create!(id: 1, name: 'group_namespace', path: 'path-1', type: 'Group', + default_branch_protection: 0) + namespaces_table.create!(id: 2, name: 'user_namespace', path: 'path-2', type: 'User', default_branch_protection: 1) + namespaces_table.create!(id: 3, name: 'user_three_namespace', path: 'path-3', type: 'User', + default_branch_protection: 2) + namespaces_table.create!(id: 4, name: 'group_four_namespace', path: 'path-4', type: 'Group', + default_branch_protection: 3) + namespaces_table.create!(id: 5, name: 'group_five_namespace', path: 'path-5', type: 'Group', + default_branch_protection: 4) + + namespace_settings_table.create!(namespace_id: 1, default_branch_protection_defaults: {}) + namespace_settings_table.create!(namespace_id: 2, default_branch_protection_defaults: {}) + namespace_settings_table.create!(namespace_id: 3, default_branch_protection_defaults: {}) + namespace_settings_table.create!(namespace_id: 4, default_branch_protection_defaults: {}) + namespace_settings_table.create!(namespace_id: 5, default_branch_protection_defaults: {}) + end + + it 'updates default_branch_protection_defaults to a correct value', :aggregate_failures do + expect(ActiveRecord::QueryRecorder.new { perform_migration }.count).to eq(16) + + expect(migrated_attribute(1)).to eq({ "allow_force_push" => true, + "allowed_to_merge" => [{ "access_level" => 30 }], + "allowed_to_push" => [{ "access_level" => 30 }] }) + expect(migrated_attribute(2)).to eq({ "allow_force_push" => false, + "allowed_to_merge" => [{ "access_level" => 30 }], + "allowed_to_push" => [{ "access_level" => 30 }] }) + expect(migrated_attribute(3)).to eq({ "allow_force_push" => false, + "allowed_to_merge" => [{ "access_level" => 40 }], + "allowed_to_push" => [{ "access_level" => 40 }] }) + expect(migrated_attribute(4)).to eq({ "allow_force_push" => true, + "allowed_to_merge" => [{ "access_level" => 30 }], + "allowed_to_push" => [{ "access_level" => 40 }] }) + expect(migrated_attribute(5)).to eq({ "allow_force_push" => true, + "allowed_to_merge" => [{ "access_level" => 30 }], + "allowed_to_push" => [{ "access_level" => 40 }], + "developer_can_initial_push" => true }) + end + + def migrated_attribute(namespace_id) + namespace_settings_table.find(namespace_id).default_branch_protection_defaults + end +end diff --git a/spec/lib/gitlab/checks/branch_check_spec.rb b/spec/lib/gitlab/checks/branch_check_spec.rb index 7ce267c535f..9f6d4c7fd36 100644 --- a/spec/lib/gitlab/checks/branch_check_spec.rb +++ b/spec/lib/gitlab/checks/branch_check_spec.rb @@ -32,6 +32,18 @@ RSpec.describe Gitlab::Checks::BranchCheck, feature_category: :source_code_manag expect { subject.validate! }.to raise_error(Gitlab::GitAccess::ForbiddenError, "You cannot create a branch with a 40-character hexadecimal branch name.") end + it "prohibits 64-character hexadecimal branch names" do + allow(subject).to receive(:branch_name).and_return("09b9fd3ea68e9b95a51b693a29568c898e27d1476bbd83c825664f18467fc175") + + expect { subject.validate! }.to raise_error(Gitlab::GitAccess::ForbiddenError, "You cannot create a branch with a 40-character hexadecimal branch name.") + end + + it "prohibits 64-character hexadecimal branch names as the start of a path" do + allow(subject).to receive(:branch_name).and_return("09b9fd3ea68e9b95a51b693a29568c898e27d1476bbd83c825664f18467fc175/test") + + expect { subject.validate! }.to raise_error(Gitlab::GitAccess::ForbiddenError, "You cannot create a branch with a 40-character hexadecimal branch name.") + end + it "doesn't prohibit a nested hexadecimal in a branch name" do allow(subject).to receive(:branch_name).and_return("267208abfe40e546f5e847444276f7d43a39503e-fix") diff --git a/spec/lib/gitlab/content_security_policy/config_loader_spec.rb b/spec/lib/gitlab/content_security_policy/config_loader_spec.rb index b40829d72a0..44887a86aff 100644 --- a/spec/lib/gitlab/content_security_policy/config_loader_spec.rb +++ b/spec/lib/gitlab/content_security_policy/config_loader_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Gitlab::ContentSecurityPolicy::ConfigLoader do +RSpec.describe Gitlab::ContentSecurityPolicy::ConfigLoader, feature_category: :shared do let(:policy) { ActionDispatch::ContentSecurityPolicy.new } let(:csp_config) do { @@ -29,7 +29,7 @@ RSpec.describe Gitlab::ContentSecurityPolicy::ConfigLoader do context 'when in production' do before do - allow(Rails).to receive(:env).and_return(ActiveSupport::StringInquirer.new('production')) + stub_rails_env('production') end it 'is disabled' do @@ -40,6 +40,16 @@ RSpec.describe Gitlab::ContentSecurityPolicy::ConfigLoader do describe '.default_directives' do let(:directives) { described_class.default_directives } + let(:child_src) { directives['child_src'] } + let(:connect_src) { directives['connect_src'] } + let(:font_src) { directives['font_src'] } + let(:frame_src) { directives['frame_src'] } + let(:img_src) { directives['img_src'] } + let(:media_src) { directives['media_src'] } + let(:report_uri) { directives['report_uri'] } + let(:script_src) { directives['script_src'] } + let(:style_src) { directives['style_src'] } + let(:worker_src) { directives['worker_src'] } it 'returns default directives' do directive_names = (described_class::DIRECTIVES - ['report_uri']) @@ -49,68 +59,167 @@ RSpec.describe Gitlab::ContentSecurityPolicy::ConfigLoader do end expect(directives.has_key?('report_uri')).to be_truthy - expect(directives['report_uri']).to be_nil - expect(directives['child_src']).to eq("#{directives['frame_src']} #{directives['worker_src']}") + expect(report_uri).to be_nil + expect(child_src).to eq("#{frame_src} #{worker_src}") end describe 'the images-src directive' do it 'can be loaded from anywhere' do - expect(directives['img_src']).to include('http: https:') + expect(img_src).to include('http: https:') end end describe 'the media-src directive' do it 'can be loaded from anywhere' do - expect(directives['media_src']).to include('http: https:') + expect(media_src).to include('http: https:') end end - context 'adds all websocket origins to support Safari' do + describe 'Webpack dev server websocket connections' do + let(:webpack_dev_server_host) { 'webpack-dev-server.com' } + let(:webpack_dev_server_port) { '9999' } + let(:webpack_dev_server_https) { true } + + before do + stub_config_setting( + webpack: { dev_server: { + host: webpack_dev_server_host, + webpack_dev_server_port: webpack_dev_server_port, + https: webpack_dev_server_https + } } + ) + end + + context 'when in production' do + before do + stub_rails_env('production') + end + + context 'with secure domain' do + it 'does not include webpack dev server in connect-src' do + expect(connect_src).not_to include(webpack_dev_server_host) + expect(connect_src).not_to include(webpack_dev_server_port) + end + end + + context 'with insecure domain' do + let(:webpack_dev_server_https) { false } + + it 'does not include webpack dev server in connect-src' do + expect(connect_src).not_to include(webpack_dev_server_host) + expect(connect_src).not_to include(webpack_dev_server_port) + end + end + end + + context 'when in development' do + before do + stub_rails_env('development') + end + + context 'with secure domain' do + before do + stub_config_setting(host: webpack_dev_server_host, port: webpack_dev_server_port, https: true) + end + + it 'includes secure websocket url for webpack dev server in connect-src' do + expect(connect_src).to include("wss://#{webpack_dev_server_host}:#{webpack_dev_server_port}") + expect(connect_src).not_to include("ws://#{webpack_dev_server_host}:#{webpack_dev_server_port}") + end + end + + context 'with insecure domain' do + before do + stub_config_setting(host: webpack_dev_server_host, port: webpack_dev_server_port, https: false) + end + + it 'includes insecure websocket url for webpack dev server in connect-src' do + expect(connect_src).not_to include("wss://#{webpack_dev_server_host}:#{webpack_dev_server_port}") + expect(connect_src).to include("ws://#{webpack_dev_server_host}:#{webpack_dev_server_port}") + end + end + end + end + + describe 'Websocket connections' do it 'with insecure domain' do stub_config_setting(host: 'example.com', https: false) - expect(directives['connect_src']).to eq("'self' ws://example.com") + expect(connect_src).to eq("'self' ws://example.com") end it 'with secure domain' do stub_config_setting(host: 'example.com', https: true) - expect(directives['connect_src']).to eq("'self' wss://example.com") + expect(connect_src).to eq("'self' wss://example.com") end it 'with custom port' do stub_config_setting(host: 'example.com', port: '1234') - expect(directives['connect_src']).to eq("'self' ws://example.com:1234") + expect(connect_src).to eq("'self' ws://example.com:1234") end it 'with custom port and secure domain' do stub_config_setting(host: 'example.com', https: true, port: '1234') - expect(directives['connect_src']).to eq("'self' wss://example.com:1234") + expect(connect_src).to eq("'self' wss://example.com:1234") + end + + it 'when port is included in HTTP_PORTS' do + described_class::HTTP_PORTS.each do |port| + stub_config_setting(host: 'example.com', https: true, port: port) + expect(connect_src).to eq("'self' wss://example.com") + end end end - context 'when CDN host is defined' do + describe 'CDN connections' do before do - stub_config_setting(cdn_host: 'https://cdn.example.com') + allow(described_class).to receive(:allow_letter_opener) + allow(described_class).to receive(:allow_zuora) + allow(described_class).to receive(:allow_framed_gitlab_paths) + allow(described_class).to receive(:allow_customersdot) + allow(described_class).to receive(:csp_level_3_backport) + end + + context 'when CDN host is defined' do + let(:cdn_host) { 'https://cdn.example.com' } + + before do + stub_config_setting(cdn_host: cdn_host) + end + + it 'adds CDN host to CSP' do + expect(script_src).to include(cdn_host) + expect(style_src).to include(cdn_host) + expect(font_src).to include(cdn_host) + expect(worker_src).to include(cdn_host) + expect(frame_src).to include(cdn_host) + end end - it 'adds CDN host to CSP' do - expect(directives['script_src']).to eq(::Gitlab::ContentSecurityPolicy::Directives.script_src + " https://cdn.example.com") - expect(directives['style_src']).to eq(::Gitlab::ContentSecurityPolicy::Directives.style_src + " https://cdn.example.com") - expect(directives['font_src']).to eq("'self' https://cdn.example.com") - expect(directives['worker_src']).to eq('http://localhost/assets/ blob: data: https://cdn.example.com') - expect(directives['frame_src']).to eq(::Gitlab::ContentSecurityPolicy::Directives.frame_src + " https://cdn.example.com http://localhost/admin/ http://localhost/assets/ http://localhost/-/speedscope/index.html http://localhost/-/sandbox/") + context 'when CDN host is undefined' do + before do + stub_config_setting(cdn_host: nil) + end + + it 'does not include CDN host in CSP' do + expect(script_src).to eq(::Gitlab::ContentSecurityPolicy::Directives.script_src) + expect(style_src).to eq(::Gitlab::ContentSecurityPolicy::Directives.style_src) + expect(font_src).to eq("'self'") + expect(worker_src).to eq("http://localhost/assets/ blob: data:") + expect(frame_src).to eq(::Gitlab::ContentSecurityPolicy::Directives.frame_src) + end end end describe 'Zuora directives' do context 'when on SaaS', :saas do it 'adds Zuora host to CSP' do - expect(directives['frame_src']).to include('https://*.zuora.com/apps/PublicHostedPageLite.do') + expect(frame_src).to include('https://*.zuora.com/apps/PublicHostedPageLite.do') end end context 'when is not Gitlab.com?' do it 'does not add Zuora host to CSP' do - expect(directives['frame_src']).not_to include('https://*.zuora.com/apps/PublicHostedPageLite.do') + expect(frame_src).not_to include('https://*.zuora.com/apps/PublicHostedPageLite.do') end end end @@ -131,7 +240,7 @@ RSpec.describe Gitlab::ContentSecurityPolicy::ConfigLoader do end it 'adds legacy sentry path to CSP' do - expect(directives['connect_src']).to eq("'self' ws://gitlab.example.com dummy://legacy-sentry.example.com") + expect(connect_src).to eq("'self' ws://gitlab.example.com dummy://legacy-sentry.example.com") end end @@ -143,7 +252,7 @@ RSpec.describe Gitlab::ContentSecurityPolicy::ConfigLoader do end it 'adds new sentry path to CSP' do - expect(directives['connect_src']).to eq("'self' ws://gitlab.example.com dummy://sentry.example.com") + expect(connect_src).to eq("'self' ws://gitlab.example.com dummy://sentry.example.com") end end @@ -159,11 +268,22 @@ RSpec.describe Gitlab::ContentSecurityPolicy::ConfigLoader do end it 'config is backwards compatible, does not add sentry path to CSP' do - expect(directives['connect_src']).to eq("'self' ws://gitlab.example.com") + expect(connect_src).to eq("'self' ws://gitlab.example.com") end end context 'when legacy sentry and sentry are both configured' do + let(:connect_src_expectation) do + # rubocop:disable Lint/PercentStringArray + %w[ + 'self' + ws://gitlab.example.com + dummy://legacy-sentry.example.com + dummy://sentry.example.com + ].join(' ') + # rubocop:enable Lint/PercentStringArray + end + before do allow(Gitlab.config.sentry).to receive(:enabled).and_return(true) allow(Gitlab.config.sentry).to receive(:clientside_dsn).and_return(legacy_dsn) @@ -173,24 +293,57 @@ RSpec.describe Gitlab::ContentSecurityPolicy::ConfigLoader do end it 'adds both sentry paths to CSP' do - expect(directives['connect_src']).to eq("'self' ws://gitlab.example.com dummy://legacy-sentry.example.com dummy://sentry.example.com") + expect(connect_src).to eq(connect_src_expectation) end end end - context 'when CUSTOMER_PORTAL_URL is set' do - let(:customer_portal_url) { 'https://customers.example.com' } + describe 'Customer portal frames' do + context 'when CUSTOMER_PORTAL_URL is set' do + let(:customer_portal_url) { 'https://customers.example.com' } + let(:frame_src_expectation) do + [ + ::Gitlab::ContentSecurityPolicy::Directives.frame_src, + 'http://localhost/admin/', + 'http://localhost/assets/', + 'http://localhost/-/speedscope/index.html', + 'http://localhost/-/sandbox/', + customer_portal_url + ].join(' ') + end - before do - stub_env('CUSTOMER_PORTAL_URL', customer_portal_url) + before do + stub_env('CUSTOMER_PORTAL_URL', customer_portal_url) + end + + it 'adds CUSTOMER_PORTAL_URL to CSP' do + expect(frame_src).to eq(frame_src_expectation) + end end - it 'adds CUSTOMER_PORTAL_URL to CSP' do - expect(directives['frame_src']).to eq(::Gitlab::ContentSecurityPolicy::Directives.frame_src + " http://localhost/admin/ http://localhost/assets/ http://localhost/-/speedscope/index.html http://localhost/-/sandbox/ #{customer_portal_url}") + context 'when CUSTOMER_PORTAL_URL is blank' do + let(:customer_portal_url) { '' } + let(:frame_src_expectation) do + [ + ::Gitlab::ContentSecurityPolicy::Directives.frame_src, + 'http://localhost/admin/', + 'http://localhost/assets/', + 'http://localhost/-/speedscope/index.html', + 'http://localhost/-/sandbox/' + ].join(' ') + end + + before do + stub_env('CUSTOMER_PORTAL_URL', customer_portal_url) + end + + it 'adds CUSTOMER_PORTAL_URL to CSP' do + expect(frame_src).to eq(frame_src_expectation) + end end end - context 'letter_opener application URL' do + describe 'letter_opener application URL' do let(:gitlab_url) { 'http://gitlab.example.com' } let(:letter_opener_url) { "#{gitlab_url}/rails/letter_opener/" } @@ -200,21 +353,21 @@ RSpec.describe Gitlab::ContentSecurityPolicy::ConfigLoader do context 'when in production' do before do - allow(Rails).to receive(:env).and_return(ActiveSupport::StringInquirer.new('production')) + stub_rails_env('production') end it 'does not add letter_opener to CSP' do - expect(directives['frame_src']).not_to include(letter_opener_url) + expect(frame_src).not_to include(letter_opener_url) end end context 'when in development' do before do - allow(Rails).to receive(:env).and_return(ActiveSupport::StringInquirer.new('development')) + stub_rails_env('development') end it 'adds letter_opener to CSP' do - expect(directives['frame_src']).to include(letter_opener_url) + expect(frame_src).to include(letter_opener_url) end end end @@ -234,7 +387,7 @@ RSpec.describe Gitlab::ContentSecurityPolicy::ConfigLoader do end it 'does not add Snowplow Micro URL to connect-src' do - expect(directives['connect_src']).not_to include(snowplow_micro_url) + expect(connect_src).not_to include(snowplow_micro_url) end end @@ -244,7 +397,7 @@ RSpec.describe Gitlab::ContentSecurityPolicy::ConfigLoader do end it 'adds Snowplow Micro URL with trailing slash to connect-src' do - expect(directives['connect_src']).to match(Regexp.new(snowplow_micro_url)) + expect(connect_src).to match(Regexp.new(snowplow_micro_url)) end context 'when not enabled using config' do @@ -253,7 +406,7 @@ RSpec.describe Gitlab::ContentSecurityPolicy::ConfigLoader do end it 'does not add Snowplow Micro URL to connect-src' do - expect(directives['connect_src']).not_to include(snowplow_micro_url) + expect(connect_src).not_to include(snowplow_micro_url) end end @@ -262,8 +415,18 @@ RSpec.describe Gitlab::ContentSecurityPolicy::ConfigLoader do stub_env('REVIEW_APPS_ENABLED', 'true') end - it 'adds gitlab-org/gitlab merge requests API endpoint to CSP' do - expect(directives['connect_src']).to include('https://gitlab.com/api/v4/projects/278964/merge_requests/') + it "includes review app's merge requests API endpoint in the CSP" do + expect(connect_src).to include('https://gitlab.com/api/v4/projects/278964/merge_requests/') + end + end + + context 'when REVIEW_APPS_ENABLED is blank' do + before do + stub_env('REVIEW_APPS_ENABLED', '') + end + + it "does not include review app's merge requests API endpoint in the CSP" do + expect(connect_src).not_to include('https://gitlab.com/api/v4/projects/278964/merge_requests/') end end end diff --git a/spec/lib/gitlab/git/commit_spec.rb b/spec/lib/gitlab/git/commit_spec.rb index 3b1dbf7d602..5c4be1003c3 100644 --- a/spec/lib/gitlab/git/commit_spec.rb +++ b/spec/lib/gitlab/git/commit_spec.rb @@ -691,6 +691,100 @@ RSpec.describe Gitlab::Git::Commit, feature_category: :source_code_management do end end + describe 'SHA patterns' do + shared_examples 'a SHA-matching pattern' do + let(:expected_match) { sha } + + shared_examples 'a match' do + it 'matches the pattern' do + expect(value).to match(pattern) + expect(pattern.match(value).to_a).to eq([expected_match]) + end + end + + shared_examples 'no match' do + it 'does not match the pattern' do + expect(value).not_to match(pattern) + end + end + + shared_examples 'a SHA pattern' do + context "with too short value" do + let(:value) { sha[0, described_class::MIN_SHA_LENGTH - 1] } + + it_behaves_like 'no match' + end + + context "with full length" do + let(:value) { sha } + + it_behaves_like 'a match' + end + + context "with exceeeding length" do + let(:value) { sha + sha } + + # This case is not exactly pretty for SHA1 as we would still match the full SHA256 length. It's arguable what + # the correct behaviour would be, but without starting to distinguish SHA1 and SHA256 hashes this is the best + # we can do. + let(:expected_match) { (sha + sha)[0, described_class::MAX_SHA_LENGTH] } + + it_behaves_like 'a match' + end + + context "with embedded SHA" do + let(:value) { "xxx#{sha}xxx" } + + it_behaves_like 'a match' + end + end + + context 'abbreviated SHA pattern' do + let(:pattern) { described_class::SHA_PATTERN } + + context "with minimum length" do + let(:value) { sha[0, described_class::MIN_SHA_LENGTH] } + let(:expected_match) { value } + + it_behaves_like 'a match' + end + + context "with medium length" do + let(:value) { sha[0, described_class::MIN_SHA_LENGTH + 20] } + let(:expected_match) { value } + + it_behaves_like 'a match' + end + + it_behaves_like 'a SHA pattern' + end + + context 'full SHA pattern' do + let(:pattern) { described_class::FULL_SHA_PATTERN } + + context 'with abbreviated length' do + let(:value) { sha[0, described_class::SHA1_LENGTH - 1] } + + it_behaves_like 'no match' + end + + it_behaves_like 'a SHA pattern' + end + end + + context 'SHA1' do + let(:sha) { "5716ca5987cbf97d6bb54920bea6adde242d87e6" } + + it_behaves_like 'a SHA-matching pattern' + end + + context 'SHA256' do + let(:sha) { "a52e146ac2ab2d0efbb768ab8ebd1e98a6055764c81fe424fbae4522f5b4cb92" } + + it_behaves_like 'a SHA-matching pattern' + end + end + def sample_commit_hash { author_email: "dmitriy.zaporozhets@gmail.com", diff --git a/spec/lib/gitlab/hook_data/merge_request_builder_spec.rb b/spec/lib/gitlab/hook_data/merge_request_builder_spec.rb index f9a6c25b786..1818693974e 100644 --- a/spec/lib/gitlab/hook_data/merge_request_builder_spec.rb +++ b/spec/lib/gitlab/hook_data/merge_request_builder_spec.rb @@ -39,6 +39,7 @@ RSpec.describe Gitlab::HookData::MergeRequestBuilder do title updated_at updated_by_id + draft ].freeze expect(safe_attribute_keys).to match_array(expected_safe_attribute_keys) @@ -66,6 +67,7 @@ RSpec.describe Gitlab::HookData::MergeRequestBuilder do url last_commit work_in_progress + draft total_time_spent time_change human_total_time_spent diff --git a/spec/lib/gitlab/x509/signature_spec.rb b/spec/lib/gitlab/x509/signature_spec.rb index d119a4e2b9d..e0823aa8153 100644 --- a/spec/lib/gitlab/x509/signature_spec.rb +++ b/spec/lib/gitlab/x509/signature_spec.rb @@ -36,6 +36,7 @@ RSpec.describe Gitlab::X509::Signature do it 'returns a verified signature if email does match' do expect(signature.x509_certificate).to have_attributes(certificate_attributes) + expect(signature.x509_certificate.x509_issuer).to have_attributes(issuer_attributes) expect(signature.verified_signature).to be_truthy expect(signature.verification_status).to eq(:verified) @@ -55,6 +56,27 @@ RSpec.describe Gitlab::X509::Signature do expect(signature.verification_status).to eq(:verified) end + context 'when the certificate contains multiple emails' do + before do + allow_any_instance_of(described_class).to receive(:get_certificate_extension).and_call_original + + allow_any_instance_of(described_class).to receive(:get_certificate_extension) + .with('subjectAltName') + .and_return("email:gitlab2@example.com, othername:<unsupported>, email:#{X509Helpers::User1.certificate_email}") + end + + context 'and the email matches one of them' do + it 'returns a verified signature' do + expect(signature.x509_certificate).to have_attributes(certificate_attributes.except(:email, :emails)) + expect(signature.x509_certificate.email).to eq('gitlab2@example.com') + expect(signature.x509_certificate.emails).to contain_exactly('gitlab2@example.com', X509Helpers::User1.certificate_email) + expect(signature.x509_certificate.x509_issuer).to have_attributes(issuer_attributes) + expect(signature.verified_signature).to be_truthy + expect(signature.verification_status).to eq(:verified) + end + end + end + context "if the email matches but isn't confirmed" do let!(:user) { create(:user, :unconfirmed, email: X509Helpers::User1.certificate_email) } @@ -106,6 +128,7 @@ RSpec.describe Gitlab::X509::Signature do subject_key_identifier: X509Helpers::User1.certificate_subject_key_identifier, subject: X509Helpers::User1.certificate_subject, email: X509Helpers::User1.certificate_email, + emails: [X509Helpers::User1.certificate_email], serial_number: X509Helpers::User1.certificate_serial } end @@ -248,15 +271,31 @@ RSpec.describe Gitlab::X509::Signature do .and_return("email:gitlab@example.com, othername:<unsupported>") end - it 'extracts email' do - signature = described_class.new( + let(:signature) do + described_class.new( X509Helpers::User1.signed_commit_signature, X509Helpers::User1.signed_commit_base_data, 'gitlab@example.com', X509Helpers::User1.signed_commit_time ) + end + it 'extracts email' do expect(signature.x509_certificate.email).to eq("gitlab@example.com") + expect(signature.x509_certificate.emails).to contain_exactly("gitlab@example.com") + end + + context 'when there are multiple emails' do + before do + allow_any_instance_of(described_class).to receive(:get_certificate_extension) + .with('subjectAltName') + .and_return("email:gitlab@example.com, othername:<unsupported>, email:gitlab2@example.com") + end + + it 'extracts all the emails' do + expect(signature.x509_certificate.email).to eq("gitlab@example.com") + expect(signature.x509_certificate.emails).to contain_exactly("gitlab@example.com", "gitlab2@example.com") + end end end @@ -311,6 +350,7 @@ RSpec.describe Gitlab::X509::Signature do subject_key_identifier: X509Helpers::User1.tag_certificate_subject_key_identifier, subject: X509Helpers::User1.certificate_subject, email: X509Helpers::User1.certificate_email, + emails: [X509Helpers::User1.certificate_email], serial_number: X509Helpers::User1.tag_certificate_serial } end diff --git a/spec/migrations/20230724071541_queue_backfill_default_branch_protection_namespace_setting_spec.rb b/spec/migrations/20230724071541_queue_backfill_default_branch_protection_namespace_setting_spec.rb new file mode 100644 index 00000000000..5ba8c6b853c --- /dev/null +++ b/spec/migrations/20230724071541_queue_backfill_default_branch_protection_namespace_setting_spec.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe QueueBackfillDefaultBranchProtectionNamespaceSetting, feature_category: :database do + let!(:batched_migration) { described_class::MIGRATION } + + it 'schedules a new batched migration' do + reversible_migration do |migration| + migration.before -> { + expect(batched_migration).not_to have_scheduled_batched_migration + } + + migration.after -> { + expect(batched_migration).to have_scheduled_batched_migration( + table_name: :namespace_settings, + column_name: :namespace_id, + interval: described_class::DELAY_INTERVAL, + batch_size: described_class::BATCH_SIZE, + sub_batch_size: described_class::SUB_BATCH_SIZE + ) + } + end + end +end diff --git a/spec/models/commit_spec.rb b/spec/models/commit_spec.rb index dd3d4f1865c..7ab43611108 100644 --- a/spec/models/commit_spec.rb +++ b/spec/models/commit_spec.rb @@ -831,7 +831,8 @@ eos expect(described_class.valid_hash?('a' * 6)).to be false expect(described_class.valid_hash?('a' * 7)).to be true expect(described_class.valid_hash?('a' * 40)).to be true - expect(described_class.valid_hash?('a' * 41)).to be false + expect(described_class.valid_hash?('a' * 64)).to be true + expect(described_class.valid_hash?('a' * 65)).to be false end end diff --git a/spec/models/project_team_spec.rb b/spec/models/project_team_spec.rb index 7df49fbe548..a6766035c1e 100644 --- a/spec/models/project_team_spec.rb +++ b/spec/models/project_team_spec.rb @@ -180,7 +180,9 @@ RSpec.describe ProjectTeam, feature_category: :groups_and_projects do subject(:import) { target_project.team.import(source_project, current_user) } - it { is_expected.to match(imported_members) } + it 'matches the imported members', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/419394' do + is_expected.to match(imported_members) + end it 'target project includes source member with the same access' do import diff --git a/spec/presenters/blob_presenter_spec.rb b/spec/presenters/blob_presenter_spec.rb index 150c7bd5f3e..00a2c218466 100644 --- a/spec/presenters/blob_presenter_spec.rb +++ b/spec/presenters/blob_presenter_spec.rb @@ -2,8 +2,8 @@ require 'spec_helper' -RSpec.describe BlobPresenter do - let_it_be(:project) { create(:project, :repository) } +RSpec.describe BlobPresenter, feature_category: :source_code_management do + let_it_be(:project) { create(:project, :repository, lfs: true) } let_it_be(:user) { project.first_owner } let(:repository) { project.repository } @@ -228,6 +228,83 @@ RSpec.describe BlobPresenter do it { expect(presenter.code_owners).to match_array([]) } end + describe '#external_storage_url' do + let(:static_objects_external_storage_url) { nil } + let(:raw_path) { Rails.application.routes.url_helpers.project_raw_path(project, File.join(ref, path)) } + let(:token) { '' } + let(:cdn_fronted_url) do + "#{static_objects_external_storage_url}#{raw_path}#{token}" + end + + subject { presenter.external_storage_url } + + before do + stub_application_setting(static_objects_external_storage_url: static_objects_external_storage_url) + end + + context 'when blob is an lfs pointer' do + let_it_be(:blob) { project.repository.blob_at_branch('lfs', 'files/lfs/lfs_object.iso') } + let_it_be(:lfs_object) { project.lfs_objects.find_by_oid(blob.lfs_oid) } + + let(:lfs_object_url) { lfs_object.file.url(content_type: "application/octet-stream") } + let(:lfs_object_proxy_url) { "#{project.http_url_to_repo}/gitlab-lfs/objects/#{lfs_object.oid}" } + let(:proxy_download) { true } + let(:lfs_config) do + Gitlab.config.lfs.deep_merge( + 'enabled' => true, + 'object_store' => { + 'remote_directory' => 'lfs-objects', + 'enabled' => true, + 'proxy_download' => proxy_download, + 'connection' => { + 'endpoint' => 'http:127.0.0.1:9000', + 'path_style' => true + } + } + ) + end + + before do + stub_lfs_setting(lfs_config) + stub_lfs_object_storage(proxy_download: proxy_download) + end + + context 'when direct download is enabled' do + let(:proxy_download) { false } + + it { is_expected.to eq(lfs_object_url) } + end + + context 'when proxy download is enabled' do + it { is_expected.to eq(lfs_object_proxy_url) } + end + end + + context 'when static_objects_external_storage_enabled?' do + let(:static_objects_external_storage_url) { 'https://cdn.gitlab.com' } + + context 'and project is private' do + let(:token) { "?token=#{user.static_object_token}" } + + it { is_expected.to eq(cdn_fronted_url) } + end + + context 'and project is public' do + let(:token) { '' } + + before do + allow(project).to receive(:public?).and_return(true) + end + + it { is_expected.to eq(cdn_fronted_url) } + end + end + + context 'when not static_objects_external_storage_enabled?' do + it { is_expected.to be_nil } + end + end + describe '#ide_edit_path' do it { expect(presenter.ide_edit_path).to eq("/-/ide/project/#{project.full_path}/edit/HEAD/-/files/ruby/regex.rb") } end diff --git a/spec/routing/project_routing_spec.rb b/spec/routing/project_routing_spec.rb index c78adc2dcef..abc42d11c63 100644 --- a/spec/routing/project_routing_spec.rb +++ b/spec/routing/project_routing_spec.rb @@ -380,13 +380,14 @@ RSpec.describe 'project routing' do it_behaves_like 'redirecting a legacy path', '/gitlab/gitlabhq/hooks/hook_logs/1', '/gitlab/gitlabhq/-/hooks/hook_logs/1' end - # project_commit GET /:project_id/commit/:id(.:format) commit#show {id: /\h{7,40}/, project_id: /[^\/]+/} + # project_commit GET /:project_id/commit/:id(.:format) commit#show {id: Gitlab::Git::Commit::SHA_PATTERN, project_id: /[^\/]+/} describe Projects::CommitController, 'routing' do it 'to #show' do expect(get('/gitlab/gitlabhq/-/commit/4246fbd')).to route_to('projects/commit#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: '4246fbd') expect(get('/gitlab/gitlabhq/-/commit/4246fbd.diff')).to route_to('projects/commit#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: '4246fbd', format: 'diff') expect(get('/gitlab/gitlabhq/-/commit/4246fbd.patch')).to route_to('projects/commit#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: '4246fbd', format: 'patch') expect(get('/gitlab/gitlabhq/-/commit/4246fbd13872934f72a8fd0d6fb1317b47b59cb5')).to route_to('projects/commit#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: '4246fbd13872934f72a8fd0d6fb1317b47b59cb5') + expect(get('/gitlab/gitlabhq/-/commit/6ef19b41225c5369f1c104d45d8d85efa9b057b53b14b4b9b939dd74decc5321')).to route_to('projects/commit#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: '6ef19b41225c5369f1c104d45d8d85efa9b057b53b14b4b9b939dd74decc5321') end it_behaves_like 'redirecting a legacy path', "/gitlab/gitlabhq/commit/4246fbd", "/gitlab/gitlabhq/-/commit/4246fbd" @@ -652,6 +653,10 @@ RSpec.describe 'project routing' do it 'to #show' do expect(get('/gitlab/gitlabhq/-/compare/master...stable')).to route_to('projects/compare#show', namespace_id: 'gitlab', project_id: 'gitlabhq', from: 'master', to: 'stable') expect(get('/gitlab/gitlabhq/-/compare/issue/1234...stable')).to route_to('projects/compare#show', namespace_id: 'gitlab', project_id: 'gitlabhq', from: 'issue/1234', to: 'stable') + expect(get('/gitlab/gitlabhq/-/compare/257cc5642cb1a054f08cc83f2d943e56fd3ebe99...5716ca5987cbf97d6bb54920bea6adde242d87e6')) + .to route_to('projects/compare#show', namespace_id: 'gitlab', project_id: 'gitlabhq', from: '257cc5642cb1a054f08cc83f2d943e56fd3ebe99', to: '5716ca5987cbf97d6bb54920bea6adde242d87e6') + expect(get('/gitlab/gitlabhq/-/compare/47d6aca82756ff2e61e53520bfdf1faa6c86d933be4854eb34840c57d12e0c85...a52e146ac2ab2d0efbb768ab8ebd1e98a6055764c81fe424fbae4522f5b4cb92')) + .to route_to('projects/compare#show', namespace_id: 'gitlab', project_id: 'gitlabhq', from: '47d6aca82756ff2e61e53520bfdf1faa6c86d933be4854eb34840c57d12e0c85', to: 'a52e146ac2ab2d0efbb768ab8ebd1e98a6055764c81fe424fbae4522f5b4cb92') end it_behaves_like 'redirecting a legacy path', '/gitlab/gitlabhq/compare', '/gitlab/gitlabhq/-/compare' diff --git a/spec/support/helpers/filter_spec_helper.rb b/spec/support/helpers/filter_spec_helper.rb index 7beed9c7755..dc282bf0a68 100644 --- a/spec/support/helpers/filter_spec_helper.rb +++ b/spec/support/helpers/filter_spec_helper.rb @@ -94,9 +94,9 @@ module FilterSpecHelper when /\A(.+)?[^\d]\d+\z/ # Integer-based reference with optional project prefix reference.gsub(/\d+\z/) { |i| i.to_i + 10_000 } - when /\A(.+@)?(\h{7,40}\z)/ + when /\A(.+@)?(#{Gitlab::Git::Commit::RAW_SHA_PATTERN}\z)/o # SHA-based reference with optional prefix - reference.gsub(/\h{7,40}\z/) { |v| v.reverse } + reference.gsub(/#{Gitlab::Git::Commit::RAW_SHA_PATTERN}\z/o) { |v| v.reverse } else reference.gsub(/\w+\z/) { |v| v.reverse } end diff --git a/spec/support/shared_examples/features/access_tokens_shared_examples.rb b/spec/support/shared_examples/features/access_tokens_shared_examples.rb index 3c78869ffaa..34e3ba95b0d 100644 --- a/spec/support/shared_examples/features/access_tokens_shared_examples.rb +++ b/spec/support/shared_examples/features/access_tokens_shared_examples.rb @@ -15,6 +15,8 @@ RSpec.shared_examples 'resource access tokens creation' do |resource_type| name = 'My access token' visit resource_settings_access_tokens_path + + click_button 'Add new token' fill_in 'Token name', with: name # Set date to 1st of next month |