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>2023-07-27 18:10:15 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2023-07-27 18:10:15 +0300
commit9979d2afd66e12d938ea55372dcf2d8105b5eaca (patch)
tree88df8f6a2f2ffba2fa1318dee83f58d6fe76d40d /spec
parentfdf32113c3924f7faec91101282fc28ec42fc869 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
-rw-r--r--spec/features/admin/admin_users_impersonation_tokens_spec.rb1
-rw-r--r--spec/features/profiles/personal_access_tokens_spec.rb5
-rw-r--r--spec/features/projects/settings/access_tokens_spec.rb3
-rw-r--r--spec/features/projects/settings/user_searches_in_settings_spec.rb2
-rw-r--r--spec/frontend/access_tokens/components/access_token_table_app_spec.js18
-rw-r--r--spec/frontend/access_tokens/components/new_access_token_app_spec.js11
-rw-r--r--spec/frontend/access_tokens/index_spec.js4
-rw-r--r--spec/frontend/vue_merge_request_widget/components/widget/__snapshots__/dynamic_content_spec.js.snap20
-rw-r--r--spec/graphql/types/custom_emoji_type_spec.rb13
-rw-r--r--spec/lib/api/validations/validators/git_sha_spec.rb3
-rw-r--r--spec/lib/gitlab/background_migration/backfill_default_branch_protection_namespace_setting_spec.rb65
-rw-r--r--spec/lib/gitlab/checks/branch_check_spec.rb12
-rw-r--r--spec/lib/gitlab/content_security_policy/config_loader_spec.rb245
-rw-r--r--spec/lib/gitlab/git/commit_spec.rb94
-rw-r--r--spec/lib/gitlab/hook_data/merge_request_builder_spec.rb2
-rw-r--r--spec/lib/gitlab/x509/signature_spec.rb44
-rw-r--r--spec/migrations/20230724071541_queue_backfill_default_branch_protection_namespace_setting_spec.rb26
-rw-r--r--spec/models/commit_spec.rb3
-rw-r--r--spec/models/project_team_spec.rb4
-rw-r--r--spec/presenters/blob_presenter_spec.rb81
-rw-r--r--spec/routing/project_routing_spec.rb7
-rw-r--r--spec/support/helpers/filter_spec_helper.rb4
-rw-r--r--spec/support/shared_examples/features/access_tokens_shared_examples.rb2
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