Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
		
							parent
							
								
									75d101a1c2
								
							
						
					
					
						commit
						dcd01617a7
					
				|  | @ -110,7 +110,6 @@ Layout/LineContinuationSpacing: | |||
|     - 'ee/spec/services/phone_verification/telesign_client/send_verification_code_service_spec.rb' | ||||
|     - 'ee/spec/services/phone_verification/users/send_verification_code_service_spec.rb' | ||||
|     - 'ee/spec/services/security/security_orchestration_policies/ci_configuration_service_spec.rb' | ||||
|     - 'ee/spec/services/security/security_orchestration_policies/legacy_ci_configuration_service_spec.rb' | ||||
|     - 'ee/spec/views/compliance_management/compliance_framework/_project_settings.html.haml_spec.rb' | ||||
|     - 'ee/spec/workers/ee/issuable_export_csv_worker_spec.rb' | ||||
|     - 'lib/api/dependency_proxy.rb' | ||||
|  |  | |||
|  | @ -1,5 +1,4 @@ | |||
| import { flatten } from 'lodash'; | ||||
| import { hideFlash } from '~/flash'; | ||||
| import dateFormat from '~/lib/dateformat'; | ||||
| import { slugify } from '~/lib/utils/text_utility'; | ||||
| import { urlQueryToFilter } from '~/vue_shared/components/filtered_search_bar/filtered_search_utils'; | ||||
|  | @ -74,10 +73,8 @@ export const getDataZoomOption = ({ | |||
| }; | ||||
| 
 | ||||
| export const removeFlash = (type = 'alert') => { | ||||
|   const flashEl = document.querySelector(`.flash-${type}`); | ||||
|   if (flashEl) { | ||||
|     hideFlash(flashEl); | ||||
|   } | ||||
|   // flash-warning don't have dismiss button.
 | ||||
|   document.querySelector(`.flash-${type} .js-close`)?.click(); | ||||
| }; | ||||
| 
 | ||||
| /** | ||||
|  |  | |||
|  | @ -1,5 +1,5 @@ | |||
| import $ from 'jquery'; | ||||
| import { createAlert, hideFlash } from './flash'; | ||||
| import { createAlert } from './flash'; | ||||
| import axios from './lib/utils/axios_utils'; | ||||
| import { parseBoolean } from './lib/utils/common_utils'; | ||||
| import { __ } from './locale'; | ||||
|  | @ -18,7 +18,7 @@ export default () => { | |||
|     }; | ||||
| 
 | ||||
|     const hideConsentMessage = () => | ||||
|       hideFlash(document.querySelector('.service-ping-consent-message')); | ||||
|       document.querySelector('.service-ping-consent-message .js-close')?.click(); | ||||
| 
 | ||||
|     axios | ||||
|       .put(url, data) | ||||
|  |  | |||
|  | @ -139,9 +139,11 @@ export default { | |||
|         this.fetchingApprovals = false; | ||||
|       }) | ||||
|       .catch(() => | ||||
|         this.alerts.push( | ||||
|           createAlert({ | ||||
|             message: FETCH_ERROR, | ||||
|           }), | ||||
|         ), | ||||
|       ); | ||||
|   }, | ||||
|   methods: { | ||||
|  | @ -154,9 +156,11 @@ export default { | |||
|       this.updateApproval( | ||||
|         () => this.service.approveMergeRequest(), | ||||
|         () => | ||||
|           this.alerts.push( | ||||
|             createAlert({ | ||||
|               message: APPROVE_ERROR, | ||||
|             }), | ||||
|           ), | ||||
|       ); | ||||
|     }, | ||||
|     approveWithAuth(data) { | ||||
|  | @ -167,9 +171,11 @@ export default { | |||
|             this.hasApprovalAuthError = true; | ||||
|             return; | ||||
|           } | ||||
|           this.alerts.push( | ||||
|             createAlert({ | ||||
|               message: APPROVE_ERROR, | ||||
|           }); | ||||
|             }), | ||||
|           ); | ||||
|         }, | ||||
|       ); | ||||
|     }, | ||||
|  | @ -177,9 +183,11 @@ export default { | |||
|       this.updateApproval( | ||||
|         () => this.service.unapproveMergeRequest(), | ||||
|         () => | ||||
|           this.alerts.push( | ||||
|             createAlert({ | ||||
|               message: UNAPPROVE_ERROR, | ||||
|             }), | ||||
|           ), | ||||
|       ); | ||||
|     }, | ||||
|     updateApproval(serviceFn, errFn) { | ||||
|  |  | |||
|  | @ -1,14 +1,15 @@ | |||
| import { hideFlash } from '~/flash'; | ||||
| 
 | ||||
| export default { | ||||
|   data() { | ||||
|     return { | ||||
|       alerts: [], | ||||
|     }; | ||||
|   }, | ||||
|   methods: { | ||||
|     clearError() { | ||||
|       this.$emit('clearError'); | ||||
|       this.hasApprovalAuthError = false; | ||||
|       const flashEl = document.querySelector('.flash-alert'); | ||||
|       if (flashEl) { | ||||
|         hideFlash(flashEl); | ||||
|       } | ||||
|       this.alerts.forEach((alert) => alert.dismiss()); | ||||
|       this.alerts = []; | ||||
|     }, | ||||
|     refreshApprovals() { | ||||
|       return this.service.fetchApprovals().then((data) => { | ||||
|  |  | |||
|  | @ -68,8 +68,10 @@ class Admin::ApplicationSettings::AppearancesController < Admin::ApplicationCont | |||
|   def allowed_appearance_params | ||||
|     %i[ | ||||
|       title | ||||
|       pwa_short_name | ||||
|       description | ||||
|       pwa_name | ||||
|       pwa_short_name | ||||
|       pwa_description | ||||
|       logo | ||||
|       logo_cache | ||||
|       header_logo | ||||
|  |  | |||
|  | @ -29,28 +29,6 @@ class Admin::RunnersController < Admin::ApplicationController | |||
|     end | ||||
|   end | ||||
| 
 | ||||
|   def destroy | ||||
|     Ci::Runners::UnregisterRunnerService.new(@runner, current_user).execute | ||||
| 
 | ||||
|     redirect_to admin_runners_path, status: :found | ||||
|   end | ||||
| 
 | ||||
|   def resume | ||||
|     if Ci::Runners::UpdateRunnerService.new(@runner).execute(active: true).success? | ||||
|       redirect_to admin_runners_path, notice: _('Runner was successfully updated.') | ||||
|     else | ||||
|       redirect_to admin_runners_path, alert: _('Runner was not updated.') | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   def pause | ||||
|     if Ci::Runners::UpdateRunnerService.new(@runner).execute(active: false).success? | ||||
|       redirect_to admin_runners_path, notice: _('Runner was successfully updated.') | ||||
|     else | ||||
|       redirect_to admin_runners_path, alert: _('Runner was not updated.') | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   def tag_list | ||||
|     tags = Autocomplete::ActsAsTaggableOn::TagsFinder.new(params: params).execute | ||||
| 
 | ||||
|  |  | |||
|  | @ -9,8 +9,6 @@ class Groups::RunnersController < Groups::ApplicationController | |||
|   urgency :low | ||||
| 
 | ||||
|   def index | ||||
|     finder = Ci::RunnersFinder.new(current_user: current_user, params: { group: @group }) | ||||
|     @group_runners_limited_count = finder.execute.except(:limit, :offset).page.total_count_with_limit(:all, limit: 1000) | ||||
|     @group_runner_registration_token = @group.runners_token if can?(current_user, :register_group_runners, group) | ||||
| 
 | ||||
|     Gitlab::Tracking.event(self.class.name, 'index', user: current_user, namespace: @group) | ||||
|  |  | |||
|  | @ -53,6 +53,7 @@ class Import::BulkImportsController < ApplicationController | |||
|   end | ||||
| 
 | ||||
|   def create | ||||
|     return render json: { success: false }, status: :too_many_requests if throttled_request? | ||||
|     return render json: { success: false }, status: :unprocessable_entity unless valid_create_params? | ||||
| 
 | ||||
|     responses = create_params.map do |entry| | ||||
|  | @ -204,4 +205,8 @@ class Import::BulkImportsController < ApplicationController | |||
|   def current_user_bulk_imports | ||||
|     current_user.bulk_imports.gitlab | ||||
|   end | ||||
| 
 | ||||
|   def throttled_request? | ||||
|     ::Gitlab::ApplicationRateLimiter.throttled_request?(request, current_user, :bulk_import, scope: current_user) | ||||
|   end | ||||
| end | ||||
|  |  | |||
|  | @ -4,14 +4,26 @@ module AppearancesHelper | |||
|   include MarkupHelper | ||||
|   include Gitlab::Utils::StrongMemoize | ||||
| 
 | ||||
|   def appearance_short_name | ||||
|     Appearance.current&.pwa_short_name.presence || _('GitLab') | ||||
|   end | ||||
| 
 | ||||
|   def brand_title | ||||
|     current_appearance&.title.presence || default_brand_title | ||||
|   end | ||||
| 
 | ||||
|   def appearance_pwa_name | ||||
|     current_appearance&.pwa_name.presence || _('GitLab') | ||||
|   end | ||||
| 
 | ||||
|   def appearance_pwa_short_name | ||||
|     current_appearance&.pwa_short_name.presence || _('GitLab') | ||||
|   end | ||||
| 
 | ||||
|   def appearance_pwa_description | ||||
|     current_appearance&.pwa_description.presence || | ||||
|       _("The complete DevOps platform. " \ | ||||
|         "One application with endless possibilities. " \ | ||||
|         "Organizations rely on GitLab’s source code management, " \ | ||||
|         "CI/CD, security, and more to deliver software rapidly.") | ||||
|   end | ||||
| 
 | ||||
|   def default_brand_title | ||||
|     # This resides in a separate method so that EE can easily redefine it. | ||||
|     _('GitLab Community Edition') | ||||
|  |  | |||
|  | @ -6,8 +6,10 @@ class Appearance < ApplicationRecord | |||
|   include WithUploads | ||||
| 
 | ||||
|   attribute :title, default: '' | ||||
|   attribute :pwa_short_name, default: '' | ||||
|   attribute :description, default: '' | ||||
|   attribute :pwa_name, default: '' | ||||
|   attribute :pwa_short_name, default: '' | ||||
|   attribute :pwa_description, default: '' | ||||
|   attribute :new_project_guidelines, default: '' | ||||
|   attribute :profile_image_guidelines, default: '' | ||||
|   attribute :header_message, default: '' | ||||
|  | @ -22,6 +24,18 @@ class Appearance < ApplicationRecord | |||
|   cache_markdown_field :header_message, pipeline: :broadcast_message | ||||
|   cache_markdown_field :footer_message, pipeline: :broadcast_message | ||||
| 
 | ||||
|   validates :pwa_name, | ||||
|             length: { maximum: 255, message: N_("is too long (maximum is %{count} characters)") }, | ||||
|             allow_blank: true | ||||
| 
 | ||||
|   validates :pwa_short_name, | ||||
|             length: { maximum: 255, message: N_("is too long (maximum is %{count} characters)") }, | ||||
|             allow_blank: true | ||||
| 
 | ||||
|   validates :pwa_description, | ||||
|             length: { maximum: 2048, message: N_("is too long (maximum is %{count} characters)") }, | ||||
|             allow_blank: true | ||||
| 
 | ||||
|   validates :logo,        file_size: { maximum: 1.megabyte } | ||||
|   validates :pwa_icon,    file_size: { maximum: 1.megabyte } | ||||
|   validates :header_logo, file_size: { maximum: 1.megabyte } | ||||
|  |  | |||
|  | @ -1,3 +1,3 @@ | |||
| - page_title s_('Runners|Runners') | ||||
| 
 | ||||
| #js-group-runners{ data: group_runners_data_attributes(@group).merge({ group_runners_limited_count: @group_runners_limited_count, registration_token: @group_runner_registration_token }) } | ||||
| #js-group-runners{ data: group_runners_data_attributes(@group).merge({registration_token: @group_runner_registration_token }) } | ||||
|  |  | |||
|  | @ -1,7 +1,7 @@ | |||
| { | ||||
|   "name": "<%= Appearance.current&.title.presence || _('GitLab') %>", | ||||
|   "short_name": "<%= appearance_short_name %>", | ||||
|   "description": "<%= Appearance.current&.description.presence || _("The complete DevOps platform. One application with endless possibilities. Organizations rely on GitLab’s source code management, CI/CD, security, and more to deliver software rapidly.") %>", | ||||
|   "name": "<%= appearance_pwa_name %>", | ||||
|   "short_name": "<%= appearance_pwa_short_name %>", | ||||
|   "description": "<%= appearance_pwa_description %>", | ||||
|   "start_url": "<%= explore_projects_path %>", | ||||
|   "scope": "<%= root_path %>", | ||||
|   "display": "browser", | ||||
|  |  | |||
|  | @ -0,0 +1,15 @@ | |||
| # frozen_string_literal: true | ||||
| 
 | ||||
| class AddPwaAttributesToAppearances < Gitlab::Database::Migration[2.1] | ||||
|   # rubocop:disable Migration/AddLimitToTextColumns | ||||
|   def up | ||||
|     add_column :appearances, :pwa_name, :text | ||||
|     add_column :appearances, :pwa_description, :text | ||||
|   end | ||||
|   # rubocop:enable Migration/AddLimitToTextColumns | ||||
| 
 | ||||
|   def down | ||||
|     remove_column :appearances, :pwa_name | ||||
|     remove_column :appearances, :pwa_description | ||||
|   end | ||||
| end | ||||
|  | @ -0,0 +1,15 @@ | |||
| # frozen_string_literal: true | ||||
| 
 | ||||
| class AddTextLimitToPwaAttributes < Gitlab::Database::Migration[2.1] | ||||
|   disable_ddl_transaction! | ||||
| 
 | ||||
|   def up | ||||
|     add_text_limit :appearances, :pwa_name, 255 | ||||
|     add_text_limit :appearances, :pwa_description, 2048 | ||||
|   end | ||||
| 
 | ||||
|   def down | ||||
|     remove_text_limit :appearances, :pwa_name | ||||
|     remove_text_limit :appearances, :pwa_description | ||||
|   end | ||||
| end | ||||
|  | @ -0,0 +1,13 @@ | |||
| # frozen_string_literal: true | ||||
| 
 | ||||
| class RenameWebHookCallsToWebHookCallsHigh < Gitlab::Database::Migration[2.1] | ||||
|   disable_ddl_transaction! | ||||
| 
 | ||||
|   def up | ||||
|     rename_column_concurrently :plan_limits, :web_hook_calls, :web_hook_calls_high | ||||
|   end | ||||
| 
 | ||||
|   def down | ||||
|     undo_rename_column_concurrently :plan_limits, :web_hook_calls, :web_hook_calls_high | ||||
|   end | ||||
| end | ||||
|  | @ -0,0 +1,13 @@ | |||
| # frozen_string_literal: true | ||||
| 
 | ||||
| class CleanupWebHookCallsColumnRename < Gitlab::Database::Migration[2.1] | ||||
|   disable_ddl_transaction! | ||||
| 
 | ||||
|   def up | ||||
|     cleanup_concurrent_column_rename :plan_limits, :web_hook_calls, :web_hook_calls_high | ||||
|   end | ||||
| 
 | ||||
|   def down | ||||
|     undo_cleanup_concurrent_column_rename :plan_limits, :web_hook_calls, :web_hook_calls_high | ||||
|   end | ||||
| end | ||||
|  | @ -0,0 +1,20 @@ | |||
| # frozen_string_literal: true | ||||
| 
 | ||||
| class AddTmpIndexToCiBuildNeed < Gitlab::Database::Migration[2.1] | ||||
|   disable_ddl_transaction! | ||||
| 
 | ||||
|   INDEX_NAME = :tmp_index_ci_build_needs_on_partition_id_and_id | ||||
|   TABLE_NAME = :ci_build_needs | ||||
| 
 | ||||
|   def up | ||||
|     return unless Gitlab.com? | ||||
| 
 | ||||
|     prepare_async_index(TABLE_NAME, [:partition_id, :id], where: 'partition_id = 101', name: INDEX_NAME) | ||||
|   end | ||||
| 
 | ||||
|   def down | ||||
|     return unless Gitlab.com? | ||||
| 
 | ||||
|     unprepare_async_index_by_name(TABLE_NAME, INDEX_NAME) | ||||
|   end | ||||
| end | ||||
|  | @ -0,0 +1,20 @@ | |||
| # frozen_string_literal: true | ||||
| 
 | ||||
| class AddTmpIndexToCiPipelineVariable < Gitlab::Database::Migration[2.1] | ||||
|   disable_ddl_transaction! | ||||
| 
 | ||||
|   INDEX_NAME = :tmp_index_ci_pipeline_variables_on_partition_id_and_id | ||||
|   TABLE_NAME = :ci_pipeline_variables | ||||
| 
 | ||||
|   def up | ||||
|     return unless Gitlab.com? | ||||
| 
 | ||||
|     prepare_async_index(TABLE_NAME, [:partition_id, :id], where: 'partition_id = 101', name: INDEX_NAME) | ||||
|   end | ||||
| 
 | ||||
|   def down | ||||
|     return unless Gitlab.com? | ||||
| 
 | ||||
|     unprepare_async_index_by_name(TABLE_NAME, INDEX_NAME) | ||||
|   end | ||||
| end | ||||
|  | @ -0,0 +1,20 @@ | |||
| # frozen_string_literal: true | ||||
| 
 | ||||
| class AddTmpIndexToCiBuildReportResults < Gitlab::Database::Migration[2.1] | ||||
|   disable_ddl_transaction! | ||||
| 
 | ||||
|   INDEX_NAME = :tmp_index_ci_build_report_results_on_partition_id_and_id | ||||
|   TABLE_NAME = :ci_build_report_results | ||||
| 
 | ||||
|   def up | ||||
|     return unless Gitlab.com? | ||||
| 
 | ||||
|     prepare_async_index(TABLE_NAME, [:partition_id, :id], where: 'partition_id = 101', name: INDEX_NAME) | ||||
|   end | ||||
| 
 | ||||
|   def down | ||||
|     return unless Gitlab.com? | ||||
| 
 | ||||
|     unprepare_async_index_by_name(TABLE_NAME, INDEX_NAME) | ||||
|   end | ||||
| end | ||||
|  | @ -0,0 +1,19 @@ | |||
| # frozen_string_literal: true | ||||
| 
 | ||||
| class AddTmpIndexToCiBuildsOnPartitionId < Gitlab::Database::Migration[2.1] | ||||
|   disable_ddl_transaction! | ||||
| 
 | ||||
|   INDEX_NAME = :tmp_index_ci_builds_on_partition_id_and_id | ||||
| 
 | ||||
|   def up | ||||
|     return unless Gitlab.com? | ||||
| 
 | ||||
|     prepare_async_index :ci_builds, [:partition_id, :id], name: INDEX_NAME, where: 'partition_id = 101' | ||||
|   end | ||||
| 
 | ||||
|   def down | ||||
|     return unless Gitlab.com? | ||||
| 
 | ||||
|     unprepare_async_index :ci_builds, [:partition_id, :id], name: INDEX_NAME, where: 'partition_id = 101' | ||||
|   end | ||||
| end | ||||
|  | @ -0,0 +1,19 @@ | |||
| # frozen_string_literal: true | ||||
| 
 | ||||
| class AddTmpIndexToCiPipelinesOnPartitionId < Gitlab::Database::Migration[2.1] | ||||
|   disable_ddl_transaction! | ||||
| 
 | ||||
|   INDEX_NAME = :tmp_index_ci_pipelines_on_partition_id_and_id | ||||
| 
 | ||||
|   def up | ||||
|     return unless Gitlab.com? | ||||
| 
 | ||||
|     prepare_async_index :ci_pipelines, [:partition_id, :id], name: INDEX_NAME, where: 'partition_id = 101' | ||||
|   end | ||||
| 
 | ||||
|   def down | ||||
|     return unless Gitlab.com? | ||||
| 
 | ||||
|     unprepare_async_index :ci_pipelines, [:partition_id, :id], name: INDEX_NAME, where: 'partition_id = 101' | ||||
|   end | ||||
| end | ||||
|  | @ -0,0 +1,19 @@ | |||
| # frozen_string_literal: true | ||||
| 
 | ||||
| class AddTmpIndexToCiStagesOnPartitionId < Gitlab::Database::Migration[2.1] | ||||
|   disable_ddl_transaction! | ||||
| 
 | ||||
|   INDEX_NAME = :tmp_index_ci_stages_on_partition_id_and_id | ||||
| 
 | ||||
|   def up | ||||
|     return unless Gitlab.com? | ||||
| 
 | ||||
|     prepare_async_index :ci_stages, [:partition_id, :id], name: INDEX_NAME, where: 'partition_id = 101' | ||||
|   end | ||||
| 
 | ||||
|   def down | ||||
|     return unless Gitlab.com? | ||||
| 
 | ||||
|     unprepare_async_index :ci_stages, [:partition_id, :id], name: INDEX_NAME, where: 'partition_id = 101' | ||||
|   end | ||||
| end | ||||
|  | @ -0,0 +1 @@ | |||
| 2935444c762f3fdc8bd04055fc6048be4b637d2136e71a84479135e44c50856b | ||||
|  | @ -0,0 +1 @@ | |||
| 0105a4d40b8ecb6e4c1bc543001f223bf9bbb25c03288dd394859d4926bb4801 | ||||
|  | @ -0,0 +1 @@ | |||
| a567168b41dc56069e485ef303aeb69b967e685d463ed44d99f54dc96cdf9bbd | ||||
|  | @ -0,0 +1 @@ | |||
| 052c36d0911e104f8bc42f3229170c234f3c61555f53712adbfee6ab385233b3 | ||||
|  | @ -0,0 +1 @@ | |||
| a2cb76b2138b3edc014c01c4b130fcd58bf81a10c68c897376f5bf8d69d5a660 | ||||
|  | @ -0,0 +1 @@ | |||
| 97a52b54895ff5f5ea3c2dac6148c8d8110081bffe9064c50547b776ec56e78a | ||||
|  | @ -0,0 +1 @@ | |||
| 775eb98fc81524f667cfab4dfdcee9bd668143c7286011dd1f0d40f87fc06ab0 | ||||
|  | @ -0,0 +1 @@ | |||
| 4d38db045a0d505ea8f62327de8cc58fc0896e7c194cf71ca28ba08113757696 | ||||
|  | @ -0,0 +1 @@ | |||
| 28b959fe3c79a9d24e24d296112ee7ada71b9932e608cbf5fa2d01cac3db0247 | ||||
|  | @ -0,0 +1 @@ | |||
| 0a34ab643f8ac5fdd0dd604f53244fe07a88ebf992fed7863bf38300817c9acb | ||||
|  | @ -11065,8 +11065,12 @@ CREATE TABLE appearances ( | |||
|     profile_image_guidelines_html text, | ||||
|     pwa_short_name text, | ||||
|     pwa_icon text, | ||||
|     pwa_name text, | ||||
|     pwa_description text, | ||||
|     CONSTRAINT appearances_profile_image_guidelines CHECK ((char_length(profile_image_guidelines) <= 4096)), | ||||
|     CONSTRAINT check_13b2165eca CHECK ((char_length(pwa_name) <= 255)), | ||||
|     CONSTRAINT check_5c3fd63577 CHECK ((char_length(pwa_short_name) <= 255)), | ||||
|     CONSTRAINT check_5e0e6f24ed CHECK ((char_length(pwa_description) <= 2048)), | ||||
|     CONSTRAINT check_5e5b7ac344 CHECK ((char_length(pwa_icon) <= 1024)) | ||||
| ); | ||||
| 
 | ||||
|  | @ -19565,7 +19569,6 @@ CREATE TABLE plan_limits ( | |||
|     helm_max_file_size bigint DEFAULT 5242880 NOT NULL, | ||||
|     ci_registered_group_runners integer DEFAULT 1000 NOT NULL, | ||||
|     ci_registered_project_runners integer DEFAULT 1000 NOT NULL, | ||||
|     web_hook_calls integer DEFAULT 0 NOT NULL, | ||||
|     ci_daily_pipeline_schedule_triggers integer DEFAULT 0 NOT NULL, | ||||
|     ci_max_artifact_size_running_container_scanning integer DEFAULT 0 NOT NULL, | ||||
|     ci_max_artifact_size_cluster_image_scanning integer DEFAULT 0 NOT NULL, | ||||
|  | @ -19589,7 +19592,9 @@ CREATE TABLE plan_limits ( | |||
|     pipeline_hierarchy_size integer DEFAULT 1000 NOT NULL, | ||||
|     enforcement_limit integer DEFAULT 0 NOT NULL, | ||||
|     notification_limit integer DEFAULT 0 NOT NULL, | ||||
|     dashboard_limit_enabled_at timestamp with time zone | ||||
|     dashboard_limit_enabled_at timestamp with time zone, | ||||
|     web_hook_calls_high integer DEFAULT 0, | ||||
|     CONSTRAINT check_0fa68f370e CHECK ((web_hook_calls_high IS NOT NULL)) | ||||
| ); | ||||
| 
 | ||||
| CREATE SEQUENCE plan_limits_id_seq | ||||
|  |  | |||
|  | @ -147,7 +147,7 @@ To set this limit for a self-managed installation, run the following in the | |||
| # If limits don't exist for the default plan, you can create one with: | ||||
| # Plan.default.create_limits! | ||||
| 
 | ||||
| Plan.default.actual_limits.update!(web_hook_calls: 10) | ||||
| Plan.default.actual_limits.update!(web_hook_calls_high: 10) | ||||
| ``` | ||||
| 
 | ||||
| Set the limit to `0` to disable it. | ||||
|  |  | |||
|  | @ -29,8 +29,10 @@ Example response: | |||
| ```json | ||||
| { | ||||
|   "title": "GitLab Test Instance", | ||||
|   "pwa_short_name": "GitLab", | ||||
|   "description": "gitlab-test.example.com", | ||||
|   "pwa_name": "GitLab PWA", | ||||
|   "pwa_short_name": "GitLab", | ||||
|   "pwa_description": "GitLab as PWA", | ||||
|   "pwa_icon": "/uploads/-/system/appearance/pwa_icon/1/pwa_logo.png", | ||||
|   "logo": "/uploads/-/system/appearance/logo/1/logo.png", | ||||
|   "header_logo": "/uploads/-/system/appearance/header_logo/1/header.png", | ||||
|  | @ -56,8 +58,10 @@ PUT /application/appearance | |||
| | Attribute                         | Type    | Required | Description | | ||||
| | --------------------------------- | ------- | -------- | ----------- | | ||||
| | `title`                           | string  | no       | Instance title on the sign in / sign up page | ||||
| | `pwa_short_name`                  | string  | no       | Optional, short name for Progressive Web App | ||||
| | `description`                     | string  | no       | Markdown text shown on the sign in / sign up page | ||||
| | `pwa_name`                        | string  | no       | Full name of the Progressive Web App. Used for the attribute `name` in `manifest.json`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/375708) in GitLab 15.8. | ||||
| | `pwa_short_name`                  | string  | no       | Short name for Progressive Web App. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/375708) in GitLab 15.8. | ||||
| | `pwa_description`                 | string  | no       | An explanation of what the Progressive Web App does. Used for the attribute `description` in `manifest.json`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/375708) in GitLab 15.8. | ||||
| | `pwa_icon`                        | mixed   | no       | Icon used for Progressive Web App. See [Change logo](#change-logo). [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/375708) in GitLab 15.8. | ||||
| | `logo`                            | mixed   | no       | Instance image used on the sign in / sign up page. See [Change logo](#change-logo) | ||||
| | `header_logo`                     | mixed   | no       | Instance image used for the main navigation bar | ||||
|  | @ -79,8 +83,10 @@ Example response: | |||
| ```json | ||||
| { | ||||
|   "title": "GitLab Test Instance", | ||||
|   "pwa_short_name": "GitLab", | ||||
|   "description": "gitlab-test.example.com", | ||||
|   "pwa_name": "GitLab PWA", | ||||
|   "pwa_short_name": "GitLab", | ||||
|   "pwa_description": "GitLab as PWA", | ||||
|   "pwa_icon": "/uploads/-/system/appearance/pwa_icon/1/pwa_logo.png", | ||||
|   "logo": "/uploads/-/system/appearance/logo/1/logo.png", | ||||
|   "header_logo": "/uploads/-/system/appearance/header_logo/1/header.png", | ||||
|  |  | |||
|  | @ -78,7 +78,7 @@ sudo -u git -H bundle exec rails runner -e production 'puts Gitlab::Database::Ba | |||
| > - [Enabled by default](https://gitlab.com/gitlab-org/gitlab/-/issues/329511) in GitLab 13.12. | ||||
| > - Enabled on GitLab.com. | ||||
| > - Recommended for production use. | ||||
| > - For GitLab self-managed instances, GitLab administrators can opt to [disable it](#enable-or-disable-batched-background-migrations). | ||||
| > - For GitLab self-managed instances, GitLab administrators can opt to [disable it](#enable-or-disable-background-migrations). | ||||
| 
 | ||||
| There can be [risks when disabling released features](../administration/feature_flags.md#risks-when-disabling-released-features). | ||||
| Refer to this feature's version history for more details. | ||||
|  | @ -203,17 +203,21 @@ Feature.disable(:optimize_batched_migrations) | |||
| 
 | ||||
| ## Troubleshooting | ||||
| 
 | ||||
| ### Enable or disable batched background migrations | ||||
| ### Enable or disable background migrations | ||||
| 
 | ||||
| In extremely limited circumstances, a GitLab administrator can disable the | ||||
| `execute_batched_migrations_on_schedule` [feature flag](../administration/feature_flags.md). | ||||
| This flag is enabled by default, and should be disabled only as a last resort | ||||
| In extremely limited circumstances, a GitLab administrator can disable either or | ||||
| both of these [feature flags](../administration/feature_flags.md): | ||||
| 
 | ||||
| - `execute_background_migrations` | ||||
| - `execute_batched_migrations_on_schedule` | ||||
| 
 | ||||
| These flags are enabled by default. Disable them only as a last resort | ||||
| to limit database operations in special circumstances, like database host maintenance. | ||||
| 
 | ||||
| WARNING: | ||||
| Do not disable this flag unless you fully understand the ramifications. If you disable | ||||
| the `execute_batched_migrations_on_schedule` feature flag, GitLab upgrades may fail | ||||
| and data loss may occur. | ||||
| Do not disable either of these flags unless you fully understand the ramifications. If you disable | ||||
| the `execute_background_migrations` or `execute_batched_migrations_on_schedule` feature flag, | ||||
| GitLab upgrades might fail and data loss might occur. | ||||
| 
 | ||||
| ### Database migrations failing because of batched background migration not finished | ||||
| 
 | ||||
|  |  | |||
|  | @ -21,12 +21,18 @@ To use the Security Dashboards, you must: | |||
| 
 | ||||
| ## When Security Dashboards are updated | ||||
| 
 | ||||
| The Security Dashboards show results of the most recent security scan on the | ||||
| The Security Dashboards show results of scans from the most recent completed pipeline on the | ||||
| [default branch](../../project/repository/branches/default.md). | ||||
| Security scans run only when the default branch updates, so | ||||
| information on the Security Dashboard might not reflect newly-discovered vulnerabilities. | ||||
| Dashboards are updated with the result of completed pipelines run on the default branch; they do not include vulnerabilities discovered in pipelines from other un-merged branches. | ||||
| 
 | ||||
| To run a daily security scan, | ||||
| If you use manual jobs, for example gate deployments, in the default branch's pipeline, | ||||
| the results of any scans are only updated when the job has been successfully run. | ||||
| If manual jobs are skipped regularly, you should to define the job as optional, | ||||
| using the [`allow_failure`](../../../ci/jobs/job_control.md#types-of-manual-jobs) attribute. | ||||
| 
 | ||||
| To ensure regular security scans (even on infrequently developed projects), | ||||
| you should use [scan execution policies](../../../user/application_security/policies/scan-execution-policies.md). | ||||
| Alternatively, you can | ||||
| [configure a scheduled pipeline](../../../ci/pipelines/schedules.md). | ||||
| 
 | ||||
| ## Reduce false negatives in dependency scans | ||||
|  |  | |||
|  | @ -37,8 +37,8 @@ PUT /projects/:id/packages/terraform/modules/:module-name/:module-system/:module | |||
| | Attribute          | Type            | Required | Description                                                                                                                      | | ||||
| | -------------------| --------------- | ---------| -------------------------------------------------------------------------------------------------------------------------------- | | ||||
| | `id`               | integer/string  | yes      | The ID or [URL-encoded path of the project](../../../api/rest/index.md#namespaced-path-encoding).                                    | | ||||
| | `module-name`      | string          | yes      | The package name. **Supported syntax**: One to 64 ASCII characters, including lowercase letters (a-z), digits (0-9), and hyphens (`-`). | ||||
| | `module-system`    | string          | yes      | The package system. **Supported syntax**: One to 64 ASCII characters, including lowercase letters (a-z), digits (0-9), and hyphens (`-`). More information can be found in the [Terraform Module Registry Protocol documentation](https://www.terraform.io/internals/module-registry-protocol). | ||||
| | `module-name`      | string          | yes      | The package name. **Supported syntax**: One to 64 ASCII characters, including lowercase letters (a-z) and digits (0-9). The package name can't exceed 64 characters. | ||||
| | `module-system`    | string          | yes      | The package system. **Supported syntax**: One to 64 ASCII characters, including lowercase letters (a-z) and digits (0-9). The package system can't exceed 64 characters. More information can be found in the [Terraform Module Registry Protocol documentation](https://www.terraform.io/internals/module-registry-protocol). | ||||
| | `module-version`   | string          | yes      | The package version. It must be valid according to the [Semantic Versioning Specification](https://semver.org/). | ||||
| 
 | ||||
| Provide the file content in the request body. | ||||
|  |  | |||
|  | @ -243,7 +243,7 @@ like in https://gitlab.com/gitlab-org/gitlab/-/merge_requests/87727/diffs?diff_i | |||
| 
 | ||||
| FLAG: | ||||
| On self-managed GitLab, by default this feature is not available. To make it available per project or for your entire instance, ask an administrator to [enable the feature flag](../../../administration/feature_flags.md) named `moved_mr_sidebar`. | ||||
| On GitLab.com, this feature is not available. | ||||
| On GitLab.com, this feature is enabled in the following projects: `gitlab-org/gitlab`, `gitlab-com/www-gitlab-com`, and `gitlab-org/customers-gitlab-com`. | ||||
| 
 | ||||
| When this feature flag is enabled, you can find the following actions in | ||||
| **Merge request actions** (**{ellipsis_v}**) on the top right: | ||||
|  |  | |||
|  | @ -26,8 +26,10 @@ module API | |||
|     end | ||||
|     params do | ||||
|       optional :title, type: String, desc: 'Instance title on the sign in / sign up page' | ||||
|       optional :pwa_short_name, type: String, desc: 'Optional, short name for Progressive Web App' | ||||
|       optional :description, type: String, desc: 'Markdown text shown on the sign in / sign up page' | ||||
|       optional :pwa_name, type: String, desc: 'Name of the Progressive Web App' | ||||
|       optional :pwa_short_name, type: String, desc: 'Optional, short name for Progressive Web App' | ||||
|       optional :pwa_description, type: String, desc: 'An explanation of what the Progressive Web App does' | ||||
|       # TODO: remove rubocop disable - https://gitlab.com/gitlab-org/gitlab/issues/14960 | ||||
|       optional :logo, type: File, desc: 'Instance image used on the sign in / sign up page' # rubocop:disable Scalability/FileUploads | ||||
|       optional :pwa_icon, type: File, desc: 'Icon used for Progressive Web App' # rubocop:disable Scalability/FileUploads | ||||
|  |  | |||
|  | @ -91,6 +91,8 @@ module API | |||
|         end | ||||
|       end | ||||
|       post do | ||||
|         check_rate_limit!(:bulk_import, scope: current_user) | ||||
| 
 | ||||
|         params[:entities].each do |entity| | ||||
|           if entity[:destination_name] | ||||
|             entity[:destination_slug] ||= entity[:destination_name] | ||||
|  |  | |||
|  | @ -4,8 +4,10 @@ module API | |||
|   module Entities | ||||
|     class Appearance < Grape::Entity | ||||
|       expose :title | ||||
|       expose :pwa_short_name | ||||
|       expose :description | ||||
|       expose :pwa_name | ||||
|       expose :pwa_short_name | ||||
|       expose :pwa_description | ||||
| 
 | ||||
|       expose :logo do |appearance, options| | ||||
|         appearance.logo.url | ||||
|  |  | |||
|  | @ -31,7 +31,7 @@ module Gitlab | |||
|           group_import: { threshold: -> { application_settings.group_import_limit }, interval: 1.minute }, | ||||
|           group_testing_hook: { threshold: 5, interval: 1.minute }, | ||||
|           profile_add_new_email: { threshold: 5, interval: 1.minute }, | ||||
|           web_hook_calls: { interval: 1.minute }, | ||||
|           web_hook_calls_high: { interval: 1.minute }, | ||||
|           web_hook_calls_mid: { interval: 1.minute }, | ||||
|           web_hook_calls_low: { interval: 1.minute }, | ||||
|           users_get_by_id: { threshold: -> { application_settings.users_get_by_id_limit }, interval: 10.minutes }, | ||||
|  | @ -55,7 +55,8 @@ module Gitlab | |||
|           phone_verification_verify_code: { threshold: 10, interval: 10.minutes }, | ||||
|           namespace_exists: { threshold: 20, interval: 1.minute }, | ||||
|           fetch_google_ip_list: { threshold: 10, interval: 1.minute }, | ||||
|           jobs_index: { threshold: 600, interval: 1.minute } | ||||
|           jobs_index: { threshold: 600, interval: 1.minute }, | ||||
|           bulk_import: { threshold: 6, interval: 1.minute } | ||||
|         }.freeze | ||||
|       end | ||||
| 
 | ||||
|  |  | |||
|  | @ -5,7 +5,7 @@ module Gitlab | |||
|     class RateLimiter | ||||
|       include Gitlab::Utils::StrongMemoize | ||||
| 
 | ||||
|       LIMIT_NAME = :web_hook_calls | ||||
|       LIMIT_NAME = :web_hook_calls_high | ||||
|       NO_LIMIT = 0 | ||||
|       # SystemHooks (instance admin hooks) and ServiceHooks (integration hooks) | ||||
|       # are not rate-limited. | ||||
|  |  | |||
|  | @ -111,7 +111,7 @@ | |||
|     "codesandbox-api": "0.0.23", | ||||
|     "compression-webpack-plugin": "^5.0.2", | ||||
|     "copy-webpack-plugin": "^6.4.1", | ||||
|     "core-js": "^3.27.1", | ||||
|     "core-js": "^3.27.2", | ||||
|     "cron-validator": "^1.1.1", | ||||
|     "cronstrue": "^1.122.0", | ||||
|     "cropper": "^2.3.0", | ||||
|  |  | |||
|  | @ -11,8 +11,10 @@ RSpec.describe Admin::ApplicationSettings::AppearancesController do | |||
|     let(:create_params) do | ||||
|       { | ||||
|         title: 'Foo', | ||||
|         pwa_short_name: 'F', | ||||
|         description: 'Bar', | ||||
|         pwa_name: 'GitLab PWA', | ||||
|         pwa_short_name: 'F', | ||||
|         pwa_description: 'This is GitLab as PWA', | ||||
|         header_message: header_message, | ||||
|         footer_message: footer_message | ||||
|       } | ||||
|  | @ -26,6 +28,11 @@ RSpec.describe Admin::ApplicationSettings::AppearancesController do | |||
|       post :create, params: { appearance: create_params } | ||||
| 
 | ||||
|       expect(Appearance.current).to have_attributes( | ||||
|         title: 'Foo', | ||||
|         description: 'Bar', | ||||
|         pwa_name: 'GitLab PWA', | ||||
|         pwa_short_name: 'F', | ||||
|         pwa_description: 'This is GitLab as PWA', | ||||
|         header_message: header_message, | ||||
|         footer_message: footer_message, | ||||
|         email_header_and_footer_enabled: false, | ||||
|  | @ -41,6 +48,11 @@ RSpec.describe Admin::ApplicationSettings::AppearancesController do | |||
|         post :create, params: { appearance: create_params } | ||||
| 
 | ||||
|         expect(Appearance.current).to have_attributes( | ||||
|           title: 'Foo', | ||||
|           description: 'Bar', | ||||
|           pwa_name: 'GitLab PWA', | ||||
|           pwa_short_name: 'F', | ||||
|           pwa_description: 'This is GitLab as PWA', | ||||
|           header_message: header_message, | ||||
|           footer_message: footer_message, | ||||
|           email_header_and_footer_enabled: true | ||||
|  |  | |||
|  | @ -105,49 +105,6 @@ RSpec.describe Admin::RunnersController, feature_category: :runner_fleet do | |||
|     end | ||||
|   end | ||||
| 
 | ||||
|   describe '#destroy' do | ||||
|     it 'destroys the runner' do | ||||
|       expect_next_instance_of(Ci::Runners::UnregisterRunnerService, runner, user) do |service| | ||||
|         expect(service).to receive(:execute).once.and_call_original | ||||
|       end | ||||
| 
 | ||||
|       delete :destroy, params: { id: runner.id } | ||||
| 
 | ||||
|       expect(response).to have_gitlab_http_status(:found) | ||||
|       expect(Ci::Runner.find_by(id: runner.id)).to be_nil | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   describe '#resume' do | ||||
|     it 'marks the runner as active and ticks the queue' do | ||||
|       runner.update!(active: false) | ||||
| 
 | ||||
|       expect do | ||||
|         post :resume, params: { id: runner.id } | ||||
|       end.to change { runner.ensure_runner_queue_value } | ||||
| 
 | ||||
|       runner.reload | ||||
| 
 | ||||
|       expect(response).to have_gitlab_http_status(:found) | ||||
|       expect(runner.active).to eq(true) | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   describe '#pause' do | ||||
|     it 'marks the runner as inactive and ticks the queue' do | ||||
|       runner.update!(active: true) | ||||
| 
 | ||||
|       expect do | ||||
|         post :pause, params: { id: runner.id } | ||||
|       end.to change { runner.ensure_runner_queue_value } | ||||
| 
 | ||||
|       runner.reload | ||||
| 
 | ||||
|       expect(response).to have_gitlab_http_status(:found) | ||||
|       expect(runner.active).to eq(false) | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   describe 'GET #runner_setup_scripts' do | ||||
|     it 'renders the setup scripts' do | ||||
|       get :runner_setup_scripts, params: { os: 'linux', arch: 'amd64' } | ||||
|  |  | |||
|  | @ -30,7 +30,6 @@ RSpec.describe Groups::RunnersController, feature_category: :runner_fleet do | |||
| 
 | ||||
|         expect(response).to have_gitlab_http_status(:ok) | ||||
|         expect(response).to render_template(:index) | ||||
|         expect(assigns(:group_runners_limited_count)).to be(2) | ||||
|       end | ||||
| 
 | ||||
|       it 'tracks the event' do | ||||
|  |  | |||
|  | @ -9,14 +9,12 @@ RSpec.describe Import::BulkImportsController, feature_category: :importers do | |||
|     stub_application_setting(bulk_import_enabled: true) | ||||
| 
 | ||||
|     sign_in(user) | ||||
| 
 | ||||
|     allow(::Gitlab::ApplicationRateLimiter).to receive(:throttled?).and_return(false) | ||||
|   end | ||||
| 
 | ||||
|   context 'when user is signed in' do | ||||
|     context 'when bulk_import feature flag is enabled' do | ||||
|       before do | ||||
|         stub_feature_flags(bulk_import: true) | ||||
|       end | ||||
| 
 | ||||
|       describe 'POST configure' do | ||||
|         before do | ||||
|           allow_next_instance_of(BulkImports::Clients::HTTP) do |instance| | ||||
|  | @ -400,6 +398,18 @@ RSpec.describe Import::BulkImportsController, feature_category: :importers do | |||
|             expect(response).to have_gitlab_http_status(:unprocessable_entity) | ||||
|           end | ||||
|         end | ||||
| 
 | ||||
|         context 'when request exceeds rate limits' do | ||||
|           it 'prevents user from starting a new migration' do | ||||
|             allow(::Gitlab::ApplicationRateLimiter).to receive(:throttled?).and_return(true) | ||||
| 
 | ||||
|             post :create, params: { bulk_import: {} } | ||||
| 
 | ||||
|             request | ||||
| 
 | ||||
|             expect(response).to have_gitlab_http_status(:too_many_requests) | ||||
|           end | ||||
|         end | ||||
|       end | ||||
|     end | ||||
| 
 | ||||
|  |  | |||
|  | @ -13,7 +13,12 @@ import { | |||
| } from '~/vue_merge_request_widget/components/approvals/messages'; | ||||
| import eventHub from '~/vue_merge_request_widget/event_hub'; | ||||
| 
 | ||||
| jest.mock('~/flash'); | ||||
| const mockAlertDismiss = jest.fn(); | ||||
| jest.mock('~/flash', () => ({ | ||||
|   createAlert: jest.fn().mockImplementation(() => ({ | ||||
|     dismiss: mockAlertDismiss, | ||||
|   })), | ||||
| })); | ||||
| 
 | ||||
| const RULE_NAME = 'first_rule'; | ||||
| const TEST_HELP_PATH = 'help/path'; | ||||
|  | @ -267,9 +272,16 @@ describe('MRWidget approvals', () => { | |||
|             return nextTick(); | ||||
|           }); | ||||
| 
 | ||||
|           it('flashes error message', () => { | ||||
|           it('shows an alert with error message', () => { | ||||
|             expect(createAlert).toHaveBeenCalledWith({ message: APPROVE_ERROR }); | ||||
|           }); | ||||
| 
 | ||||
|           it('clears the previous alert', () => { | ||||
|             expect(mockAlertDismiss).toHaveBeenCalledTimes(0); | ||||
| 
 | ||||
|             findAction().vm.$emit('click'); | ||||
|             expect(mockAlertDismiss).toHaveBeenCalledTimes(1); | ||||
|           }); | ||||
|         }); | ||||
|       }); | ||||
|     }); | ||||
|  |  | |||
|  | @ -10,17 +10,45 @@ RSpec.describe AppearancesHelper do | |||
|     allow(helper).to receive(:current_user).and_return(user) | ||||
|   end | ||||
| 
 | ||||
|   describe '#appearance_short_name' do | ||||
|   describe '#appearance_pwa_name' do | ||||
|     it 'returns the default value' do | ||||
|       create(:appearance) | ||||
| 
 | ||||
|       expect(helper.appearance_short_name).to match('GitLab') | ||||
|       expect(helper.appearance_pwa_name).to match('GitLab') | ||||
|     end | ||||
| 
 | ||||
|     it 'returns the customized value' do | ||||
|       create(:appearance, pwa_name: 'GitLab as PWA') | ||||
| 
 | ||||
|       expect(helper.appearance_pwa_name).to match('GitLab as PWA') | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   describe '#appearance_pwa_short_name' do | ||||
|     it 'returns the default value' do | ||||
|       create(:appearance) | ||||
| 
 | ||||
|       expect(helper.appearance_pwa_short_name).to match('GitLab') | ||||
|     end | ||||
| 
 | ||||
|     it 'returns the customized value' do | ||||
|       create(:appearance, pwa_short_name: 'Short') | ||||
| 
 | ||||
|       expect(helper.appearance_short_name).to match('Short') | ||||
|       expect(helper.appearance_pwa_short_name).to match('Short') | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   describe '#appearance_pwa_description' do | ||||
|     it 'returns the default value' do | ||||
|       create(:appearance) | ||||
| 
 | ||||
|       expect(helper.appearance_pwa_description).to include('The complete DevOps platform.') | ||||
|     end | ||||
| 
 | ||||
|     it 'returns the customized value' do | ||||
|       create(:appearance, pwa_description: 'This is a description') | ||||
| 
 | ||||
|       expect(helper.appearance_pwa_description).to match('This is a description') | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|  |  | |||
|  | @ -32,7 +32,7 @@ RSpec.describe Gitlab::WebHooks::RateLimiter, :clean_gitlab_redis_rate_limiting | |||
| 
 | ||||
|     context 'when there is a plan limit' do | ||||
|       before_all do | ||||
|         create(:plan_limits, plan: plan, web_hook_calls: limit) | ||||
|         create(:plan_limits, plan: plan, web_hook_calls_high: limit) | ||||
|       end | ||||
| 
 | ||||
|       where(:hook, :limitless_hook_type) do | ||||
|  | @ -65,7 +65,7 @@ RSpec.describe Gitlab::WebHooks::RateLimiter, :clean_gitlab_redis_rate_limiting | |||
| 
 | ||||
|     describe 'rate limit scope' do | ||||
|       it 'rate limits all hooks from the same namespace', :freeze_time do | ||||
|         create(:plan_limits, plan: plan, web_hook_calls: limit) | ||||
|         create(:plan_limits, plan: plan, web_hook_calls_high: limit) | ||||
|         project_hook_in_different_namespace = create(:project_hook) | ||||
|         project_hook_in_same_namespace = create(:project_hook, | ||||
|           project: create(:project, namespace: project_hook.project.namespace) | ||||
|  | @ -92,7 +92,7 @@ RSpec.describe Gitlab::WebHooks::RateLimiter, :clean_gitlab_redis_rate_limiting | |||
| 
 | ||||
|     context 'when there is a plan limit' do | ||||
|       before_all do | ||||
|         create(:plan_limits, plan: plan, web_hook_calls: limit) | ||||
|         create(:plan_limits, plan: plan, web_hook_calls_high: limit) | ||||
|       end | ||||
| 
 | ||||
|       context 'when hook is not rate-limited' do | ||||
|  |  | |||
|  | @ -3,6 +3,7 @@ | |||
| require 'spec_helper' | ||||
| 
 | ||||
| RSpec.describe Appearance do | ||||
|   using RSpec::Parameterized::TableSyntax | ||||
|   subject { build(:appearance) } | ||||
| 
 | ||||
|   it { include(CacheableAttributes) } | ||||
|  | @ -14,8 +15,10 @@ RSpec.describe Appearance do | |||
|     subject(:appearance) { described_class.new } | ||||
| 
 | ||||
|     it { expect(appearance.title).to eq('') } | ||||
|     it { expect(appearance.pwa_short_name).to eq('') } | ||||
|     it { expect(appearance.description).to eq('') } | ||||
|     it { expect(appearance.pwa_name).to eq('') } | ||||
|     it { expect(appearance.pwa_short_name).to eq('') } | ||||
|     it { expect(appearance.pwa_description).to eq('') } | ||||
|     it { expect(appearance.new_project_guidelines).to eq('') } | ||||
|     it { expect(appearance.profile_image_guidelines).to eq('') } | ||||
|     it { expect(appearance.header_message).to eq('') } | ||||
|  | @ -96,6 +99,41 @@ RSpec.describe Appearance do | |||
|     it { is_expected.not_to allow_value('000').for(:message_font_color) } | ||||
|   end | ||||
| 
 | ||||
|   shared_examples 'validation allows' do | ||||
|     it { is_expected.to allow_value(value).for(attribute) } | ||||
|   end | ||||
| 
 | ||||
|   shared_examples 'validation permits with message' do | ||||
|     it { is_expected.not_to allow_value(value).for(attribute).with_message(message) } | ||||
|   end | ||||
| 
 | ||||
|   context 'valid pwa attributes' do | ||||
|     where(:attribute, :value) do | ||||
|       :pwa_name        | nil | ||||
|       :pwa_name        | "G" * 255 | ||||
|       :pwa_short_name  | nil | ||||
|       :pwa_short_name  | "S" * 255 | ||||
|       :pwa_description | nil | ||||
|       :pwa_description | "T" * 2048 | ||||
|     end | ||||
| 
 | ||||
|     with_them do | ||||
|       it_behaves_like 'validation allows' | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   context 'invalid pwa attributes' do | ||||
|     where(:attribute, :value, :message) do | ||||
|       :pwa_name        | "G" * 256  | 'is too long (maximum is 255 characters)' | ||||
|       :pwa_short_name  | "S" * 256  | 'is too long (maximum is 255 characters)' | ||||
|       :pwa_description | "T" * 2049 | 'is too long (maximum is 2048 characters)' | ||||
|     end | ||||
| 
 | ||||
|     with_them do | ||||
|       it_behaves_like 'validation permits with message' | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   describe 'email_header_and_footer_enabled' do | ||||
|     context 'default email_header_and_footer_enabled flag value' do | ||||
|       it 'returns email_header_and_footer_enabled as true' do | ||||
|  |  | |||
|  | @ -213,7 +213,7 @@ RSpec.describe PlanLimits do | |||
|         ci_active_jobs | ||||
|         storage_size_limit | ||||
|         daily_invites | ||||
|         web_hook_calls | ||||
|         web_hook_calls_high | ||||
|         web_hook_calls_mid | ||||
|         web_hook_calls_low | ||||
|         ci_daily_pipeline_schedule_triggers | ||||
|  |  | |||
|  | @ -34,7 +34,9 @@ RSpec.describe API::Appearance, 'Appearance', feature_category: :navigation do | |||
|         expect(json_response['new_project_guidelines']).to eq('') | ||||
|         expect(json_response['profile_image_guidelines']).to eq('') | ||||
|         expect(json_response['title']).to eq('') | ||||
|         expect(json_response['pwa_name']).to eq('') | ||||
|         expect(json_response['pwa_short_name']).to eq('') | ||||
|         expect(json_response['pwa_description']).to eq('') | ||||
|       end | ||||
|     end | ||||
|   end | ||||
|  | @ -53,8 +55,10 @@ RSpec.describe API::Appearance, 'Appearance', feature_category: :navigation do | |||
|         it "allows updating the settings" do | ||||
|           put api("/application/appearance", admin), params: { | ||||
|             title: "GitLab Test Instance", | ||||
|             pwa_short_name: "GitLab PWA", | ||||
|             description: "gitlab-test.example.com", | ||||
|             pwa_name: "GitLab PWA Test", | ||||
|             pwa_short_name: "GitLab PWA", | ||||
|             pwa_description: "This is GitLab as PWA", | ||||
|             new_project_guidelines: "Please read the FAQs for help.", | ||||
|             profile_image_guidelines: "Custom profile image guidelines" | ||||
|           } | ||||
|  | @ -74,7 +78,9 @@ RSpec.describe API::Appearance, 'Appearance', feature_category: :navigation do | |||
|           expect(json_response['new_project_guidelines']).to eq('Please read the FAQs for help.') | ||||
|           expect(json_response['profile_image_guidelines']).to eq('Custom profile image guidelines') | ||||
|           expect(json_response['title']).to eq('GitLab Test Instance') | ||||
|           expect(json_response['pwa_name']).to eq('GitLab PWA Test') | ||||
|           expect(json_response['pwa_short_name']).to eq('GitLab PWA') | ||||
|           expect(json_response['pwa_description']).to eq('This is GitLab as PWA') | ||||
|         end | ||||
|       end | ||||
| 
 | ||||
|  |  | |||
|  | @ -13,6 +13,8 @@ RSpec.describe API::BulkImports, feature_category: :importers do | |||
| 
 | ||||
|   before do | ||||
|     stub_application_setting(bulk_import_enabled: true) | ||||
| 
 | ||||
|     allow(::Gitlab::ApplicationRateLimiter).to receive(:throttled?).and_return(false) | ||||
|   end | ||||
| 
 | ||||
|   shared_examples 'disabled feature' do | ||||
|  | @ -73,20 +75,8 @@ RSpec.describe API::BulkImports, feature_category: :importers do | |||
|   end | ||||
| 
 | ||||
|   describe 'POST /bulk_imports' do | ||||
|     before do | ||||
|       allow_next_instance_of(BulkImports::Clients::HTTP) do |instance| | ||||
|         allow(instance) | ||||
|           .to receive(:instance_version) | ||||
|           .and_return( | ||||
|             Gitlab::VersionInfo.new(::BulkImport::MIN_MAJOR_VERSION, ::BulkImport::MIN_MINOR_VERSION_FOR_PROJECT)) | ||||
|         allow(instance) | ||||
|           .to receive(:instance_enterprise) | ||||
|           .and_return(false) | ||||
|       end | ||||
|     end | ||||
| 
 | ||||
|     shared_examples 'starting a new migration' do | ||||
|     let(:request) { post api('/bulk_imports', user), params: params } | ||||
|     let(:destination_param) { { destination_slug: 'destination_slug' } } | ||||
|     let(:params) do | ||||
|       { | ||||
|         configuration: { | ||||
|  | @ -103,6 +93,19 @@ RSpec.describe API::BulkImports, feature_category: :importers do | |||
|       } | ||||
|     end | ||||
| 
 | ||||
|     before do | ||||
|       allow_next_instance_of(BulkImports::Clients::HTTP) do |instance| | ||||
|         allow(instance) | ||||
|           .to receive(:instance_version) | ||||
|           .and_return( | ||||
|             Gitlab::VersionInfo.new(::BulkImport::MIN_MAJOR_VERSION, ::BulkImport::MIN_MINOR_VERSION_FOR_PROJECT)) | ||||
|         allow(instance) | ||||
|           .to receive(:instance_enterprise) | ||||
|           .and_return(false) | ||||
|       end | ||||
|     end | ||||
| 
 | ||||
|     shared_examples 'starting a new migration' do | ||||
|       it 'starts a new migration' do | ||||
|         request | ||||
| 
 | ||||
|  | @ -278,6 +281,17 @@ RSpec.describe API::BulkImports, feature_category: :importers do | |||
|     end | ||||
| 
 | ||||
|     include_examples 'disabled feature' | ||||
| 
 | ||||
|     context 'when request exceeds rate limits' do | ||||
|       it 'prevents user from starting a new migration' do | ||||
|         allow(::Gitlab::ApplicationRateLimiter).to receive(:throttled?).and_return(true) | ||||
| 
 | ||||
|         request | ||||
| 
 | ||||
|         expect(response).to have_gitlab_http_status(:too_many_requests) | ||||
|         expect(json_response['message']['error']).to eq('This endpoint has been requested too many times. Try again later.') | ||||
|       end | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   describe 'GET /bulk_imports/entities' do | ||||
|  |  | |||
|  | @ -7,14 +7,15 @@ RSpec.describe PwaController, feature_category: :navigation do | |||
|     it 'responds with json' do | ||||
|       get manifest_path(format: :json) | ||||
| 
 | ||||
|       expect(response.body).to include('The complete DevOps platform.') | ||||
|       expect(Gitlab::Json.parse(response.body)).to include({ 'name' => 'GitLab' }) | ||||
|       expect(Gitlab::Json.parse(response.body)).to include({ 'short_name' => 'GitLab' }) | ||||
|       expect(response.body).to include('The complete DevOps platform.') | ||||
|       expect(response).to have_gitlab_http_status(:success) | ||||
|     end | ||||
| 
 | ||||
|     context 'with customized appearance' do | ||||
|       let_it_be(:appearance) do | ||||
|         create(:appearance, title: 'Long name', pwa_short_name: 'Short name', description: 'This is a test') | ||||
|         create(:appearance, pwa_name: 'PWA name', pwa_short_name: 'Short name', pwa_description: 'This is a test') | ||||
|       end | ||||
| 
 | ||||
|       it 'uses custom values', :aggregate_failures do | ||||
|  | @ -22,7 +23,7 @@ RSpec.describe PwaController, feature_category: :navigation do | |||
| 
 | ||||
|         expect(Gitlab::Json.parse(response.body)).to include({ | ||||
|                                                                'description' => 'This is a test', | ||||
|                                                                'name' => 'Long name', | ||||
|                                                                'name' => 'PWA name', | ||||
|                                                                'short_name' => 'Short name' | ||||
|                                                              }) | ||||
|         expect(response).to have_gitlab_http_status(:success) | ||||
|  |  | |||
|  | @ -606,7 +606,7 @@ RSpec.describe WebHookService, :request_store, :clean_gitlab_redis_shared_state | |||
| 
 | ||||
|     def expect_to_rate_limit(hook, threshold:, throttled: false) | ||||
|       expect(Gitlab::ApplicationRateLimiter).to receive(:throttled?) | ||||
|         .with(:web_hook_calls, scope: [hook.parent.root_namespace], threshold: threshold) | ||||
|         .with(:web_hook_calls_high, scope: [hook.parent.root_namespace], threshold: threshold) | ||||
|         .and_return(throttled) | ||||
|     end | ||||
| 
 | ||||
|  | @ -621,7 +621,7 @@ RSpec.describe WebHookService, :request_store, :clean_gitlab_redis_shared_state | |||
| 
 | ||||
|     context 'when rate limiting is configured' do | ||||
|       let_it_be(:threshold) { 3 } | ||||
|       let_it_be(:plan_limits) { create(:plan_limits, :default_plan, web_hook_calls: threshold) } | ||||
|       let_it_be(:plan_limits) { create(:plan_limits, :default_plan, web_hook_calls_high: threshold) } | ||||
| 
 | ||||
|       it 'queues a worker and tracks the call' do | ||||
|         expect_to_rate_limit(project_hook, threshold: threshold) | ||||
|  |  | |||
|  | @ -3999,10 +3999,10 @@ core-js-pure@^3.0.0: | |||
|   resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.6.5.tgz#c79e75f5e38dbc85a662d91eea52b8256d53b813" | ||||
|   integrity sha512-lacdXOimsiD0QyNf9BC/mxivNJ/ybBGJXQFKzRekp1WTHoVUWsUHEn+2T8GJAzzIhyOuXA+gOxCVN3l+5PLPUA== | ||||
| 
 | ||||
| core-js@^3.27.1, core-js@^3.6.5: | ||||
|   version "3.27.1" | ||||
|   resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.27.1.tgz#23cc909b315a6bb4e418bf40a52758af2103ba46" | ||||
|   integrity sha512-GutwJLBChfGCpwwhbYoqfv03LAfmiz7e7D/BNxzeMxwQf10GRSzqiOjx7AmtEk+heiD/JWmBuyBPgFtx0Sg1ww== | ||||
| core-js@^3.27.2, core-js@^3.6.5: | ||||
|   version "3.27.2" | ||||
|   resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.27.2.tgz#85b35453a424abdcacb97474797815f4d62ebbf7" | ||||
|   integrity sha512-9ashVQskuh5AZEZ1JdQWp1GqSoC1e1G87MzRqg2gIfVAQ7Qn9K+uFj8EcniUFA4P2NLZfV+TOlX1SzoKfo+s7w== | ||||
| 
 | ||||
| core-util-is@~1.0.0: | ||||
|   version "1.0.3" | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue