Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
		
							parent
							
								
									ea413f31cf
								
							
						
					
					
						commit
						277496b843
					
				|  | @ -63,7 +63,7 @@ and cross-posted (with the command results) to the responsible team's Slack chan | ||||||
|   Cross link the issue here if it does. |   Cross link the issue here if it does. | ||||||
| - [ ] Ensure that you or a representative in development can be available for at least 2 hours after feature flag updates in production. | - [ ] Ensure that you or a representative in development can be available for at least 2 hours after feature flag updates in production. | ||||||
|   If a different developer will be covering, or an exception is needed, please inform the oncall SRE by using the `@sre-oncall` Slack alias. |   If a different developer will be covering, or an exception is needed, please inform the oncall SRE by using the `@sre-oncall` Slack alias. | ||||||
| - [ ] Ensure that [documentation has been updated](https://docs.gitlab.com/ee/development/documentation/feature_flags.html). | - [ ] Ensure that documentation exists for the feature, and the [version history text](https://docs.gitlab.com/ee/development/documentation/feature_flags.html#add-version-history-text) has been updated. | ||||||
| - [ ] Leave a comment on [the feature issue][main-issue] announcing estimated time when this feature flag will be enabled on GitLab.com. | - [ ] Leave a comment on [the feature issue][main-issue] announcing estimated time when this feature flag will be enabled on GitLab.com. | ||||||
| - [ ] Ensure that any breaking changes have been announced following the [release post process](https://about.gitlab.com/handbook/marketing/blog/release-posts/#deprecations-removals-and-breaking-changes) to ensure GitLab customers are aware. | - [ ] Ensure that any breaking changes have been announced following the [release post process](https://about.gitlab.com/handbook/marketing/blog/release-posts/#deprecations-removals-and-breaking-changes) to ensure GitLab customers are aware. | ||||||
| - [ ] Notify the [`#support_gitlab-com` Slack channel](https://gitlab.slack.com/archives/C4XFU81LG) and your team channel ([more guidance when this is necessary in the dev docs](https://docs.gitlab.com/ee/development/feature_flags/controls.html#communicate-the-change)). | - [ ] Notify the [`#support_gitlab-com` Slack channel](https://gitlab.slack.com/archives/C4XFU81LG) and your team channel ([more guidance when this is necessary in the dev docs](https://docs.gitlab.com/ee/development/feature_flags/controls.html#communicate-the-change)). | ||||||
|  |  | ||||||
|  | @ -483,9 +483,9 @@ BackgroundMigration/FeatureCategory: | ||||||
|   Include: |   Include: | ||||||
|     - 'lib/gitlab/background_migration/*.rb' |     - 'lib/gitlab/background_migration/*.rb' | ||||||
| 
 | 
 | ||||||
| BackgroundMigration/MissingDictionaryFile: | BackgroundMigration/DictionaryFile: | ||||||
|   Enabled: true |   Enabled: true | ||||||
|   EnforcedSince: 20230307160251 |   EnforcedSince: 20231018100907 | ||||||
|   Include: |   Include: | ||||||
|     - 'db/post_migrate/*.rb' |     - 'db/post_migrate/*.rb' | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -0,0 +1,4 @@ | ||||||
|  | --- | ||||||
|  | # Grace period will be removed in https://gitlab.com/gitlab-org/gitlab/-/issues/428931 | ||||||
|  | BackgroundMigration/DictionaryFile: | ||||||
|  |   Details: grace period | ||||||
|  | @ -36,8 +36,7 @@ export default function initDiffsApp(store = notesStore) { | ||||||
|         iid: dataset.iid || '', |         iid: dataset.iid || '', | ||||||
|         endpointCoverage: dataset.endpointCoverage || '', |         endpointCoverage: dataset.endpointCoverage || '', | ||||||
|         endpointCodequality: dataset.endpointCodequality || '', |         endpointCodequality: dataset.endpointCodequality || '', | ||||||
|         // This is a workaround which will be solved in: https://gitlab.com/gitlab-org/gitlab/-/issues/428758
 |         sastReportAvailable: dataset.endpointSast, | ||||||
|         sastReportAvailable: Boolean(dataset.endpointSast), |  | ||||||
|         helpPagePath: dataset.helpPagePath, |         helpPagePath: dataset.helpPagePath, | ||||||
|         currentUser: JSON.parse(dataset.currentUserData) || {}, |         currentUser: JSON.parse(dataset.currentUserData) || {}, | ||||||
|         changesEmptyStateIllustration: dataset.changesEmptyStateIllustration, |         changesEmptyStateIllustration: dataset.changesEmptyStateIllustration, | ||||||
|  |  | ||||||
|  | @ -657,7 +657,6 @@ $discord: #5865f2; | ||||||
| $linkedin: #2867b2; | $linkedin: #2867b2; | ||||||
| $mastodon: #6364ff; | $mastodon: #6364ff; | ||||||
| $skype: #0078d7; | $skype: #0078d7; | ||||||
| $twitter: #1d9bf0; |  | ||||||
| 
 | 
 | ||||||
| /* | /* | ||||||
|  *  Award emoji |  *  Award emoji | ||||||
|  |  | ||||||
|  | @ -235,7 +235,7 @@ | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .twitter-icon { | .twitter-icon { | ||||||
|   color: $twitter; |   color: var(--gl-text-color, $gl-text-color); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .discord-icon { | .discord-icon { | ||||||
|  |  | ||||||
|  | @ -1,6 +1,7 @@ | ||||||
| # frozen_string_literal: true | # frozen_string_literal: true | ||||||
| 
 | 
 | ||||||
| class AcmeChallengesController < BaseActionController | # rubocop:disable Rails/ApplicationController | ||||||
|  | class AcmeChallengesController < ActionController::Base | ||||||
|   def show |   def show | ||||||
|     if acme_order |     if acme_order | ||||||
|       render plain: acme_order.challenge_file_content, content_type: 'text/plain' |       render plain: acme_order.challenge_file_content, content_type: 'text/plain' | ||||||
|  | @ -15,3 +16,4 @@ class AcmeChallengesController < BaseActionController | ||||||
|     @acme_order ||= PagesDomainAcmeOrder.find_by_domain_and_token(params[:domain], params[:token]) |     @acme_order ||= PagesDomainAcmeOrder.find_by_domain_and_token(params[:domain], params[:token]) | ||||||
|   end |   end | ||||||
| end | end | ||||||
|  | # rubocop:enable Rails/ApplicationController | ||||||
|  |  | ||||||
|  | @ -3,7 +3,7 @@ | ||||||
| require 'gon' | require 'gon' | ||||||
| require 'fogbugz' | require 'fogbugz' | ||||||
| 
 | 
 | ||||||
| class ApplicationController < BaseActionController | class ApplicationController < ActionController::Base | ||||||
|   include Gitlab::GonHelper |   include Gitlab::GonHelper | ||||||
|   include Gitlab::NoCacheHeaders |   include Gitlab::NoCacheHeaders | ||||||
|   include GitlabRoutingHelper |   include GitlabRoutingHelper | ||||||
|  |  | ||||||
|  | @ -1,31 +0,0 @@ | ||||||
| # frozen_string_literal: true |  | ||||||
| 
 |  | ||||||
| # GitLab lightweight base action controller |  | ||||||
| # |  | ||||||
| # This class should be limited to content that |  | ||||||
| # is desired/required for *all* controllers in |  | ||||||
| # GitLab. |  | ||||||
| # |  | ||||||
| # Most controllers inherit from `ApplicationController`. |  | ||||||
| # Some controllers don't want or need all of that |  | ||||||
| # logic and instead inherit from `ActionController::Base`. |  | ||||||
| # This makes it difficult to set security headers and |  | ||||||
| # handle other critical logic across *all* controllers. |  | ||||||
| # |  | ||||||
| # Between this controller and `ApplicationController` |  | ||||||
| # no controller should ever inherit directly from |  | ||||||
| # `ActionController::Base` |  | ||||||
| # |  | ||||||
| # rubocop:disable Rails/ApplicationController |  | ||||||
| # rubocop:disable Gitlab/NamespacedClass |  | ||||||
| class BaseActionController < ActionController::Base |  | ||||||
|   before_action :security_headers |  | ||||||
| 
 |  | ||||||
|   private |  | ||||||
| 
 |  | ||||||
|   def security_headers |  | ||||||
|     headers['Cross-Origin-Opener-Policy'] = 'same-origin' if ::Feature.enabled?(:coop_header) |  | ||||||
|   end |  | ||||||
| end |  | ||||||
| # rubocop:enable Gitlab/NamespacedClass |  | ||||||
| # rubocop:enable Rails/ApplicationController |  | ||||||
|  | @ -1,6 +1,7 @@ | ||||||
| # frozen_string_literal: true | # frozen_string_literal: true | ||||||
| 
 | 
 | ||||||
| class ChaosController < BaseActionController | # rubocop:disable Rails/ApplicationController | ||||||
|  | class ChaosController < ActionController::Base | ||||||
|   before_action :validate_chaos_secret, unless: :development_or_test? |   before_action :validate_chaos_secret, unless: :development_or_test? | ||||||
| 
 | 
 | ||||||
|   def leakmem |   def leakmem | ||||||
|  | @ -94,3 +95,4 @@ class ChaosController < BaseActionController | ||||||
|     Rails.env.development? || Rails.env.test? |     Rails.env.development? || Rails.env.test? | ||||||
|   end |   end | ||||||
| end | end | ||||||
|  | # rubocop:enable Rails/ApplicationController | ||||||
|  |  | ||||||
|  | @ -1,6 +1,7 @@ | ||||||
| # frozen_string_literal: true | # frozen_string_literal: true | ||||||
| 
 | 
 | ||||||
| class HealthController < BaseActionController | # rubocop:disable Rails/ApplicationController | ||||||
|  | class HealthController < ActionController::Base | ||||||
|   protect_from_forgery with: :exception, prepend: true |   protect_from_forgery with: :exception, prepend: true | ||||||
|   include RequiresAllowlistedMonitoringClient |   include RequiresAllowlistedMonitoringClient | ||||||
| 
 | 
 | ||||||
|  | @ -39,3 +40,4 @@ class HealthController < BaseActionController | ||||||
|     render json: result.json, status: result.http_status |     render json: result.json, status: result.http_status | ||||||
|   end |   end | ||||||
| end | end | ||||||
|  | # rubocop:enable Rails/ApplicationController | ||||||
|  |  | ||||||
|  | @ -1,6 +1,7 @@ | ||||||
| # frozen_string_literal: true | # frozen_string_literal: true | ||||||
| 
 | 
 | ||||||
| class MetricsController < BaseActionController | # rubocop:disable Rails/ApplicationController | ||||||
|  | class MetricsController < ActionController::Base | ||||||
|   include RequiresAllowlistedMonitoringClient |   include RequiresAllowlistedMonitoringClient | ||||||
| 
 | 
 | ||||||
|   protect_from_forgery with: :exception, prepend: true |   protect_from_forgery with: :exception, prepend: true | ||||||
|  | @ -35,3 +36,4 @@ class MetricsController < BaseActionController | ||||||
|     ) |     ) | ||||||
|   end |   end | ||||||
| end | end | ||||||
|  | # rubocop:enable Rails/ApplicationController | ||||||
|  |  | ||||||
|  | @ -1,4 +1,4 @@ | ||||||
| %p.text-center | %p{ class: local_assigns.fetch(:wrapper_class, 'gl-text-center') } | ||||||
|   %span.light |   %span.light | ||||||
|     = _('Already have an account?') |     = _('Already have an account?') | ||||||
|     - path_params = { redirect_to_referer: 'yes' } |     - path_params = { redirect_to_referer: 'yes' } | ||||||
|  |  | ||||||
|  | @ -1,77 +1,10 @@ | ||||||
| - max_first_name_length = max_last_name_length = 127 |  | ||||||
| - borderless ||= false | - borderless ||= false | ||||||
| - form_resource_name = "new_#{resource_name}" |  | ||||||
| 
 | 
 | ||||||
| .gl-mb-3.gl-p-4{ class: (borderless ? '' : 'gl-border-gray-100 gl-border-1 gl-border-solid gl-rounded-base') } | .gl-mb-3.gl-p-4{ class: (borderless ? '' : 'gl-border-gray-100 gl-border-1 gl-border-solid gl-rounded-base') } | ||||||
|   = yield :omniauth_providers_top if show_omniauth_providers |   = yield :omniauth_providers_top if show_omniauth_providers | ||||||
| 
 | 
 | ||||||
|   = gitlab_ui_form_for(resource, as: form_resource_name, url: url, html: { class: 'gl-show-field-errors js-arkose-labs-form', aria: { live: 'assertive' }}, data: { testid: 'signup-form' }) do |f| |   = render 'devise/shared/signup_box_form', | ||||||
|     .devise-errors |     button_text: button_text, | ||||||
|       = render 'devise/shared/error_messages', resource: resource |     url: url, | ||||||
|     - if Gitlab::CurrentSettings.invisible_captcha_enabled |     show_omniauth_providers: omniauth_enabled? && button_based_providers_enabled? | ||||||
|       = invisible_captcha nonce: true, autocomplete: SecureRandom.alphanumeric(12) |  | ||||||
|     .name.form-row |  | ||||||
|       .col.form-group |  | ||||||
|         = f.label :first_name, _('First name'), for: 'new_user_first_name' |  | ||||||
|         = f.text_field :first_name, |  | ||||||
|           class: 'form-control gl-form-input top js-block-emoji js-validate-length', |  | ||||||
|           data: { max_length: max_first_name_length, |  | ||||||
|           max_length_message: s_('SignUp|First name is too long (maximum is %{max_length} characters).') % { max_length: max_first_name_length }, |  | ||||||
|           testid: 'new-user-first-name-field' }, |  | ||||||
|           required: true, |  | ||||||
|           title: _('This field is required.') |  | ||||||
|       .col.form-group |  | ||||||
|         = f.label :last_name, _('Last name'), for: 'new_user_last_name' |  | ||||||
|         = f.text_field :last_name, |  | ||||||
|           class: 'form-control gl-form-input top js-block-emoji js-validate-length', |  | ||||||
|           data: { max_length: max_last_name_length, |  | ||||||
|           max_length_message: s_('SignUp|Last name is too long (maximum is %{max_length} characters).') % { max_length: max_last_name_length }, |  | ||||||
|           testid: 'new-user-last-name-field' }, |  | ||||||
|           required: true, |  | ||||||
|           title: _('This field is required.') |  | ||||||
|     .username.form-group |  | ||||||
|       = f.label :username, _('Username') |  | ||||||
|       = f.text_field :username, |  | ||||||
|         class: 'form-control gl-form-input middle js-block-emoji js-validate-length js-validate-username', |  | ||||||
|         data: signup_username_data_attributes, |  | ||||||
|         pattern: Gitlab::PathRegex::NAMESPACE_FORMAT_REGEX_JS, |  | ||||||
|         required: true, |  | ||||||
|         title: _('Please create a username with only alphanumeric characters.') |  | ||||||
|       %p.validation-error.gl-text-red-500.gl-field-error-ignore.gl-mt-2.field-validation.hide= _('Username is already taken.') |  | ||||||
|       %p.validation-success.gl-text-green-600.gl-field-error-ignore.gl-mt-2.field-validation.hide= _('Username is available.') |  | ||||||
|       %p.validation-pending.gl-field-error-ignore.gl-mt-2.field-validation.hide= _('Checking username availability...') |  | ||||||
|     .form-group |  | ||||||
|       = f.label :email, _('Email') |  | ||||||
|       = f.email_field :email, |  | ||||||
|         class: 'form-control gl-form-input middle js-validate-email', |  | ||||||
|         data: { testid: 'new-user-email-field' }, |  | ||||||
|         required: true, |  | ||||||
|         title: _('Please provide a valid email address.') |  | ||||||
|       %p.validation-hint.gl-field-hint.text-secondary= _('We recommend a work email address.') |  | ||||||
|       %p.validation-warning.gl-field-error-ignore.text-secondary.hide= _('This email address does not look right, are you sure you typed it correctly?') |  | ||||||
|       -# This is used for providing entry to Jihu on email verification |  | ||||||
|       = render_if_exists 'devise/shared/signup_email_additional_info' |  | ||||||
|     .form-group.gl-mb-5 |  | ||||||
|       = f.label :password, _('Password') |  | ||||||
|       %input.form-control.gl-form-input.js-password{ data: { id: "#{form_resource_name}_password", |  | ||||||
|         title: s_('SignUp|Minimum length is %{minimum_password_length} characters.') % { minimum_password_length: @minimum_password_length }, |  | ||||||
|         minimum_password_length: @minimum_password_length, |  | ||||||
|         testid: 'new-user-password-field', |  | ||||||
|         autocomplete: 'new-password', |  | ||||||
|         name: "#{form_resource_name}[password]" } } |  | ||||||
|       %p.gl-field-hint-valid.text-secondary= s_('SignUp|Minimum length is %{minimum_password_length} characters.') % { minimum_password_length: @minimum_password_length } |  | ||||||
|       = render_if_exists 'shared/password_requirements_list' |  | ||||||
|     = render_if_exists 'devise/shared/phone_verification', form: f |  | ||||||
| 
 | 
 | ||||||
|     .form-group |  | ||||||
|       - if arkose_labs_enabled? |  | ||||||
|         = render_if_exists 'devise/registrations/arkose_labs' |  | ||||||
|       - elsif show_recaptcha_sign_up? |  | ||||||
|         = recaptcha_tags nonce: content_security_policy_nonce |  | ||||||
| 
 |  | ||||||
|     = render Pajamas::ButtonComponent.new(type: :submit, variant: :confirm, block: true, button_options: { data: { testid: 'new-user-register-button' }}) do |  | ||||||
|       = button_text |  | ||||||
| 
 |  | ||||||
|     = render 'devise/shared/terms_of_service_notice', button_text: button_text |  | ||||||
| 
 |  | ||||||
|   = yield :omniauth_providers_bottom if show_omniauth_providers |  | ||||||
|  |  | ||||||
|  | @ -0,0 +1,73 @@ | ||||||
|  | - max_first_name_length = max_last_name_length = 127 | ||||||
|  | - form_resource_name = "new_#{resource_name}" | ||||||
|  | 
 | ||||||
|  | = gitlab_ui_form_for(resource, as: form_resource_name, url: url, html: { class: 'gl-show-field-errors js-arkose-labs-form', aria: { live: 'assertive' }}, data: { testid: 'signup-form' }) do |f| | ||||||
|  |   .devise-errors | ||||||
|  |     = render 'devise/shared/error_messages', resource: resource | ||||||
|  |   - if Gitlab::CurrentSettings.invisible_captcha_enabled | ||||||
|  |     = invisible_captcha nonce: true, autocomplete: SecureRandom.alphanumeric(12) | ||||||
|  |   .name.form-row | ||||||
|  |     .col.form-group | ||||||
|  |       = f.label :first_name, _('First name'), for: 'new_user_first_name' | ||||||
|  |       = f.text_field :first_name, | ||||||
|  |         class: 'form-control gl-form-input top js-block-emoji js-validate-length', | ||||||
|  |         data: { max_length: max_first_name_length, | ||||||
|  |         max_length_message: s_('SignUp|First name is too long (maximum is %{max_length} characters).') % { max_length: max_first_name_length }, | ||||||
|  |         testid: 'new-user-first-name-field' }, | ||||||
|  |         required: true, | ||||||
|  |         title: _('This field is required.') | ||||||
|  |     .col.form-group | ||||||
|  |       = f.label :last_name, _('Last name'), for: 'new_user_last_name' | ||||||
|  |       = f.text_field :last_name, | ||||||
|  |         class: 'form-control gl-form-input top js-block-emoji js-validate-length', | ||||||
|  |         data: { max_length: max_last_name_length, | ||||||
|  |         max_length_message: s_('SignUp|Last name is too long (maximum is %{max_length} characters).') % { max_length: max_last_name_length }, | ||||||
|  |         testid: 'new-user-last-name-field' }, | ||||||
|  |         required: true, | ||||||
|  |         title: _('This field is required.') | ||||||
|  |   .username.form-group | ||||||
|  |     = f.label :username, _('Username') | ||||||
|  |     = f.text_field :username, | ||||||
|  |       class: 'form-control gl-form-input middle js-block-emoji js-validate-length js-validate-username', | ||||||
|  |       data: signup_username_data_attributes, | ||||||
|  |       pattern: Gitlab::PathRegex::NAMESPACE_FORMAT_REGEX_JS, | ||||||
|  |       required: true, | ||||||
|  |       title: _('Please create a username with only alphanumeric characters.') | ||||||
|  |     %p.validation-error.gl-text-red-500.gl-field-error-ignore.gl-mt-2.field-validation.hide= _('Username is already taken.') | ||||||
|  |     %p.validation-success.gl-text-green-600.gl-field-error-ignore.gl-mt-2.field-validation.hide= _('Username is available.') | ||||||
|  |     %p.validation-pending.gl-field-error-ignore.gl-mt-2.field-validation.hide= _('Checking username availability...') | ||||||
|  |   .form-group | ||||||
|  |     = f.label :email, _('Email') | ||||||
|  |     = f.email_field :email, | ||||||
|  |       class: 'form-control gl-form-input middle js-validate-email', | ||||||
|  |       data: { testid: 'new-user-email-field' }, | ||||||
|  |       required: true, | ||||||
|  |       title: _('Please provide a valid email address.') | ||||||
|  |     %p.validation-hint.gl-field-hint.text-secondary= _('We recommend a work email address.') | ||||||
|  |     %p.validation-warning.gl-field-error-ignore.text-secondary.hide= _('This email address does not look right, are you sure you typed it correctly?') | ||||||
|  |     -# This is used for providing entry to Jihu on email verification | ||||||
|  |     = render_if_exists 'devise/shared/signup_email_additional_info' | ||||||
|  |   .form-group.gl-mb-5 | ||||||
|  |     = f.label :password, _('Password') | ||||||
|  |     %input.form-control.gl-form-input.js-password{ data: { id: "#{form_resource_name}_password", | ||||||
|  |       title: s_('SignUp|Minimum length is %{minimum_password_length} characters.') % { minimum_password_length: @minimum_password_length }, | ||||||
|  |       minimum_password_length: @minimum_password_length, | ||||||
|  |       testid: 'new-user-password-field', | ||||||
|  |       autocomplete: 'new-password', | ||||||
|  |       name: "#{form_resource_name}[password]" } } | ||||||
|  |     %p.gl-field-hint-valid.text-secondary= s_('SignUp|Minimum length is %{minimum_password_length} characters.') % { minimum_password_length: @minimum_password_length } | ||||||
|  |     = render_if_exists 'shared/password_requirements_list' | ||||||
|  |   = render_if_exists 'devise/shared/phone_verification', form: f | ||||||
|  | 
 | ||||||
|  |   .form-group | ||||||
|  |     - if arkose_labs_enabled? | ||||||
|  |       = render_if_exists 'devise/registrations/arkose_labs' | ||||||
|  |     - elsif show_recaptcha_sign_up? | ||||||
|  |       = recaptcha_tags nonce: content_security_policy_nonce | ||||||
|  | 
 | ||||||
|  |   = render Pajamas::ButtonComponent.new(type: :submit, variant: :confirm, block: true, button_options: { data: { testid: 'new-user-register-button' }}) do | ||||||
|  |     = button_text | ||||||
|  | 
 | ||||||
|  |   = render 'devise/shared/terms_of_service_notice', button_text: button_text | ||||||
|  | 
 | ||||||
|  | = yield :omniauth_providers_bottom if show_omniauth_providers | ||||||
|  | @ -14,7 +14,10 @@ | ||||||
|     = _("Create an account using:") |     = _("Create an account using:") | ||||||
|   .gl-display-flex.gl-justify-content-between.gl-flex-wrap |   .gl-display-flex.gl-justify-content-between.gl-flex-wrap | ||||||
|     - providers.each do |provider| |     - providers.each do |provider| | ||||||
|       = button_to omniauth_authorize_path(:user, provider, register_omniauth_params(local_assigns)), class: "btn gl-button btn-default gl-w-full gl-mb-4 js-oauth-login #{qa_selector_for_provider(provider)}", data: { provider: provider, track_action: "#{provider}_sso", track_label: tracking_label }, id: "oauth-login-#{provider}" do |       = button_to omniauth_authorize_path(:user, provider, register_omniauth_params(local_assigns)), | ||||||
|  |         class: "btn gl-button btn-default gl-w-full gl-mb-4 js-oauth-login #{qa_selector_for_provider(provider)}", | ||||||
|  |         data: { provider: provider, track_action: "#{provider}_sso", track_label: tracking_label }, | ||||||
|  |         id: "oauth-login-#{provider}" do | ||||||
|         - if provider_has_icon?(provider) |         - if provider_has_icon?(provider) | ||||||
|           = provider_image_tag(provider) |           = provider_image_tag(provider) | ||||||
|         %span.gl-button-text |         %span.gl-button-text | ||||||
|  |  | ||||||
|  | @ -1,8 +0,0 @@ | ||||||
| --- |  | ||||||
| name: coop_header |  | ||||||
| introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/131571 |  | ||||||
| rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/425701 |  | ||||||
| milestone: '16.5' |  | ||||||
| type: development |  | ||||||
| group: group::authentication |  | ||||||
| default_enabled: false |  | ||||||
|  | @ -1,6 +1,6 @@ | ||||||
| # frozen_string_literal: true | # frozen_string_literal: true | ||||||
| 
 | 
 | ||||||
| # rubocop: disable BackgroundMigration/MissingDictionaryFile | # rubocop: disable BackgroundMigration/DictionaryFile | ||||||
| 
 | 
 | ||||||
| class RescheduleMigrationForRemediation < Gitlab::Database::Migration[2.1] | class RescheduleMigrationForRemediation < Gitlab::Database::Migration[2.1] | ||||||
|   MIGRATION = 'MigrateRemediationsForVulnerabilityFindings' |   MIGRATION = 'MigrateRemediationsForVulnerabilityFindings' | ||||||
|  | @ -29,4 +29,4 @@ class RescheduleMigrationForRemediation < Gitlab::Database::Migration[2.1] | ||||||
|     delete_batched_background_migration(MIGRATION, :vulnerability_occurrences, :id, []) |     delete_batched_background_migration(MIGRATION, :vulnerability_occurrences, :id, []) | ||||||
|   end |   end | ||||||
| end | end | ||||||
| # rubocop: enable BackgroundMigration/MissingDictionaryFile | # rubocop: enable BackgroundMigration/DictionaryFile | ||||||
|  |  | ||||||
|  | @ -1,6 +1,6 @@ | ||||||
| # frozen_string_literal: true | # frozen_string_literal: true | ||||||
| 
 | 
 | ||||||
| # rubocop:disable BackgroundMigration/MissingDictionaryFile | # rubocop:disable BackgroundMigration/DictionaryFile | ||||||
| class RequeueBackfillProjectWikiRepositories < Gitlab::Database::Migration[2.1] | class RequeueBackfillProjectWikiRepositories < Gitlab::Database::Migration[2.1] | ||||||
|   MIGRATION = "BackfillProjectWikiRepositories" |   MIGRATION = "BackfillProjectWikiRepositories" | ||||||
|   DELAY_INTERVAL = 2.minutes |   DELAY_INTERVAL = 2.minutes | ||||||
|  | @ -26,4 +26,4 @@ class RequeueBackfillProjectWikiRepositories < Gitlab::Database::Migration[2.1] | ||||||
|     delete_batched_background_migration(MIGRATION, :projects, :id, []) |     delete_batched_background_migration(MIGRATION, :projects, :id, []) | ||||||
|   end |   end | ||||||
| end | end | ||||||
| # rubocop:enable BackgroundMigration/MissingDictionaryFile | # rubocop:enable BackgroundMigration/DictionaryFile | ||||||
|  |  | ||||||
|  | @ -1,6 +1,6 @@ | ||||||
| # frozen_string_literal: true | # frozen_string_literal: true | ||||||
| 
 | 
 | ||||||
| # rubocop:disable BackgroundMigration/MissingDictionaryFile | # rubocop:disable BackgroundMigration/DictionaryFile | ||||||
| 
 | 
 | ||||||
| class RescheduleEvidencesHandlingUnicode < Gitlab::Database::Migration[2.1] | class RescheduleEvidencesHandlingUnicode < Gitlab::Database::Migration[2.1] | ||||||
|   restrict_gitlab_migration gitlab_schema: :gitlab_main |   restrict_gitlab_migration gitlab_schema: :gitlab_main | ||||||
|  | @ -29,4 +29,4 @@ class RescheduleEvidencesHandlingUnicode < Gitlab::Database::Migration[2.1] | ||||||
|     delete_batched_background_migration(MIGRATION, :vulnerability_occurrences, :id, []) |     delete_batched_background_migration(MIGRATION, :vulnerability_occurrences, :id, []) | ||||||
|   end |   end | ||||||
| end | end | ||||||
| # rubocop:enable BackgroundMigration/MissingDictionaryFile | # rubocop:enable BackgroundMigration/DictionaryFile | ||||||
|  |  | ||||||
|  | @ -1,6 +1,6 @@ | ||||||
| # frozen_string_literal: true | # frozen_string_literal: true | ||||||
| 
 | 
 | ||||||
| # rubocop: disable BackgroundMigration/MissingDictionaryFile | # rubocop: disable BackgroundMigration/DictionaryFile | ||||||
| 
 | 
 | ||||||
| class RescheduleMigrationForLinksFromMetadata < Gitlab::Database::Migration[2.1] | class RescheduleMigrationForLinksFromMetadata < Gitlab::Database::Migration[2.1] | ||||||
|   MIGRATION = 'MigrateLinksForVulnerabilityFindings' |   MIGRATION = 'MigrateLinksForVulnerabilityFindings' | ||||||
|  | @ -29,4 +29,4 @@ class RescheduleMigrationForLinksFromMetadata < Gitlab::Database::Migration[2.1] | ||||||
|     delete_batched_background_migration(MIGRATION, :vulnerability_occurrences, :id, []) |     delete_batched_background_migration(MIGRATION, :vulnerability_occurrences, :id, []) | ||||||
|   end |   end | ||||||
| end | end | ||||||
| # rubocop: enable BackgroundMigration/MissingDictionaryFile | # rubocop: enable BackgroundMigration/DictionaryFile | ||||||
|  |  | ||||||
|  | @ -0,0 +1,16 @@ | ||||||
|  | # frozen_string_literal: true | ||||||
|  | 
 | ||||||
|  | class CleanupBigintConversionForCiProjectMonthlyUsagesSharedRunnersDuration < Gitlab::Database::Migration[2.1] | ||||||
|  |   enable_lock_retries! | ||||||
|  | 
 | ||||||
|  |   TABLE = :ci_project_monthly_usages | ||||||
|  |   COLUMNS = [:shared_runners_duration] | ||||||
|  | 
 | ||||||
|  |   def up | ||||||
|  |     cleanup_conversion_of_integer_to_bigint(TABLE, COLUMNS) | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   def down | ||||||
|  |     restore_conversion_of_integer_to_bigint(TABLE, COLUMNS) | ||||||
|  |   end | ||||||
|  | end | ||||||
|  | @ -0,0 +1,16 @@ | ||||||
|  | # frozen_string_literal: true | ||||||
|  | 
 | ||||||
|  | class CleanupBigintConversionForCiNamespaceMonthlyUsagesSharedRunnersDuration < Gitlab::Database::Migration[2.1] | ||||||
|  |   enable_lock_retries! | ||||||
|  | 
 | ||||||
|  |   TABLE = :ci_namespace_monthly_usages | ||||||
|  |   COLUMNS = [:shared_runners_duration] | ||||||
|  | 
 | ||||||
|  |   def up | ||||||
|  |     cleanup_conversion_of_integer_to_bigint(TABLE, COLUMNS) | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   def down | ||||||
|  |     restore_conversion_of_integer_to_bigint(TABLE, COLUMNS) | ||||||
|  |   end | ||||||
|  | end | ||||||
|  | @ -0,0 +1,17 @@ | ||||||
|  | # frozen_string_literal: true | ||||||
|  | 
 | ||||||
|  | class RemoveRedundantGroupStagesIndex < Gitlab::Database::Migration[2.2] | ||||||
|  |   disable_ddl_transaction! | ||||||
|  | 
 | ||||||
|  |   milestone '16.6' | ||||||
|  | 
 | ||||||
|  |   INDEX_NAME = 'index_analytics_ca_group_stages_on_group_id' | ||||||
|  | 
 | ||||||
|  |   def up | ||||||
|  |     remove_concurrent_index_by_name(:analytics_cycle_analytics_group_stages, INDEX_NAME) | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   def down | ||||||
|  |     add_concurrent_index(:analytics_cycle_analytics_group_stages, :group_id, name: INDEX_NAME) | ||||||
|  |   end | ||||||
|  | end | ||||||
|  | @ -0,0 +1,17 @@ | ||||||
|  | # frozen_string_literal: true | ||||||
|  | 
 | ||||||
|  | class RemoveRedundantMrMetricsIndexOnTargetProjectId < Gitlab::Database::Migration[2.2] | ||||||
|  |   disable_ddl_transaction! | ||||||
|  | 
 | ||||||
|  |   milestone '16.6' | ||||||
|  | 
 | ||||||
|  |   INDEX_NAME = 'index_merge_request_metrics_on_target_project_id' | ||||||
|  | 
 | ||||||
|  |   def up | ||||||
|  |     remove_concurrent_index_by_name(:merge_request_metrics, INDEX_NAME) | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   def down | ||||||
|  |     add_concurrent_index(:merge_request_metrics, :target_project_id, name: INDEX_NAME) | ||||||
|  |   end | ||||||
|  | end | ||||||
|  | @ -0,0 +1 @@ | ||||||
|  | 1bd136e7d4fb7c34030cea6c915a2eeae619ea5ae1a701cb4d5d4bb069df7113 | ||||||
|  | @ -0,0 +1 @@ | ||||||
|  | bf03b09c6247d2f5c3543f4046b48763dfc7e6fb2cdaedc52d8cfc8777f70e71 | ||||||
|  | @ -0,0 +1 @@ | ||||||
|  | add7ce4f9fb56221512227d5aa3697245d537cd5c975978b7dc6dab992890e4e | ||||||
|  | @ -0,0 +1 @@ | ||||||
|  | 08275dacbe6b1bd44cc67834fc77d6615e43ebd1b9a85edc9e7237cbecc57315 | ||||||
|  | @ -335,15 +335,6 @@ BEGIN | ||||||
| END; | END; | ||||||
| $$; | $$; | ||||||
| 
 | 
 | ||||||
| CREATE FUNCTION trigger_bbb95b2d6929() RETURNS trigger |  | ||||||
|     LANGUAGE plpgsql |  | ||||||
|     AS $$ |  | ||||||
| BEGIN |  | ||||||
|   NEW."shared_runners_duration_convert_to_bigint" := NEW."shared_runners_duration"; |  | ||||||
|   RETURN NEW; |  | ||||||
| END; |  | ||||||
| $$; |  | ||||||
| 
 |  | ||||||
| CREATE FUNCTION trigger_bfad0e2b9c86() RETURNS trigger | CREATE FUNCTION trigger_bfad0e2b9c86() RETURNS trigger | ||||||
|     LANGUAGE plpgsql |     LANGUAGE plpgsql | ||||||
|     AS $$ |     AS $$ | ||||||
|  | @ -353,15 +344,6 @@ BEGIN | ||||||
| END; | END; | ||||||
| $$; | $$; | ||||||
| 
 | 
 | ||||||
| CREATE FUNCTION trigger_c0353bbb6145() RETURNS trigger |  | ||||||
|     LANGUAGE plpgsql |  | ||||||
|     AS $$ |  | ||||||
| BEGIN |  | ||||||
|   NEW."shared_runners_duration_convert_to_bigint" := NEW."shared_runners_duration"; |  | ||||||
|   RETURN NEW; |  | ||||||
| END; |  | ||||||
| $$; |  | ||||||
| 
 |  | ||||||
| CREATE FUNCTION unset_has_issues_on_vulnerability_reads() RETURNS trigger | CREATE FUNCTION unset_has_issues_on_vulnerability_reads() RETURNS trigger | ||||||
|     LANGUAGE plpgsql |     LANGUAGE plpgsql | ||||||
|     AS $$ |     AS $$ | ||||||
|  | @ -13788,7 +13770,6 @@ CREATE TABLE ci_namespace_monthly_usages ( | ||||||
|     namespace_id bigint NOT NULL, |     namespace_id bigint NOT NULL, | ||||||
|     date date NOT NULL, |     date date NOT NULL, | ||||||
|     notification_level smallint DEFAULT 100 NOT NULL, |     notification_level smallint DEFAULT 100 NOT NULL, | ||||||
|     shared_runners_duration_convert_to_bigint integer DEFAULT 0 NOT NULL, |  | ||||||
|     created_at timestamp with time zone, |     created_at timestamp with time zone, | ||||||
|     amount_used numeric(18,4) DEFAULT 0.0 NOT NULL, |     amount_used numeric(18,4) DEFAULT 0.0 NOT NULL, | ||||||
|     shared_runners_duration bigint DEFAULT 0 NOT NULL, |     shared_runners_duration bigint DEFAULT 0 NOT NULL, | ||||||
|  | @ -14074,7 +14055,6 @@ CREATE TABLE ci_project_monthly_usages ( | ||||||
|     id bigint NOT NULL, |     id bigint NOT NULL, | ||||||
|     project_id bigint NOT NULL, |     project_id bigint NOT NULL, | ||||||
|     date date NOT NULL, |     date date NOT NULL, | ||||||
|     shared_runners_duration_convert_to_bigint integer DEFAULT 0 NOT NULL, |  | ||||||
|     created_at timestamp with time zone, |     created_at timestamp with time zone, | ||||||
|     amount_used numeric(18,4) DEFAULT 0.0 NOT NULL, |     amount_used numeric(18,4) DEFAULT 0.0 NOT NULL, | ||||||
|     shared_runners_duration bigint DEFAULT 0 NOT NULL, |     shared_runners_duration bigint DEFAULT 0 NOT NULL, | ||||||
|  | @ -31413,8 +31393,6 @@ CREATE INDEX index_allowed_email_domains_on_group_id ON allowed_email_domains US | ||||||
| 
 | 
 | ||||||
| CREATE INDEX index_analytics_ca_group_stages_on_end_event_label_id ON analytics_cycle_analytics_group_stages USING btree (end_event_label_id); | CREATE INDEX index_analytics_ca_group_stages_on_end_event_label_id ON analytics_cycle_analytics_group_stages USING btree (end_event_label_id); | ||||||
| 
 | 
 | ||||||
| CREATE INDEX index_analytics_ca_group_stages_on_group_id ON analytics_cycle_analytics_group_stages USING btree (group_id); |  | ||||||
| 
 |  | ||||||
| CREATE INDEX index_analytics_ca_group_stages_on_relative_position ON analytics_cycle_analytics_group_stages USING btree (relative_position); | CREATE INDEX index_analytics_ca_group_stages_on_relative_position ON analytics_cycle_analytics_group_stages USING btree (relative_position); | ||||||
| 
 | 
 | ||||||
| CREATE INDEX index_analytics_ca_group_stages_on_start_event_label_id ON analytics_cycle_analytics_group_stages USING btree (start_event_label_id); | CREATE INDEX index_analytics_ca_group_stages_on_start_event_label_id ON analytics_cycle_analytics_group_stages USING btree (start_event_label_id); | ||||||
|  | @ -33129,8 +33107,6 @@ CREATE INDEX index_merge_request_metrics_on_merged_by_id ON merge_request_metric | ||||||
| 
 | 
 | ||||||
| CREATE INDEX index_merge_request_metrics_on_pipeline_id ON merge_request_metrics USING btree (pipeline_id); | CREATE INDEX index_merge_request_metrics_on_pipeline_id ON merge_request_metrics USING btree (pipeline_id); | ||||||
| 
 | 
 | ||||||
| CREATE INDEX index_merge_request_metrics_on_target_project_id ON merge_request_metrics USING btree (target_project_id); |  | ||||||
| 
 |  | ||||||
| CREATE INDEX index_merge_request_review_llm_summaries_on_mr_diff_id ON merge_request_review_llm_summaries USING btree (merge_request_diff_id); | CREATE INDEX index_merge_request_review_llm_summaries_on_mr_diff_id ON merge_request_review_llm_summaries USING btree (merge_request_diff_id); | ||||||
| 
 | 
 | ||||||
| CREATE INDEX index_merge_request_review_llm_summaries_on_review_id ON merge_request_review_llm_summaries USING btree (review_id); | CREATE INDEX index_merge_request_review_llm_summaries_on_review_id ON merge_request_review_llm_summaries USING btree (review_id); | ||||||
|  | @ -36779,12 +36755,8 @@ CREATE TRIGGER trigger_7f3d66a7d7f5 BEFORE INSERT OR UPDATE ON ci_pipeline_varia | ||||||
| 
 | 
 | ||||||
| CREATE TRIGGER trigger_b2d852e1e2cb BEFORE INSERT OR UPDATE ON ci_pipelines FOR EACH ROW EXECUTE FUNCTION trigger_b2d852e1e2cb(); | CREATE TRIGGER trigger_b2d852e1e2cb BEFORE INSERT OR UPDATE ON ci_pipelines FOR EACH ROW EXECUTE FUNCTION trigger_b2d852e1e2cb(); | ||||||
| 
 | 
 | ||||||
| CREATE TRIGGER trigger_bbb95b2d6929 BEFORE INSERT OR UPDATE ON ci_project_monthly_usages FOR EACH ROW EXECUTE FUNCTION trigger_bbb95b2d6929(); |  | ||||||
| 
 |  | ||||||
| CREATE TRIGGER trigger_bfad0e2b9c86 BEFORE INSERT OR UPDATE ON ci_pipeline_messages FOR EACH ROW EXECUTE FUNCTION trigger_bfad0e2b9c86(); | CREATE TRIGGER trigger_bfad0e2b9c86 BEFORE INSERT OR UPDATE ON ci_pipeline_messages FOR EACH ROW EXECUTE FUNCTION trigger_bfad0e2b9c86(); | ||||||
| 
 | 
 | ||||||
| CREATE TRIGGER trigger_c0353bbb6145 BEFORE INSERT OR UPDATE ON ci_namespace_monthly_usages FOR EACH ROW EXECUTE FUNCTION trigger_c0353bbb6145(); |  | ||||||
| 
 |  | ||||||
| CREATE TRIGGER trigger_delete_project_namespace_on_project_delete AFTER DELETE ON projects FOR EACH ROW WHEN ((old.project_namespace_id IS NOT NULL)) EXECUTE FUNCTION delete_associated_project_namespace(); | CREATE TRIGGER trigger_delete_project_namespace_on_project_delete AFTER DELETE ON projects FOR EACH ROW WHEN ((old.project_namespace_id IS NOT NULL)) EXECUTE FUNCTION delete_associated_project_namespace(); | ||||||
| 
 | 
 | ||||||
| CREATE TRIGGER trigger_has_external_issue_tracker_on_delete AFTER DELETE ON integrations FOR EACH ROW WHEN ((((old.category)::text = 'issue_tracker'::text) AND (old.active = true) AND (old.project_id IS NOT NULL))) EXECUTE FUNCTION set_has_external_issue_tracker(); | CREATE TRIGGER trigger_has_external_issue_tracker_on_delete AFTER DELETE ON integrations FOR EACH ROW WHEN ((((old.category)::text = 'issue_tracker'::text) AND (old.active = true) AND (old.project_id IS NOT NULL))) EXECUTE FUNCTION set_has_external_issue_tracker(); | ||||||
|  |  | ||||||
|  | @ -121,6 +121,7 @@ To install `agentk`: | ||||||
|    kind: Secret |    kind: Secret | ||||||
|    metadata: |    metadata: | ||||||
|      name: gitlab-agent-token |      name: gitlab-agent-token | ||||||
|  |      namespace: gitlab | ||||||
|    type: Opaque |    type: Opaque | ||||||
|    stringData: |    stringData: | ||||||
|       token: "<your-token-here>" |       token: "<your-token-here>" | ||||||
|  |  | ||||||
|  | @ -94,37 +94,6 @@ module API | ||||||
|       # rubocop: enable CodeReuse/ActiveRecord |       # rubocop: enable CodeReuse/ActiveRecord | ||||||
| 
 | 
 | ||||||
|       helpers do |       helpers do | ||||||
|         def commit |  | ||||||
|           strong_memoize(:commit) do |  | ||||||
|             user_project.commit(params[:sha]) |  | ||||||
|           end |  | ||||||
|         end |  | ||||||
| 
 |  | ||||||
|         def all_matching_pipelines |  | ||||||
|           pipelines = user_project.ci_pipelines.newest_first(sha: commit.sha) |  | ||||||
|           pipelines = pipelines.for_ref(params[:ref]) if params[:ref] |  | ||||||
|           pipelines = pipelines.id_in(params[:pipeline_id]) if params[:pipeline_id] |  | ||||||
|           pipelines |  | ||||||
|         end |  | ||||||
| 
 |  | ||||||
|         def apply_job_state!(job) |  | ||||||
|           case params[:state] |  | ||||||
|           when 'pending' |  | ||||||
|             job.enqueue! |  | ||||||
|           when 'running' |  | ||||||
|             job.enqueue |  | ||||||
|             job.run! |  | ||||||
|           when 'success' |  | ||||||
|             job.success! |  | ||||||
|           when 'failed' |  | ||||||
|             job.drop!(:api_failure) |  | ||||||
|           when 'canceled' |  | ||||||
|             job.cancel! |  | ||||||
|           else |  | ||||||
|             render_api_error!('invalid state', 400) |  | ||||||
|           end |  | ||||||
|         end |  | ||||||
| 
 |  | ||||||
|         def optional_commit_status_params |         def optional_commit_status_params | ||||||
|           updatable_optional_attributes = %w[target_url description coverage] |           updatable_optional_attributes = %w[target_url description coverage] | ||||||
|           attributes_for_keys(updatable_optional_attributes) |           attributes_for_keys(updatable_optional_attributes) | ||||||
|  |  | ||||||
|  | @ -3,7 +3,8 @@ | ||||||
| # This is a base controller for doorkeeper. | # This is a base controller for doorkeeper. | ||||||
| # It adds the `can?` helper used in the views. | # It adds the `can?` helper used in the views. | ||||||
| module Gitlab | module Gitlab | ||||||
|   class BaseDoorkeeperController < BaseActionController |   # rubocop:disable Rails/ApplicationController | ||||||
|  |   class BaseDoorkeeperController < ActionController::Base | ||||||
|     include Gitlab::Allowable |     include Gitlab::Allowable | ||||||
|     include EnforcesTwoFactorAuthentication |     include EnforcesTwoFactorAuthentication | ||||||
|     include SessionsHelper |     include SessionsHelper | ||||||
|  | @ -12,4 +13,5 @@ module Gitlab | ||||||
| 
 | 
 | ||||||
|     helper_method :can? |     helper_method :can? | ||||||
|   end |   end | ||||||
|  |   # rubocop:enable Rails/ApplicationController | ||||||
| end | end | ||||||
|  |  | ||||||
|  | @ -6,7 +6,8 @@ | ||||||
| 
 | 
 | ||||||
| module Gitlab | module Gitlab | ||||||
|   module RequestForgeryProtection |   module RequestForgeryProtection | ||||||
|     class Controller < BaseActionController |     # rubocop:disable Rails/ApplicationController | ||||||
|  |     class Controller < ActionController::Base | ||||||
|       protect_from_forgery with: :exception, prepend: true |       protect_from_forgery with: :exception, prepend: true | ||||||
| 
 | 
 | ||||||
|       def initialize |       def initialize | ||||||
|  | @ -39,5 +40,6 @@ module Gitlab | ||||||
|     rescue ActionController::InvalidAuthenticityToken |     rescue ActionController::InvalidAuthenticityToken | ||||||
|       false |       false | ||||||
|     end |     end | ||||||
|  |     # rubocop:enable Rails/ApplicationController | ||||||
|   end |   end | ||||||
| end | end | ||||||
|  |  | ||||||
|  | @ -24739,12 +24739,21 @@ msgstr "" | ||||||
| msgid "InProductMarketing|%{strong_start}GitLab Inc.%{strong_end} 268 Bush Street, #350, San Francisco, CA 94104, USA" | msgid "InProductMarketing|%{strong_start}GitLab Inc.%{strong_end} 268 Bush Street, #350, San Francisco, CA 94104, USA" | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
|  | msgid "InProductMarketing|%{upper_start}Start your 30-day free trial of%{upper_end} %{lower_start}GitLab Ultimate%{lower_end}" | ||||||
|  | msgstr "" | ||||||
|  | 
 | ||||||
|  | msgid "InProductMarketing|Accelerate your digital transform" | ||||||
|  | msgstr "" | ||||||
|  | 
 | ||||||
| msgid "InProductMarketing|Blog" | msgid "InProductMarketing|Blog" | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
| msgid "InProductMarketing|Built-in security" | msgid "InProductMarketing|Built-in security" | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
|  | msgid "InProductMarketing|Deliver software faster" | ||||||
|  | msgstr "" | ||||||
|  | 
 | ||||||
| msgid "InProductMarketing|Ensure compliance" | msgid "InProductMarketing|Ensure compliance" | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
|  | @ -24760,12 +24769,18 @@ msgstr "" | ||||||
| msgid "InProductMarketing|If you no longer wish to receive marketing emails from us," | msgid "InProductMarketing|If you no longer wish to receive marketing emails from us," | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
|  | msgid "InProductMarketing|Improve collaboration and visibility" | ||||||
|  | msgstr "" | ||||||
|  | 
 | ||||||
| msgid "InProductMarketing|Invite unlimited colleagues" | msgid "InProductMarketing|Invite unlimited colleagues" | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
| msgid "InProductMarketing|No credit card required" | msgid "InProductMarketing|No credit card required" | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
|  | msgid "InProductMarketing|No credit card required." | ||||||
|  | msgstr "" | ||||||
|  | 
 | ||||||
| msgid "InProductMarketing|Start a Self-Managed trial" | msgid "InProductMarketing|Start a Self-Managed trial" | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
|  | @ -33224,6 +33239,9 @@ msgstr "" | ||||||
| msgid "Options" | msgid "Options" | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
|  | msgid "Or create your own GitLab account:" | ||||||
|  | msgstr "" | ||||||
|  | 
 | ||||||
| msgid "Ordered list" | msgid "Ordered list" | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
|  | @ -42651,6 +42669,9 @@ msgstr "" | ||||||
| msgid "SecurityOrchestration|Branch types don't match any existing branches." | msgid "SecurityOrchestration|Branch types don't match any existing branches." | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
|  | msgid "SecurityOrchestration|Cannot create an empty policy" | ||||||
|  | msgstr "" | ||||||
|  | 
 | ||||||
| msgid "SecurityOrchestration|Choose a project" | msgid "SecurityOrchestration|Choose a project" | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
|  | @ -42726,6 +42747,9 @@ msgstr "" | ||||||
| msgid "SecurityOrchestration|Failed to load images." | msgid "SecurityOrchestration|Failed to load images." | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
|  | msgid "SecurityOrchestration|For any MR that matches this policy's rules, only the override project approval settings apply. No additional approvals are required." | ||||||
|  | msgstr "" | ||||||
|  | 
 | ||||||
| msgid "SecurityOrchestration|For any merge request on %{branches}%{commitType}%{branchExceptionsString}" | msgid "SecurityOrchestration|For any merge request on %{branches}%{commitType}%{branchExceptionsString}" | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
|  | @ -42806,6 +42830,9 @@ msgid_plural "SecurityOrchestration|On runners with the tags:" | ||||||
| msgstr[0] "" | msgstr[0] "" | ||||||
| msgstr[1] "" | msgstr[1] "" | ||||||
| 
 | 
 | ||||||
|  | msgid "SecurityOrchestration|Only overriding settings will take effect" | ||||||
|  | msgstr "" | ||||||
|  | 
 | ||||||
| msgid "SecurityOrchestration|Only owners can update Security Policy Project" | msgid "SecurityOrchestration|Only owners can update Security Policy Project" | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
|  | @ -42971,6 +42998,9 @@ msgstr "" | ||||||
| msgid "SecurityOrchestration|This is a project-level policy" | msgid "SecurityOrchestration|This is a project-level policy" | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
|  | msgid "SecurityOrchestration|This policy doesn't contain any actions or override project approval settings. You cannot create an empty policy." | ||||||
|  | msgstr "" | ||||||
|  | 
 | ||||||
| msgid "SecurityOrchestration|This policy is inherited" | msgid "SecurityOrchestration|This policy is inherited" | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
|  | @ -44720,6 +44750,9 @@ msgstr "" | ||||||
| msgid "Sign up" | msgid "Sign up" | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
|  | msgid "Sign up for your free trial with:" | ||||||
|  | msgstr "" | ||||||
|  | 
 | ||||||
| msgid "Sign up was successful! Please confirm your email to sign in." | msgid "Sign up was successful! Please confirm your email to sign in." | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -5,7 +5,7 @@ ENV GITLAB_LICENSE_MODE=test \ | ||||||
| 
 | 
 | ||||||
| # Clone GDK at specific sha and bootstrap packages | # Clone GDK at specific sha and bootstrap packages | ||||||
| # | # | ||||||
| ARG GDK_SHA=65cf4576208b9f79c54c0042c44024c0008deafc | ARG GDK_SHA=d843a4d237bbb9c2f04d2cbddc89fd6dadeb86cf | ||||||
| RUN set -eux; \ | RUN set -eux; \ | ||||||
|     git clone --depth 1 https://gitlab.com/gitlab-org/gitlab-development-kit.git && cd gitlab-development-kit; \ |     git clone --depth 1 https://gitlab.com/gitlab-org/gitlab-development-kit.git && cd gitlab-development-kit; \ | ||||||
|     git fetch --depth 1 origin ${GDK_SHA} && git -c advice.detachedHead=false checkout ${GDK_SHA}; \ |     git fetch --depth 1 origin ${GDK_SHA} && git -c advice.detachedHead=false checkout ${GDK_SHA}; \ | ||||||
|  |  | ||||||
|  | @ -4,7 +4,7 @@ module QA | ||||||
|   module Page |   module Page | ||||||
|     module Registration |     module Registration | ||||||
|       class SignUp < Page::Base |       class SignUp < Page::Base | ||||||
|         view 'app/views/devise/shared/_signup_box.html.haml' do |         view 'app/views/devise/shared/_signup_box_form.html.haml' do | ||||||
|           element 'new-user-first-name-field' |           element 'new-user-first-name-field' | ||||||
|           element 'new-user-last-name-field' |           element 'new-user-last-name-field' | ||||||
|           element 'new-user-email-field' |           element 'new-user-email-field' | ||||||
|  |  | ||||||
|  | @ -11,8 +11,11 @@ module QA | ||||||
|       # This *could* be different than the api_client.user or the api_user provided by the QA::Resource::ApiFabricator |       # This *could* be different than the api_client.user or the api_user provided by the QA::Resource::ApiFabricator | ||||||
|       attr_writer :user |       attr_writer :user | ||||||
| 
 | 
 | ||||||
|       attribute :id |       attributes :id, :token | ||||||
|       attribute :token | 
 | ||||||
|  |       attribute :expires_at do | ||||||
|  |         Time.now.utc.to_date + 2 | ||||||
|  |       end | ||||||
| 
 | 
 | ||||||
|       # Only Admins can create PAT via the API. |       # Only Admins can create PAT via the API. | ||||||
|       # If Runtime::Env.admin_personal_access_token is provided, fabricate via the API, |       # If Runtime::Env.admin_personal_access_token is provided, fabricate via the API, | ||||||
|  | @ -49,7 +52,7 @@ module QA | ||||||
|         api_client = Runtime::API::Client.new(:gitlab, |         api_client = Runtime::API::Client.new(:gitlab, | ||||||
|           is_new_session: false, |           is_new_session: false, | ||||||
|           user: user, |           user: user, | ||||||
|           personal_access_token: self.token) |           personal_access_token: token) | ||||||
|         request_url = Runtime::API::Request.new(api_client, |         request_url = Runtime::API::Request.new(api_client, | ||||||
|           "/personal_access_tokens?user_id=#{user.id}", |           "/personal_access_tokens?user_id=#{user.id}", | ||||||
|           per_page: '100').url |           per_page: '100').url | ||||||
|  | @ -88,12 +91,7 @@ module QA | ||||||
|       end |       end | ||||||
| 
 | 
 | ||||||
|       def cache_token |       def cache_token | ||||||
|         QA::Resource::PersonalAccessTokenCache.set_token_for_username(user.username, self.token) if @user && self.token |         QA::Resource::PersonalAccessTokenCache.set_token_for_username(user.username, token) if @user && token | ||||||
|       end |  | ||||||
| 
 |  | ||||||
|       # Expire in 2 days just in case the token is created just before midnight |  | ||||||
|       def expires_at |  | ||||||
|         @expires_at || Time.now.utc.to_date + 2 |  | ||||||
|       end |       end | ||||||
| 
 | 
 | ||||||
|       def fabricate! |       def fabricate! | ||||||
|  | @ -115,7 +113,7 @@ module QA | ||||||
| 
 | 
 | ||||||
|           cache_token |           cache_token | ||||||
| 
 | 
 | ||||||
|           self.token |           token | ||||||
|         end |         end | ||||||
|       end |       end | ||||||
|     end |     end | ||||||
|  |  | ||||||
|  | @ -18,6 +18,21 @@ module QA | ||||||
|       tags: { import_type: ENV["QA_IMPORT_TYPE"], import_repo: ENV["QA_LARGE_IMPORT_REPO"] || "rspec/rspec-core" } |       tags: { import_type: ENV["QA_IMPORT_TYPE"], import_repo: ENV["QA_LARGE_IMPORT_REPO"] || "rspec/rspec-core" } | ||||||
|     } do |     } do | ||||||
|     describe 'Project import', product_group: :import_and_integrate do # rubocop:disable RSpec/MultipleMemoizedHelpers |     describe 'Project import', product_group: :import_and_integrate do # rubocop:disable RSpec/MultipleMemoizedHelpers | ||||||
|  |       let!(:api_client) { Runtime::API::Client.as_admin } | ||||||
|  |       let!(:user) { create(:user, api_client: api_client) } | ||||||
|  |       let!(:user_api_client) do | ||||||
|  |         Runtime::API::Client.new( | ||||||
|  |           user: user, | ||||||
|  |           is_new_session: false, | ||||||
|  |           personal_access_token: Resource::PersonalAccessToken.fabricate_via_api! do |pat| | ||||||
|  |             pat.user = user | ||||||
|  |             # importing very large project can take multiple days | ||||||
|  |             # token must not expire while we still poll for import result | ||||||
|  |             pat.expires_at = (Time.now.to_date + 5) | ||||||
|  |           end.token | ||||||
|  |         ) | ||||||
|  |       end | ||||||
|  | 
 | ||||||
|       # Full object comparison is a fairly heavy operation |       # Full object comparison is a fairly heavy operation | ||||||
|       # Importer itself returns counts of objects it fetched and counts it imported |       # Importer itself returns counts of objects it fetched and counts it imported | ||||||
|       # We can use that for a lightweight comparison for very large projects |       # We can use that for a lightweight comparison for very large projects | ||||||
|  | @ -103,10 +118,6 @@ module QA | ||||||
|         ] |         ] | ||||||
|       end |       end | ||||||
| 
 | 
 | ||||||
|       let(:api_client) { Runtime::API::Client.as_admin } |  | ||||||
| 
 |  | ||||||
|       let(:user) { create(:user, api_client: api_client) } |  | ||||||
| 
 |  | ||||||
|       let(:github_client) do |       let(:github_client) do | ||||||
|         Octokit::Client.new( |         Octokit::Client.new( | ||||||
|           access_token: ENV['QA_LARGE_IMPORT_GH_TOKEN'] || Runtime::Env.github_access_token, |           access_token: ENV['QA_LARGE_IMPORT_GH_TOKEN'] || Runtime::Env.github_access_token, | ||||||
|  |  | ||||||
|  | @ -1,7 +1,7 @@ | ||||||
| # frozen_string_literal: true | # frozen_string_literal: true | ||||||
| 
 | 
 | ||||||
| module RuboCop | module RuboCop | ||||||
|   class BatchedBackgroundMigrations |   class BatchedBackgroundMigrationsDictionary | ||||||
|     DICTIONARY_BASE_DIR = 'db/docs/batched_background_migrations' |     DICTIONARY_BASE_DIR = 'db/docs/batched_background_migrations' | ||||||
| 
 | 
 | ||||||
|     attr_reader :queued_migration_version |     attr_reader :queued_migration_version | ||||||
|  | @ -14,6 +14,7 @@ module RuboCop | ||||||
|           next unless dictionary['queued_migration_version'].present? |           next unless dictionary['queued_migration_version'].present? | ||||||
| 
 | 
 | ||||||
|           data[dictionary['queued_migration_version'].to_s] = { |           data[dictionary['queued_migration_version'].to_s] = { | ||||||
|  |             introduced_by_url: dictionary['introduced_by_url'], | ||||||
|             finalize_after: dictionary['finalize_after'], |             finalize_after: dictionary['finalize_after'], | ||||||
|             finalized_by: dictionary['finalized_by'].to_s |             finalized_by: dictionary['finalized_by'].to_s | ||||||
|           } |           } | ||||||
|  | @ -26,7 +27,21 @@ module RuboCop | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     def finalized_by |     def finalized_by | ||||||
|       self.class.dictionary_data.dig(queued_migration_version.to_s, :finalized_by) |       dictionary_data&.dig(:finalized_by) | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     def finalize_after | ||||||
|  |       dictionary_data&.dig(:finalize_after) | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     def introduced_by_url | ||||||
|  |       dictionary_data&.dig(:introduced_by_url) | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     private | ||||||
|  | 
 | ||||||
|  |     def dictionary_data | ||||||
|  |       @dictionary_data ||= self.class.dictionary_data[queued_migration_version.to_s] | ||||||
|     end |     end | ||||||
|   end |   end | ||||||
| end | end | ||||||
|  | @ -1,17 +1,23 @@ | ||||||
| # frozen_string_literal: true | # frozen_string_literal: true | ||||||
| 
 | 
 | ||||||
| require_relative '../../migration_helpers' | require_relative '../../migration_helpers' | ||||||
|  | require_relative '../../batched_background_migrations_dictionary' | ||||||
| 
 | 
 | ||||||
| module RuboCop | module RuboCop | ||||||
|   module Cop |   module Cop | ||||||
|     module BackgroundMigration |     module BackgroundMigration | ||||||
|       # Checks the batched background migration has the corresponding dictionary file |       # Checks the batched background migration has the corresponding dictionary file | ||||||
|       class MissingDictionaryFile < RuboCop::Cop::Base |       class DictionaryFile < RuboCop::Cop::Base | ||||||
|         include MigrationHelpers |         include MigrationHelpers | ||||||
| 
 | 
 | ||||||
|         MSG = "Missing %{file_name}. " \ |         MSG = { | ||||||
|               "Use the generator 'batched_background_migration' to create dictionary files automatically. " \ |           missing_key: "Mandatory key '%{key}' is missing from the dictionary. Please add with an appropriate value.", | ||||||
|               "For more details refer: https://docs.gitlab.com/ee/development/database/batched_background_migrations.html#generator" |           missing_dictionary: <<-MESSAGE.delete("\n").squeeze(' ').strip | ||||||
|  |             Missing %{file_name}. | ||||||
|  |             Use the generator 'batched_background_migration' to create dictionary files automatically. | ||||||
|  |             For more details refer: https://docs.gitlab.com/ee/development/database/batched_background_migrations.html#generator | ||||||
|  |           MESSAGE | ||||||
|  |         }.freeze | ||||||
| 
 | 
 | ||||||
|         DICTIONARY_DIR = "db/docs/batched_background_migrations" |         DICTIONARY_DIR = "db/docs/batched_background_migrations" | ||||||
| 
 | 
 | ||||||
|  | @ -35,9 +41,10 @@ module RuboCop | ||||||
|                              migration_name_node.value |                              migration_name_node.value | ||||||
|                            end |                            end | ||||||
| 
 | 
 | ||||||
|           return if dictionary_file?(migration_name) |           error_code, msg_params = validate_dictionary_file(migration_name, node) | ||||||
|  |           return unless error_code.present? | ||||||
| 
 | 
 | ||||||
|           add_offense(node, message: format(MSG, file_name: dictionary_file_path(migration_name))) |           add_offense(node, message: format(MSG[error_code], msg_params)) | ||||||
|         end |         end | ||||||
| 
 | 
 | ||||||
|         private |         private | ||||||
|  | @ -50,6 +57,18 @@ module RuboCop | ||||||
|           File.join(rails_root, DICTIONARY_DIR, "#{migration_class_name.underscore}.yml") |           File.join(rails_root, DICTIONARY_DIR, "#{migration_class_name.underscore}.yml") | ||||||
|         end |         end | ||||||
| 
 | 
 | ||||||
|  |         def validate_dictionary_file(migration_name, node) | ||||||
|  |           unless dictionary_file?(migration_name) | ||||||
|  |             return [:missing_dictionary, { file_name: dictionary_file_path(migration_name) }] | ||||||
|  |           end | ||||||
|  | 
 | ||||||
|  |           bbm_dictionary = RuboCop::BatchedBackgroundMigrationsDictionary.new(version(node)) | ||||||
|  | 
 | ||||||
|  |           return [:missing_key, { key: :finalize_after }] unless bbm_dictionary.finalize_after.present? | ||||||
|  | 
 | ||||||
|  |           return [:missing_key, { key: :introduced_by_url }] unless bbm_dictionary.introduced_by_url.present? | ||||||
|  |         end | ||||||
|  | 
 | ||||||
|         def rails_root |         def rails_root | ||||||
|           @rails_root ||= File.expand_path('../../..', __dir__) |           @rails_root ||= File.expand_path('../../..', __dir__) | ||||||
|         end |         end | ||||||
|  | @ -1,7 +1,7 @@ | ||||||
| # frozen_string_literal: true | # frozen_string_literal: true | ||||||
| 
 | 
 | ||||||
| require_relative '../../migration_helpers' | require_relative '../../migration_helpers' | ||||||
| require_relative '../../batched_background_migrations' | require_relative '../../batched_background_migrations_dictionary' | ||||||
| 
 | 
 | ||||||
| module RuboCop | module RuboCop | ||||||
|   module Cop |   module Cop | ||||||
|  | @ -43,7 +43,7 @@ module RuboCop | ||||||
|         private |         private | ||||||
| 
 | 
 | ||||||
|         def fetch_finalized_by(queued_migration_version) |         def fetch_finalized_by(queued_migration_version) | ||||||
|           BatchedBackgroundMigrations.new(queued_migration_version).finalized_by |           BatchedBackgroundMigrationsDictionary.new(queued_migration_version).finalized_by | ||||||
|         end |         end | ||||||
|       end |       end | ||||||
|     end |     end | ||||||
|  |  | ||||||
|  | @ -1,9 +0,0 @@ | ||||||
| # frozen_string_literal: true |  | ||||||
| 
 |  | ||||||
| require 'spec_helper' |  | ||||||
| 
 |  | ||||||
| RSpec.describe AcmeChallengesController, type: :request, feature_category: :pages do |  | ||||||
|   it_behaves_like 'Base action controller' do |  | ||||||
|     subject(:request) { get acme_challenge_path } |  | ||||||
|   end |  | ||||||
| end |  | ||||||
|  | @ -1,15 +0,0 @@ | ||||||
| # frozen_string_literal: true |  | ||||||
| 
 |  | ||||||
| require 'spec_helper' |  | ||||||
| 
 |  | ||||||
| RSpec.describe ApplicationController, type: :request, feature_category: :shared do |  | ||||||
|   let_it_be(:user) { create(:user) } |  | ||||||
| 
 |  | ||||||
|   before do |  | ||||||
|     sign_in(user) |  | ||||||
|   end |  | ||||||
| 
 |  | ||||||
|   it_behaves_like 'Base action controller' do |  | ||||||
|     subject(:request) { get root_path } |  | ||||||
|   end |  | ||||||
| end |  | ||||||
|  | @ -1,14 +0,0 @@ | ||||||
| # frozen_string_literal: true |  | ||||||
| 
 |  | ||||||
| require 'spec_helper' |  | ||||||
| 
 |  | ||||||
| RSpec.describe ChaosController, type: :request, feature_category: :tooling do |  | ||||||
|   it_behaves_like 'Base action controller' do |  | ||||||
|     before do |  | ||||||
|       # Stub leak_mem so we don't actually leak memory for the base action controller tests. |  | ||||||
|       allow(Gitlab::Chaos).to receive(:leak_mem).with(100, 30.seconds) |  | ||||||
|     end |  | ||||||
| 
 |  | ||||||
|     subject(:request) { get leakmem_chaos_path } |  | ||||||
|   end |  | ||||||
| end |  | ||||||
|  | @ -73,9 +73,7 @@ RSpec.describe HealthController, feature_category: :database do | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   describe 'GET /-/readiness' do |   describe 'GET /-/readiness' do | ||||||
|     subject(:request) { get readiness_path, params: params, headers: headers } |     subject { get '/-/readiness', params: params, headers: headers } | ||||||
| 
 |  | ||||||
|     it_behaves_like 'Base action controller' |  | ||||||
| 
 | 
 | ||||||
|     shared_context 'endpoint responding with readiness data' do |     shared_context 'endpoint responding with readiness data' do | ||||||
|       context 'when requesting instance-checks' do |       context 'when requesting instance-checks' do | ||||||
|  |  | ||||||
|  | @ -1,9 +0,0 @@ | ||||||
| # frozen_string_literal: true |  | ||||||
| 
 |  | ||||||
| require 'spec_helper' |  | ||||||
| 
 |  | ||||||
| RSpec.describe MetricsController, type: :request, feature_category: :metrics do |  | ||||||
|   it_behaves_like 'Base action controller' do |  | ||||||
|     subject(:request) { get metrics_path } |  | ||||||
|   end |  | ||||||
| end |  | ||||||
|  | @ -20,10 +20,6 @@ RSpec.describe Oauth::AuthorizationsController, feature_category: :system_access | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   describe 'GET #new' do |   describe 'GET #new' do | ||||||
|     it_behaves_like 'Base action controller' do |  | ||||||
|       subject(:request) { get oauth_authorization_path } |  | ||||||
|     end |  | ||||||
| 
 |  | ||||||
|     context 'when application redirect URI has a custom scheme' do |     context 'when application redirect URI has a custom scheme' do | ||||||
|       context 'when CSP is disabled' do |       context 'when CSP is disabled' do | ||||||
|         before do |         before do | ||||||
|  |  | ||||||
|  | @ -6,9 +6,7 @@ RSpec.describe RegistrationsController, type: :request, feature_category: :syste | ||||||
|   describe 'POST #create' do |   describe 'POST #create' do | ||||||
|     let_it_be(:user_attrs) { build_stubbed(:user).slice(:first_name, :last_name, :username, :email, :password) } |     let_it_be(:user_attrs) { build_stubbed(:user).slice(:first_name, :last_name, :username, :email, :password) } | ||||||
| 
 | 
 | ||||||
|     subject(:request) { post user_registration_path, params: { user: user_attrs } } |     subject(:create_user) { post user_registration_path, params: { user: user_attrs } } | ||||||
| 
 |  | ||||||
|     it_behaves_like 'Base action controller' |  | ||||||
| 
 | 
 | ||||||
|     context 'when email confirmation is required' do |     context 'when email confirmation is required' do | ||||||
|       before do |       before do | ||||||
|  | @ -17,7 +15,7 @@ RSpec.describe RegistrationsController, type: :request, feature_category: :syste | ||||||
|       end |       end | ||||||
| 
 | 
 | ||||||
|       it 'redirects to the `users_almost_there_path`', unless: Gitlab.ee? do |       it 'redirects to the `users_almost_there_path`', unless: Gitlab.ee? do | ||||||
|         request |         create_user | ||||||
| 
 | 
 | ||||||
|         expect(response).to redirect_to(users_almost_there_path(email: user_attrs[:email])) |         expect(response).to redirect_to(users_almost_there_path(email: user_attrs[:email])) | ||||||
|       end |       end | ||||||
|  |  | ||||||
|  | @ -7,10 +7,6 @@ RSpec.describe 'Sessions', feature_category: :system_access do | ||||||
| 
 | 
 | ||||||
|   let(:user) { create(:user) } |   let(:user) { create(:user) } | ||||||
| 
 | 
 | ||||||
|   it_behaves_like 'Base action controller' do |  | ||||||
|     subject(:request) { get new_user_session_path } |  | ||||||
|   end |  | ||||||
| 
 |  | ||||||
|   context 'for authentication', :allow_forgery_protection do |   context 'for authentication', :allow_forgery_protection do | ||||||
|     it 'logout does not require a csrf token' do |     it 'logout does not require a csrf token' do | ||||||
|       login_as(user) |       login_as(user) | ||||||
|  |  | ||||||
|  | @ -2,20 +2,24 @@ | ||||||
| 
 | 
 | ||||||
| require 'rubocop_spec_helper' | require 'rubocop_spec_helper' | ||||||
| 
 | 
 | ||||||
| require_relative '../../rubocop/batched_background_migrations' | require_relative '../../rubocop/batched_background_migrations_dictionary' | ||||||
| 
 | 
 | ||||||
| RSpec.describe RuboCop::BatchedBackgroundMigrations, feature_category: :database do | RSpec.describe RuboCop::BatchedBackgroundMigrationsDictionary, feature_category: :database do | ||||||
|   let(:bbm_dictionary_file_name) { "#{described_class::DICTIONARY_BASE_DIR}/test_migration.yml" } |   let(:bbm_dictionary_file_name) { "#{described_class::DICTIONARY_BASE_DIR}/test_migration.yml" } | ||||||
|   let(:migration_version) { 20230307160250 } |   let(:migration_version) { 20230307160250 } | ||||||
|   let(:finalized_by_version) { 20230307160255 } |   let(:finalized_by_version) { 20230307160255 } | ||||||
|  |   let(:introduced_by_url) { 'https://test_url' } | ||||||
|  |   let(:finalize_after) { '202312011212' } | ||||||
|  | 
 | ||||||
|   let(:bbm_dictionary_data) do |   let(:bbm_dictionary_data) do | ||||||
|     { |     { | ||||||
|       migration_job_name: 'TestMigration', |       migration_job_name: 'TestMigration', | ||||||
|       feature_category: :database, |       feature_category: :database, | ||||||
|       introduced_by_url: 'https://test_url', |       introduced_by_url: introduced_by_url, | ||||||
|       milestone: 16.5, |       milestone: 16.5, | ||||||
|       queued_migration_version: migration_version, |       queued_migration_version: migration_version, | ||||||
|       finalized_by: finalized_by_version |       finalized_by: finalized_by_version, | ||||||
|  |       finalize_after: finalize_after | ||||||
|     } |     } | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|  | @ -40,4 +44,24 @@ RSpec.describe RuboCop::BatchedBackgroundMigrations, feature_category: :database | ||||||
|       expect(described_class.new('random').finalized_by).to be_nil |       expect(described_class.new('random').finalized_by).to be_nil | ||||||
|     end |     end | ||||||
|   end |   end | ||||||
|  | 
 | ||||||
|  |   describe '#introduced_by_url' do | ||||||
|  |     it 'returns the introduced_by_url of the bbm with given version' do | ||||||
|  |       expect(batched_background_migration.introduced_by_url).to eq(introduced_by_url) | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     it 'returns nothing for non-existing bbm dictionary' do | ||||||
|  |       expect(described_class.new('random').introduced_by_url).to be_nil | ||||||
|  |     end | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   describe '#finalize_after' do | ||||||
|  |     it 'returns the finalize_after timestamp of the bbm with given version' do | ||||||
|  |       expect(batched_background_migration.finalize_after).to eq(finalize_after) | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     it 'returns nothing for non-existing bbm dictionary' do | ||||||
|  |       expect(described_class.new('random').finalize_after).to be_nil | ||||||
|  |     end | ||||||
|  |   end | ||||||
| end | end | ||||||
|  | @ -1,17 +1,36 @@ | ||||||
| # frozen_string_literal: true | # frozen_string_literal: true | ||||||
| 
 | 
 | ||||||
| require 'rubocop_spec_helper' | require 'rubocop_spec_helper' | ||||||
| require_relative '../../../../rubocop/cop/background_migration/missing_dictionary_file' | require_relative '../../../../rubocop/cop/background_migration/dictionary_file' | ||||||
| 
 | 
 | ||||||
| RSpec.describe RuboCop::Cop::BackgroundMigration::MissingDictionaryFile, feature_category: :database do | RSpec.describe RuboCop::Cop::BackgroundMigration::DictionaryFile, feature_category: :database do | ||||||
|   let(:config) do |   let(:config) do | ||||||
|     RuboCop::Config.new( |     RuboCop::Config.new( | ||||||
|       'BackgroundMigration/MissingDictionaryFile' => { |       'BackgroundMigration/DictionaryFile' => { | ||||||
|         'EnforcedSince' => 20230307160251 |         'EnforcedSince' => 20231018100907 | ||||||
|       } |       } | ||||||
|     ) |     ) | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|  |   shared_examples 'migration with missing dictionary keys offense' do |missing_key| | ||||||
|  |     it 'registers an offense' do | ||||||
|  |       expect_offense(<<~RUBY) | ||||||
|  |         class QueueMyMigration < Gitlab::Database::Migration[2.1] | ||||||
|  |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ #{format(described_class::MSG[:missing_key], key: missing_key)} | ||||||
|  |           MIGRATION = 'MyMigration' | ||||||
|  | 
 | ||||||
|  |           def up | ||||||
|  |             queue_batched_background_migration( | ||||||
|  |               MIGRATION, | ||||||
|  |               :users, | ||||||
|  |               :id | ||||||
|  |             ) | ||||||
|  |           end | ||||||
|  |         end | ||||||
|  |       RUBY | ||||||
|  |     end | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|   context 'for non post migrations' do |   context 'for non post migrations' do | ||||||
|     before do |     before do | ||||||
|       allow(cop).to receive(:in_post_deployment_migration?).and_return(false) |       allow(cop).to receive(:in_post_deployment_migration?).and_return(false) | ||||||
|  | @ -57,7 +76,7 @@ RSpec.describe RuboCop::Cop::BackgroundMigration::MissingDictionaryFile, feature | ||||||
| 
 | 
 | ||||||
|       context 'for migrations before enforced time' do |       context 'for migrations before enforced time' do | ||||||
|         before do |         before do | ||||||
|           allow(cop).to receive(:version).and_return(20230307160250) |           allow(cop).to receive(:version).and_return(20230918100907) | ||||||
|         end |         end | ||||||
| 
 | 
 | ||||||
|         it 'does not throw any offenses' do |         it 'does not throw any offenses' do | ||||||
|  | @ -79,7 +98,7 @@ RSpec.describe RuboCop::Cop::BackgroundMigration::MissingDictionaryFile, feature | ||||||
| 
 | 
 | ||||||
|       context 'for migrations after enforced time' do |       context 'for migrations after enforced time' do | ||||||
|         before do |         before do | ||||||
|           allow(cop).to receive(:version).and_return(20230307160252) |           allow(cop).to receive(:version).and_return(20231118100907) | ||||||
|         end |         end | ||||||
| 
 | 
 | ||||||
|         it 'throws offense on not having the appropriate dictionary file with migration name as a constant' do |         it 'throws offense on not having the appropriate dictionary file with migration name as a constant' do | ||||||
|  | @ -114,22 +133,48 @@ RSpec.describe RuboCop::Cop::BackgroundMigration::MissingDictionaryFile, feature | ||||||
|           RUBY |           RUBY | ||||||
|         end |         end | ||||||
| 
 | 
 | ||||||
|         it 'does not throw offense with appropriate dictionary file' do |         context 'with dictionary file' do | ||||||
|           expect(File).to receive(:exist?).with(dictionary_file_path).and_return(true) |           let(:introduced_by_url) { 'https://test_url' } | ||||||
|  |           let(:finalize_after) { '20230507160251' } | ||||||
| 
 | 
 | ||||||
|           expect_no_offenses(<<~RUBY) |           before do | ||||||
|             class QueueMyMigration < Gitlab::Database::Migration[2.1] |             allow(File).to receive(:exist?).with(dictionary_file_path).and_return(true) | ||||||
|               MIGRATION = 'MyMigration' |  | ||||||
| 
 | 
 | ||||||
|               def up |             allow_next_instance_of(RuboCop::BatchedBackgroundMigrationsDictionary) do |dictionary| | ||||||
|                 queue_batched_background_migration( |               allow(dictionary).to receive(:finalize_after).and_return(finalize_after) | ||||||
|                   MIGRATION, |               allow(dictionary).to receive(:introduced_by_url).and_return(introduced_by_url) | ||||||
|                   :users, |  | ||||||
|                   :id |  | ||||||
|                 ) |  | ||||||
|               end |  | ||||||
|             end |             end | ||||||
|           RUBY |           end | ||||||
|  | 
 | ||||||
|  |           context 'without introduced_by_url' do | ||||||
|  |             it_behaves_like 'migration with missing dictionary keys offense', :introduced_by_url do | ||||||
|  |               let(:introduced_by_url) { nil } | ||||||
|  |             end | ||||||
|  |           end | ||||||
|  | 
 | ||||||
|  |           context 'without finalize_after' do | ||||||
|  |             it_behaves_like 'migration with missing dictionary keys offense', :finalize_after do | ||||||
|  |               let(:finalize_after) { nil } | ||||||
|  |             end | ||||||
|  |           end | ||||||
|  | 
 | ||||||
|  |           context 'with required dictionary keys' do | ||||||
|  |             it 'does not throw offense with appropriate dictionary file' do | ||||||
|  |               expect_no_offenses(<<~RUBY) | ||||||
|  |                 class QueueMyMigration < Gitlab::Database::Migration[2.1] | ||||||
|  |                   MIGRATION = 'MyMigration' | ||||||
|  | 
 | ||||||
|  |                   def up | ||||||
|  |                     queue_batched_background_migration( | ||||||
|  |                       MIGRATION, | ||||||
|  |                       :users, | ||||||
|  |                       :id | ||||||
|  |                     ) | ||||||
|  |                   end | ||||||
|  |                 end | ||||||
|  |               RUBY | ||||||
|  |             end | ||||||
|  |           end | ||||||
|         end |         end | ||||||
|       end |       end | ||||||
|     end |     end | ||||||
|  | @ -99,7 +99,7 @@ RSpec.describe RuboCop::Cop::Migration::UnfinishedDependencies, feature_category | ||||||
| 
 | 
 | ||||||
|     context 'with properly finalized dependent background migrations' do |     context 'with properly finalized dependent background migrations' do | ||||||
|       before do |       before do | ||||||
|         allow_next_instance_of(RuboCop::BatchedBackgroundMigrations) do |bbms| |         allow_next_instance_of(RuboCop::BatchedBackgroundMigrationsDictionary) do |bbms| | ||||||
|           allow(bbms).to receive(:finalized_by).and_return(version - 5) |           allow(bbms).to receive(:finalized_by).and_return(version - 5) | ||||||
|         end |         end | ||||||
|       end |       end | ||||||
|  |  | ||||||
|  | @ -6,9 +6,6 @@ abuse_reports: | ||||||
| alert_management_http_integrations: | alert_management_http_integrations: | ||||||
|   index_http_integrations_on_project_and_endpoint: |   index_http_integrations_on_project_and_endpoint: | ||||||
|   - index_alert_management_http_integrations_on_project_id |   - index_alert_management_http_integrations_on_project_id | ||||||
| analytics_cycle_analytics_group_stages: |  | ||||||
|   index_group_stages_on_group_id_group_value_stream_id_and_name: |  | ||||||
|   - index_analytics_ca_group_stages_on_group_id |  | ||||||
| approval_project_rules_users: | approval_project_rules_users: | ||||||
|   index_approval_project_rules_users_1: |   index_approval_project_rules_users_1: | ||||||
|   - index_approval_project_rules_users_on_approval_project_rule_id |   - index_approval_project_rules_users_on_approval_project_rule_id | ||||||
|  | @ -111,9 +108,6 @@ members: | ||||||
| merge_request_assignees: | merge_request_assignees: | ||||||
|   index_merge_request_assignees_on_merge_request_id_and_user_id: |   index_merge_request_assignees_on_merge_request_id_and_user_id: | ||||||
|   - index_merge_request_assignees_on_merge_request_id |   - index_merge_request_assignees_on_merge_request_id | ||||||
| merge_request_metrics: |  | ||||||
|   index_mr_metrics_on_target_project_id_merged_at_nulls_last: |  | ||||||
|   - index_merge_request_metrics_on_target_project_id |  | ||||||
| merge_requests: | merge_requests: | ||||||
|   index_merge_requests_on_author_id_and_created_at: |   index_merge_requests_on_author_id_and_created_at: | ||||||
|   - index_merge_requests_on_author_id |   - index_merge_requests_on_author_id | ||||||
|  |  | ||||||
|  | @ -1,26 +0,0 @@ | ||||||
| # frozen_string_literal: true |  | ||||||
| 
 |  | ||||||
| # Requires `request` subject to be defined |  | ||||||
| # |  | ||||||
| # subject(:request) { get root_path } |  | ||||||
| RSpec.shared_examples 'Base action controller' do |  | ||||||
|   describe 'security headers' do |  | ||||||
|     describe 'Cross-Origin-Opener-Policy' do |  | ||||||
|       it 'sets the header' do |  | ||||||
|         request |  | ||||||
| 
 |  | ||||||
|         expect(response.headers['Cross-Origin-Opener-Policy']).to eq('same-origin') |  | ||||||
|       end |  | ||||||
| 
 |  | ||||||
|       context 'when coop_header feature flag is disabled' do |  | ||||||
|         it 'does not set the header' do |  | ||||||
|           stub_feature_flags(coop_header: false) |  | ||||||
| 
 |  | ||||||
|           request |  | ||||||
| 
 |  | ||||||
|           expect(response.headers['Cross-Origin-Opener-Policy']).to be_nil |  | ||||||
|         end |  | ||||||
|       end |  | ||||||
|     end |  | ||||||
|   end |  | ||||||
| end |  | ||||||
		Loading…
	
		Reference in New Issue