Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
		
							parent
							
								
									abd8aecf4b
								
							
						
					
					
						commit
						ce16444418
					
				|  | @ -50,6 +50,8 @@ module Types | ||||||
|             null: true, |             null: true, | ||||||
|             description: 'How long the job was enqueued before starting.' |             description: 'How long the job was enqueued before starting.' | ||||||
| 
 | 
 | ||||||
|  |       field :downstream_pipeline, Types::Ci::PipelineType, null: true, | ||||||
|  |             description: 'Downstream pipeline for a bridge.' | ||||||
|       field :previous_stage_jobs_or_needs, Types::Ci::JobNeedUnion.connection_type, null: true, |       field :previous_stage_jobs_or_needs, Types::Ci::JobNeedUnion.connection_type, null: true, | ||||||
|             description: 'Jobs that must complete before the job runs. Returns `BuildNeed`, which is the needed jobs if the job uses the `needs` keyword, or the previous stage jobs otherwise.' |             description: 'Jobs that must complete before the job runs. Returns `BuildNeed`, which is the needed jobs if the job uses the `needs` keyword, or the previous stage jobs otherwise.' | ||||||
|       field :detailed_status, Types::Ci::DetailedStatusType, null: true, |       field :detailed_status, Types::Ci::DetailedStatusType, null: true, | ||||||
|  | @ -89,6 +91,10 @@ module Types | ||||||
|         Gitlab::Graphql::Loaders::BatchModelLoader.new(::Ci::Pipeline, object.pipeline_id).find |         Gitlab::Graphql::Loaders::BatchModelLoader.new(::Ci::Pipeline, object.pipeline_id).find | ||||||
|       end |       end | ||||||
| 
 | 
 | ||||||
|  |       def downstream_pipeline | ||||||
|  |         object.downstream_pipeline if object.respond_to?(:downstream_pipeline) | ||||||
|  |       end | ||||||
|  | 
 | ||||||
|       def tags |       def tags | ||||||
|         object.tags.map(&:name) if object.is_a?(::Ci::Build) |         object.tags.map(&:name) if object.is_a?(::Ci::Build) | ||||||
|       end |       end | ||||||
|  |  | ||||||
|  | @ -54,6 +54,10 @@ module Types | ||||||
|             description: "Number of jobs processed by the runner (limited to #{JOB_COUNT_LIMIT}, plus one to indicate that more items exist)." |             description: "Number of jobs processed by the runner (limited to #{JOB_COUNT_LIMIT}, plus one to indicate that more items exist)." | ||||||
|       field :admin_url, GraphQL::Types::String, null: true, |       field :admin_url, GraphQL::Types::String, null: true, | ||||||
|             description: 'Admin URL of the runner. Only available for administrators.' |             description: 'Admin URL of the runner. Only available for administrators.' | ||||||
|  |       field :executor_name, GraphQL::Types::String, null: true, | ||||||
|  |             description: 'Executor last advertised by the runner.', | ||||||
|  |             method: :executor_name, | ||||||
|  |             feature_flag: :graphql_ci_runner_executor | ||||||
| 
 | 
 | ||||||
|       def job_count |       def job_count | ||||||
|         # We limit to 1 above the JOB_COUNT_LIMIT to indicate that more items exist after JOB_COUNT_LIMIT |         # We limit to 1 above the JOB_COUNT_LIMIT to indicate that more items exist after JOB_COUNT_LIMIT | ||||||
|  |  | ||||||
|  | @ -441,6 +441,7 @@ module Ci | ||||||
|     private |     private | ||||||
| 
 | 
 | ||||||
|     EXECUTOR_NAME_TO_TYPES = { |     EXECUTOR_NAME_TO_TYPES = { | ||||||
|  |       'unknown' => :unknown, | ||||||
|       'custom' => :custom, |       'custom' => :custom, | ||||||
|       'shell' => :shell, |       'shell' => :shell, | ||||||
|       'docker' => :docker, |       'docker' => :docker, | ||||||
|  | @ -454,6 +455,8 @@ module Ci | ||||||
|       'kubernetes' => :kubernetes |       'kubernetes' => :kubernetes | ||||||
|     }.freeze |     }.freeze | ||||||
| 
 | 
 | ||||||
|  |     EXECUTOR_TYPE_TO_NAMES = EXECUTOR_NAME_TO_TYPES.invert.freeze | ||||||
|  | 
 | ||||||
|     def cleanup_runner_queue |     def cleanup_runner_queue | ||||||
|       Gitlab::Redis::SharedState.with do |redis| |       Gitlab::Redis::SharedState.with do |redis| | ||||||
|         redis.del(runner_queue_key) |         redis.del(runner_queue_key) | ||||||
|  |  | ||||||
|  | @ -11,5 +11,9 @@ module Ci | ||||||
| 
 | 
 | ||||||
|     delegator_override :locked |     delegator_override :locked | ||||||
|     alias_method :locked, :locked? |     alias_method :locked, :locked? | ||||||
|  | 
 | ||||||
|  |     def executor_name | ||||||
|  |       Ci::Runner::EXECUTOR_TYPE_TO_NAMES[executor_type&.to_sym] | ||||||
|  |     end | ||||||
|   end |   end | ||||||
| end | end | ||||||
|  |  | ||||||
|  | @ -0,0 +1,8 @@ | ||||||
|  | --- | ||||||
|  | name: graphql_ci_runner_executor | ||||||
|  | introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/76534 | ||||||
|  | rollout_issue_url: | ||||||
|  | milestone: '14.7' | ||||||
|  | type: development | ||||||
|  | group: group::runner | ||||||
|  | default_enabled: false | ||||||
|  | @ -1,13 +1,13 @@ | ||||||
| --- | --- | ||||||
| data_category: optional | data_category: optional | ||||||
| key_path: usage_activity_by_stage_monthly.manage.bulk_imports.gitlab | key_path: usage_activity_by_stage_monthly.manage.bulk_imports.gitlab | ||||||
| description: DEPRECATED - Count of projects imported using bulk imports | description: REMOVED - Count of projects imported using bulk imports | ||||||
| product_section: dev | product_section: dev | ||||||
| product_stage: manage | product_stage: manage | ||||||
| product_group: group::import | product_group: group::import | ||||||
| product_category: importers | product_category: importers | ||||||
| value_type: number | value_type: number | ||||||
| status: deprecated | status: removed | ||||||
| time_frame: 28d | time_frame: 28d | ||||||
| data_source: database | data_source: database | ||||||
| distribution: | distribution: | ||||||
|  |  | ||||||
|  | @ -7,7 +7,7 @@ product_stage: manage | ||||||
| product_group: group::import | product_group: group::import | ||||||
| product_category: importers | product_category: importers | ||||||
| value_type: number | value_type: number | ||||||
| status: deprecated | status: removed | ||||||
| time_frame: 28d | time_frame: 28d | ||||||
| data_source: database | data_source: database | ||||||
| distribution: | distribution: | ||||||
|  |  | ||||||
|  | @ -7,7 +7,7 @@ product_stage: manage | ||||||
| product_group: group::import | product_group: group::import | ||||||
| product_category: importers | product_category: importers | ||||||
| value_type: number | value_type: number | ||||||
| status: deprecated | status: removed | ||||||
| time_frame: 28d | time_frame: 28d | ||||||
| data_source: database | data_source: database | ||||||
| distribution: | distribution: | ||||||
|  |  | ||||||
|  | @ -7,7 +7,7 @@ product_stage: manage | ||||||
| product_group: group::import | product_group: group::import | ||||||
| product_category: importers | product_category: importers | ||||||
| value_type: number | value_type: number | ||||||
| status: deprecated | status: removed | ||||||
| time_frame: 28d | time_frame: 28d | ||||||
| data_source: database | data_source: database | ||||||
| distribution: | distribution: | ||||||
|  |  | ||||||
|  | @ -7,7 +7,7 @@ product_stage: manage | ||||||
| product_group: group::import | product_group: group::import | ||||||
| product_category: importers | product_category: importers | ||||||
| value_type: number | value_type: number | ||||||
| status: deprecated | status: removed | ||||||
| time_frame: 28d | time_frame: 28d | ||||||
| data_source: database | data_source: database | ||||||
| distribution: | distribution: | ||||||
|  |  | ||||||
|  | @ -7,7 +7,7 @@ product_stage: manage | ||||||
| product_group: group::import | product_group: group::import | ||||||
| product_category: importers | product_category: importers | ||||||
| value_type: number | value_type: number | ||||||
| status: deprecated | status: removed | ||||||
| time_frame: 28d | time_frame: 28d | ||||||
| data_source: database | data_source: database | ||||||
| distribution: | distribution: | ||||||
|  |  | ||||||
|  | @ -7,7 +7,7 @@ product_stage: manage | ||||||
| product_group: group::import | product_group: group::import | ||||||
| product_category: importers | product_category: importers | ||||||
| value_type: number | value_type: number | ||||||
| status: deprecated | status: removed | ||||||
| time_frame: 28d | time_frame: 28d | ||||||
| data_source: database | data_source: database | ||||||
| distribution: | distribution: | ||||||
|  |  | ||||||
|  | @ -7,7 +7,7 @@ product_stage: manage | ||||||
| product_group: group::import | product_group: group::import | ||||||
| product_category: importers | product_category: importers | ||||||
| value_type: number | value_type: number | ||||||
| status: deprecated | status: removed | ||||||
| time_frame: 28d | time_frame: 28d | ||||||
| data_source: database | data_source: database | ||||||
| distribution: | distribution: | ||||||
|  |  | ||||||
|  | @ -7,7 +7,7 @@ product_stage: manage | ||||||
| product_group: group::import | product_group: group::import | ||||||
| product_category: importers | product_category: importers | ||||||
| value_type: number | value_type: number | ||||||
| status: deprecated | status: removed | ||||||
| time_frame: 28d | time_frame: 28d | ||||||
| data_source: database | data_source: database | ||||||
| distribution: | distribution: | ||||||
|  |  | ||||||
|  | @ -7,7 +7,7 @@ product_stage: manage | ||||||
| product_group: group::import | product_group: group::import | ||||||
| product_category: importers | product_category: importers | ||||||
| value_type: number | value_type: number | ||||||
| status: deprecated | status: removed | ||||||
| time_frame: 28d | time_frame: 28d | ||||||
| data_source: database | data_source: database | ||||||
| distribution: | distribution: | ||||||
|  |  | ||||||
|  | @ -7,7 +7,7 @@ product_stage: manage | ||||||
| product_group: group::import | product_group: group::import | ||||||
| product_category: importers | product_category: importers | ||||||
| value_type: number | value_type: number | ||||||
| status: deprecated | status: removed | ||||||
| time_frame: 28d | time_frame: 28d | ||||||
| data_source: database | data_source: database | ||||||
| distribution: | distribution: | ||||||
|  |  | ||||||
|  | @ -7,7 +7,7 @@ product_stage: manage | ||||||
| product_group: group::import | product_group: group::import | ||||||
| product_category: importers | product_category: importers | ||||||
| value_type: number | value_type: number | ||||||
| status: deprecated | status: removed | ||||||
| time_frame: 28d | time_frame: 28d | ||||||
| data_source: database | data_source: database | ||||||
| distribution: | distribution: | ||||||
|  |  | ||||||
|  | @ -7,7 +7,7 @@ product_stage: manage | ||||||
| product_group: group::import | product_group: group::import | ||||||
| product_category: importers | product_category: importers | ||||||
| value_type: number | value_type: number | ||||||
| status: deprecated | status: removed | ||||||
| time_frame: 28d | time_frame: 28d | ||||||
| data_source: database | data_source: database | ||||||
| distribution: | distribution: | ||||||
|  |  | ||||||
|  | @ -7,7 +7,7 @@ product_stage: manage | ||||||
| product_group: group::import | product_group: group::import | ||||||
| product_category: importers | product_category: importers | ||||||
| value_type: number | value_type: number | ||||||
| status: deprecated | status: removed | ||||||
| time_frame: 28d | time_frame: 28d | ||||||
| data_source: database | data_source: database | ||||||
| distribution: | distribution: | ||||||
|  |  | ||||||
|  | @ -7,7 +7,7 @@ product_stage: manage | ||||||
| product_group: group::import | product_group: group::import | ||||||
| product_category: importers | product_category: importers | ||||||
| value_type: number | value_type: number | ||||||
| status: deprecated | status: removed | ||||||
| time_frame: 28d | time_frame: 28d | ||||||
| data_source: database | data_source: database | ||||||
| distribution: | distribution: | ||||||
|  |  | ||||||
|  | @ -8,7 +8,7 @@ product_stage: manage | ||||||
| product_group: group::import | product_group: group::import | ||||||
| product_category: importers | product_category: importers | ||||||
| value_type: number | value_type: number | ||||||
| status: deprecated | status: removed | ||||||
| time_frame: all | time_frame: all | ||||||
| data_source: database | data_source: database | ||||||
| distribution: | distribution: | ||||||
|  |  | ||||||
|  | @ -7,7 +7,7 @@ product_stage: manage | ||||||
| product_group: group::import | product_group: group::import | ||||||
| product_category: importers | product_category: importers | ||||||
| value_type: number | value_type: number | ||||||
| status: deprecated | status: removed | ||||||
| time_frame: all | time_frame: all | ||||||
| data_source: database | data_source: database | ||||||
| distribution: | distribution: | ||||||
|  |  | ||||||
|  | @ -7,7 +7,7 @@ product_stage: manage | ||||||
| product_group: group::import | product_group: group::import | ||||||
| product_category: importers | product_category: importers | ||||||
| value_type: number | value_type: number | ||||||
| status: deprecated | status: removed | ||||||
| time_frame: all | time_frame: all | ||||||
| data_source: database | data_source: database | ||||||
| distribution: | distribution: | ||||||
|  |  | ||||||
|  | @ -7,7 +7,7 @@ product_stage: manage | ||||||
| product_group: group::import | product_group: group::import | ||||||
| product_category: importers | product_category: importers | ||||||
| value_type: number | value_type: number | ||||||
| status: deprecated | status: removed | ||||||
| time_frame: all | time_frame: all | ||||||
| data_source: database | data_source: database | ||||||
| distribution: | distribution: | ||||||
|  |  | ||||||
|  | @ -7,7 +7,7 @@ product_stage: manage | ||||||
| product_group: group::import | product_group: group::import | ||||||
| product_category: importers | product_category: importers | ||||||
| value_type: number | value_type: number | ||||||
| status: deprecated | status: removed | ||||||
| time_frame: all | time_frame: all | ||||||
| data_source: database | data_source: database | ||||||
| distribution: | distribution: | ||||||
|  |  | ||||||
|  | @ -7,7 +7,7 @@ product_stage: manage | ||||||
| product_group: group::import | product_group: group::import | ||||||
| product_category: importers | product_category: importers | ||||||
| value_type: number | value_type: number | ||||||
| status: deprecated | status: removed | ||||||
| time_frame: all | time_frame: all | ||||||
| data_source: database | data_source: database | ||||||
| distribution: | distribution: | ||||||
|  |  | ||||||
|  | @ -7,7 +7,7 @@ product_stage: manage | ||||||
| product_group: group::import | product_group: group::import | ||||||
| product_category: importers | product_category: importers | ||||||
| value_type: number | value_type: number | ||||||
| status: deprecated | status: removed | ||||||
| time_frame: all | time_frame: all | ||||||
| data_source: database | data_source: database | ||||||
| distribution: | distribution: | ||||||
|  |  | ||||||
|  | @ -7,7 +7,7 @@ product_stage: manage | ||||||
| product_group: group::import | product_group: group::import | ||||||
| product_category: importers | product_category: importers | ||||||
| value_type: number | value_type: number | ||||||
| status: deprecated | status: removed | ||||||
| time_frame: all | time_frame: all | ||||||
| data_source: database | data_source: database | ||||||
| distribution: | distribution: | ||||||
|  |  | ||||||
|  | @ -7,7 +7,7 @@ product_stage: manage | ||||||
| product_group: group::import | product_group: group::import | ||||||
| product_category: importers | product_category: importers | ||||||
| value_type: number | value_type: number | ||||||
| status: deprecated | status: removed | ||||||
| time_frame: all | time_frame: all | ||||||
| data_source: database | data_source: database | ||||||
| distribution: | distribution: | ||||||
|  |  | ||||||
|  | @ -7,7 +7,7 @@ product_stage: manage | ||||||
| product_group: group::import | product_group: group::import | ||||||
| product_category: importers | product_category: importers | ||||||
| value_type: number | value_type: number | ||||||
| status: deprecated | status: removed | ||||||
| time_frame: all | time_frame: all | ||||||
| data_source: database | data_source: database | ||||||
| distribution: | distribution: | ||||||
|  |  | ||||||
|  | @ -7,7 +7,7 @@ product_stage: manage | ||||||
| product_group: group::import | product_group: group::import | ||||||
| product_category: importers | product_category: importers | ||||||
| value_type: number | value_type: number | ||||||
| status: deprecated | status: removed | ||||||
| time_frame: all | time_frame: all | ||||||
| data_source: database | data_source: database | ||||||
| distribution: | distribution: | ||||||
|  |  | ||||||
|  | @ -7,7 +7,7 @@ product_stage: manage | ||||||
| product_group: group::import | product_group: group::import | ||||||
| product_category: importers | product_category: importers | ||||||
| value_type: number | value_type: number | ||||||
| status: deprecated | status: removed | ||||||
| time_frame: all | time_frame: all | ||||||
| data_source: database | data_source: database | ||||||
| distribution: | distribution: | ||||||
|  |  | ||||||
|  | @ -7,7 +7,7 @@ product_stage: manage | ||||||
| product_group: group::import | product_group: group::import | ||||||
| product_category: importers | product_category: importers | ||||||
| value_type: number | value_type: number | ||||||
| status: deprecated | status: removed | ||||||
| time_frame: all | time_frame: all | ||||||
| data_source: database | data_source: database | ||||||
| distribution: | distribution: | ||||||
|  |  | ||||||
|  | @ -8,7 +8,7 @@ product_stage: manage | ||||||
| product_group: group::import | product_group: group::import | ||||||
| product_category: importers | product_category: importers | ||||||
| value_type: number | value_type: number | ||||||
| status: deprecated | status: removed | ||||||
| time_frame: all | time_frame: all | ||||||
| data_source: database | data_source: database | ||||||
| distribution: | distribution: | ||||||
|  |  | ||||||
|  | @ -7,7 +7,7 @@ product_stage: manage | ||||||
| product_group: group::import | product_group: group::import | ||||||
| product_category: importers | product_category: importers | ||||||
| value_type: number | value_type: number | ||||||
| status: deprecated | status: removed | ||||||
| time_frame: all | time_frame: all | ||||||
| data_source: database | data_source: database | ||||||
| distribution: | distribution: | ||||||
|  |  | ||||||
|  | @ -1,14 +1,11 @@ | ||||||
| --- | --- | ||||||
| stage: Create | stage: Create | ||||||
| group: Editor | group: Editor | ||||||
| info: "To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments" | info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments | ||||||
| type: reference |  | ||||||
| --- | --- | ||||||
| 
 | 
 | ||||||
| # Merge request diffs storage **(FREE SELF)** | # Merge request diffs storage **(FREE SELF)** | ||||||
| 
 | 
 | ||||||
| > [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/52568) in GitLab 11.8. |  | ||||||
| 
 |  | ||||||
| Merge request diffs are size-limited copies of diffs associated with merge | Merge request diffs are size-limited copies of diffs associated with merge | ||||||
| requests. When viewing a merge request, diffs are sourced from these copies | requests. When viewing a merge request, diffs are sourced from these copies | ||||||
| wherever possible as a performance optimization. | wherever possible as a performance optimization. | ||||||
|  |  | ||||||
|  | @ -8813,6 +8813,7 @@ Represents the total number of issues and their weights for a particular day. | ||||||
| | <a id="cijobcreatedat"></a>`createdAt` | [`Time!`](#time) | When the job was created. | | | <a id="cijobcreatedat"></a>`createdAt` | [`Time!`](#time) | When the job was created. | | ||||||
| | <a id="cijobcreatedbytag"></a>`createdByTag` | [`Boolean!`](#boolean) | Whether the job was created by a tag. | | | <a id="cijobcreatedbytag"></a>`createdByTag` | [`Boolean!`](#boolean) | Whether the job was created by a tag. | | ||||||
| | <a id="cijobdetailedstatus"></a>`detailedStatus` | [`DetailedStatus`](#detailedstatus) | Detailed status of the job. | | | <a id="cijobdetailedstatus"></a>`detailedStatus` | [`DetailedStatus`](#detailedstatus) | Detailed status of the job. | | ||||||
|  | | <a id="cijobdownstreampipeline"></a>`downstreamPipeline` | [`Pipeline`](#pipeline) | Downstream pipeline for a bridge. | | ||||||
| | <a id="cijobduration"></a>`duration` | [`Int`](#int) | Duration of the job in seconds. | | | <a id="cijobduration"></a>`duration` | [`Int`](#int) | Duration of the job in seconds. | | ||||||
| | <a id="cijobfinishedat"></a>`finishedAt` | [`Time`](#time) | When a job has finished running. | | | <a id="cijobfinishedat"></a>`finishedAt` | [`Time`](#time) | When a job has finished running. | | ||||||
| | <a id="cijobid"></a>`id` | [`JobID`](#jobid) | ID of the job. | | | <a id="cijobid"></a>`id` | [`JobID`](#jobid) | ID of the job. | | ||||||
|  | @ -8887,6 +8888,7 @@ Represents the total number of issues and their weights for a particular day. | ||||||
| | <a id="cirunneradminurl"></a>`adminUrl` | [`String`](#string) | Admin URL of the runner. Only available for administrators. | | | <a id="cirunneradminurl"></a>`adminUrl` | [`String`](#string) | Admin URL of the runner. Only available for administrators. | | ||||||
| | <a id="cirunnercontactedat"></a>`contactedAt` | [`Time`](#time) | Last contact from the runner. | | | <a id="cirunnercontactedat"></a>`contactedAt` | [`Time`](#time) | Last contact from the runner. | | ||||||
| | <a id="cirunnerdescription"></a>`description` | [`String`](#string) | Description of the runner. | | | <a id="cirunnerdescription"></a>`description` | [`String`](#string) | Description of the runner. | | ||||||
|  | | <a id="cirunnerexecutorname"></a>`executorName` | [`String`](#string) | Executor last advertised by the runner. Available only when feature flag `graphql_ci_runner_executor` is enabled. This flag is disabled by default, because the feature is experimental and is subject to change without notice. | | ||||||
| | <a id="cirunnerid"></a>`id` | [`CiRunnerID!`](#cirunnerid) | ID of the runner. | | | <a id="cirunnerid"></a>`id` | [`CiRunnerID!`](#cirunnerid) | ID of the runner. | | ||||||
| | <a id="cirunneripaddress"></a>`ipAddress` | [`String`](#string) | IP address of the runner. | | | <a id="cirunneripaddress"></a>`ipAddress` | [`String`](#string) | IP address of the runner. | | ||||||
| | <a id="cirunnerjobcount"></a>`jobCount` | [`Int`](#int) | Number of jobs processed by the runner (limited to 1000, plus one to indicate that more items exist). | | | <a id="cirunnerjobcount"></a>`jobCount` | [`Int`](#int) | Number of jobs processed by the runner (limited to 1000, plus one to indicate that more items exist). | | ||||||
|  |  | ||||||
|  | @ -1,8 +1,7 @@ | ||||||
| --- | --- | ||||||
| stage: Create | stage: Create | ||||||
| group: Editor | group: Editor | ||||||
| info: "To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments" | info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments | ||||||
| type: reference, api |  | ||||||
| --- | --- | ||||||
| 
 | 
 | ||||||
| # Project snippets **(FREE)** | # Project snippets **(FREE)** | ||||||
|  | @ -247,8 +246,6 @@ curl "https://gitlab.com/api/v4/projects/1/snippets/2/files/master/snippet%2Erb/ | ||||||
| 
 | 
 | ||||||
| ## Get user agent details | ## Get user agent details | ||||||
| 
 | 
 | ||||||
| > [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/29508) in GitLab 9.4. |  | ||||||
| 
 |  | ||||||
| Available only for users with the Administrator [role](../user/permissions.md). | Available only for users with the Administrator [role](../user/permissions.md). | ||||||
| 
 | 
 | ||||||
| ```plaintext | ```plaintext | ||||||
|  |  | ||||||
|  | @ -1,14 +1,11 @@ | ||||||
| --- | --- | ||||||
| stage: Create | stage: Create | ||||||
| group: Editor | group: Editor | ||||||
| info: "To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments" | info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments | ||||||
| type: reference, api |  | ||||||
| --- | --- | ||||||
| 
 | 
 | ||||||
| # Snippets API **(FREE)** | # Snippets API **(FREE)** | ||||||
| 
 | 
 | ||||||
| > [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/6373) in GitLab 8.15. |  | ||||||
| 
 |  | ||||||
| Snippets API operates on [snippets](../user/snippets.md). Related APIs exist for | Snippets API operates on [snippets](../user/snippets.md). Related APIs exist for | ||||||
| [project snippets](project_snippets.md) and | [project snippets](project_snippets.md) and | ||||||
| [moving snippets between storages](snippet_repository_storage_moves.md). | [moving snippets between storages](snippet_repository_storage_moves.md). | ||||||
|  | @ -449,8 +446,6 @@ Example response: | ||||||
| 
 | 
 | ||||||
| ## Get user agent details | ## Get user agent details | ||||||
| 
 | 
 | ||||||
| > [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/12655) in GitLab 9.4. |  | ||||||
| 
 |  | ||||||
| NOTE: | NOTE: | ||||||
| Available only for administrators. | Available only for administrators. | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1,14 +1,11 @@ | ||||||
| --- | --- | ||||||
| stage: Create | stage: Create | ||||||
| group: Editor | group: Editor | ||||||
| info: "To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments" | info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments | ||||||
| type: reference, api |  | ||||||
| --- | --- | ||||||
| 
 | 
 | ||||||
| # Project wikis API **(FREE)** | # Project wikis API **(FREE)** | ||||||
| 
 | 
 | ||||||
| > [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/13372) in GitLab 10.0. |  | ||||||
| 
 |  | ||||||
| The project [wikis](../user/project/wiki/index.md) API is available only in APIv4. | The project [wikis](../user/project/wiki/index.md) API is available only in APIv4. | ||||||
| An API for [group wikis](group_wikis.md) is also available. | An API for [group wikis](group_wikis.md) is also available. | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1,5 +1,4 @@ | ||||||
| --- | --- | ||||||
| type: reference, dev |  | ||||||
| stage: Create | stage: Create | ||||||
| group: Editor | group: Editor | ||||||
| info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments | info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments | ||||||
|  | @ -91,8 +90,6 @@ Only some data is persisted in the database: | ||||||
| 
 | 
 | ||||||
| The web UI uploads attachments through the REST API, which stores the files as commits in the wiki repository. | The web UI uploads attachments through the REST API, which stores the files as commits in the wiki repository. | ||||||
| 
 | 
 | ||||||
| Prior to GitLab 11.3 attachments were stored outside of the repository, [see this issue](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/33475). |  | ||||||
| 
 |  | ||||||
| ## Related topics | ## Related topics | ||||||
| 
 | 
 | ||||||
| - [Gollum installation instructions](https://github.com/gollum/gollum/wiki/Installation) | - [Gollum installation instructions](https://github.com/gollum/gollum/wiki/Installation) | ||||||
|  |  | ||||||
|  | @ -22,10 +22,6 @@ NOTE: | ||||||
| By default, all Git operations are first tried unauthenticated. Because of this, HTTP Git operations | By default, all Git operations are first tried unauthenticated. Because of this, HTTP Git operations | ||||||
| may trigger the rate limits configured for unauthenticated requests. | may trigger the rate limits configured for unauthenticated requests. | ||||||
| 
 | 
 | ||||||
| NOTE: |  | ||||||
| The rate limits for API requests don't affect requests made by the frontend, as these are always |  | ||||||
| counted as web traffic. |  | ||||||
| 
 |  | ||||||
| ## Enable unauthenticated API request rate limit | ## Enable unauthenticated API request rate limit | ||||||
| 
 | 
 | ||||||
| To enable the unauthenticated request rate limit: | To enable the unauthenticated request rate limit: | ||||||
|  |  | ||||||
|  | @ -110,6 +110,7 @@ The certificate [fingerprint algorithm](../../../integration/saml.md#notes-on-co | ||||||
| > - [Improved](https://gitlab.com/gitlab-org/gitlab/-/issues/292811) in GitLab 13.8, with an updated timeout experience. | > - [Improved](https://gitlab.com/gitlab-org/gitlab/-/issues/292811) in GitLab 13.8, with an updated timeout experience. | ||||||
| > - [Improved](https://gitlab.com/gitlab-org/gitlab/-/issues/211962) in GitLab 13.8 with allowing group owners to not go through SSO. | > - [Improved](https://gitlab.com/gitlab-org/gitlab/-/issues/211962) in GitLab 13.8 with allowing group owners to not go through SSO. | ||||||
| > - [Improved](https://gitlab.com/gitlab-org/gitlab/-/issues/9152) in GitLab 13.11 with enforcing open SSO session to use Git if this setting is switched on. | > - [Improved](https://gitlab.com/gitlab-org/gitlab/-/issues/9152) in GitLab 13.11 with enforcing open SSO session to use Git if this setting is switched on. | ||||||
|  | > - [Improved](https://gitlab.com/gitlab-org/gitlab/-/issues/339888) in GitLab 14.7 to not enforce SSO checks for Git activity originating from CI/CD jobs. | ||||||
| 
 | 
 | ||||||
| With this option enabled, users (except users with the Owner role) must access GitLab using your group GitLab single sign-on URL to access group resources. Users added manually as members can't access group resources. | With this option enabled, users (except users with the Owner role) must access GitLab using your group GitLab single sign-on URL to access group resources. Users added manually as members can't access group resources. | ||||||
| 
 | 
 | ||||||
|  | @ -127,6 +128,7 @@ SSO has the following effects when enabled: | ||||||
|   even if the project is forked. |   even if the project is forked. | ||||||
| - For Git activity over SSH and HTTPS, users must have at least one active session signed-in through SSO before they can push to or | - For Git activity over SSH and HTTPS, users must have at least one active session signed-in through SSO before they can push to or | ||||||
|   pull from a GitLab repository. |   pull from a GitLab repository. | ||||||
|  | - Git activity originating from CI/CD jobs do not have the SSO check enforced. | ||||||
| - Credentials that are not tied to regular users (for example, access tokens and deploy keys) do not have the SSO check enforced. | - Credentials that are not tied to regular users (for example, access tokens and deploy keys) do not have the SSO check enforced. | ||||||
| - Users must be signed-in through SSO before they can pull images using the [Dependency Proxy](../../packages/dependency_proxy/index.md). | - Users must be signed-in through SSO before they can pull images using the [Dependency Proxy](../../packages/dependency_proxy/index.md). | ||||||
| <!-- Add bullet for API activity when https://gitlab.com/gitlab-org/gitlab/-/issues/9152 is complete --> | <!-- Add bullet for API activity when https://gitlab.com/gitlab-org/gitlab/-/issues/9152 is complete --> | ||||||
|  |  | ||||||
|  | @ -2,13 +2,10 @@ | ||||||
| stage: Create | stage: Create | ||||||
| group: Code Review | group: Code Review | ||||||
| info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments | info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments | ||||||
| type: reference, howto |  | ||||||
| --- | --- | ||||||
| 
 | 
 | ||||||
| # Allow collaboration on merge requests across forks **(FREE)** | # Allow collaboration on merge requests across forks **(FREE)** | ||||||
| 
 | 
 | ||||||
| > [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/17395) in GitLab 10.6. |  | ||||||
| 
 |  | ||||||
| When a user opens a merge request from a fork, they are given the option to allow | When a user opens a merge request from a fork, they are given the option to allow | ||||||
| upstream members to collaborate with them on the source branch. This allows | upstream members to collaborate with them on the source branch. This allows | ||||||
| the members of the upstream project to make small fixes or rebase branches | the members of the upstream project to make small fixes or rebase branches | ||||||
|  |  | ||||||
|  | @ -2,7 +2,6 @@ | ||||||
| stage: Create | stage: Create | ||||||
| group: Code Review | group: Code Review | ||||||
| info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments | info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments | ||||||
| type: howto |  | ||||||
| description: "How to create merge requests in GitLab." | description: "How to create merge requests in GitLab." | ||||||
| disqus_identifier: 'https://docs.gitlab.com/ee/gitlab-basics/add-merge-request.html' | disqus_identifier: 'https://docs.gitlab.com/ee/gitlab-basics/add-merge-request.html' | ||||||
| --- | --- | ||||||
|  | @ -111,10 +110,6 @@ For more information, [see the forking workflow documentation](../repository/for | ||||||
| 
 | 
 | ||||||
| ## By sending an email | ## By sending an email | ||||||
| 
 | 
 | ||||||
| > The format of the generated email address changed in GitLab 11.7. |  | ||||||
|   The earlier format is still supported so existing aliases |  | ||||||
|   or contacts still work. |  | ||||||
| 
 |  | ||||||
| You can create a merge request by sending an email message to GitLab. | You can create a merge request by sending an email message to GitLab. | ||||||
| The merge request target branch is the project's default branch. | The merge request target branch is the project's default branch. | ||||||
| 
 | 
 | ||||||
|  | @ -142,8 +137,6 @@ A merge request is created. | ||||||
| 
 | 
 | ||||||
| ### Add attachments when creating a merge request by email | ### Add attachments when creating a merge request by email | ||||||
| 
 | 
 | ||||||
| > [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/22723) in GitLab 11.5. |  | ||||||
| 
 |  | ||||||
| You can add commits to a merge request by adding | You can add commits to a merge request by adding | ||||||
| patches as attachments to the email. All attachments with a filename | patches as attachments to the email. All attachments with a filename | ||||||
| ending in `.patch` are considered patches and are processed | ending in `.patch` are considered patches and are processed | ||||||
|  |  | ||||||
|  | @ -2,7 +2,6 @@ | ||||||
| stage: Create | stage: Create | ||||||
| group: Code Review | group: Code Review | ||||||
| info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments | info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments | ||||||
| type: index, reference |  | ||||||
| description: "Getting started with merge requests." | description: "Getting started with merge requests." | ||||||
| --- | --- | ||||||
| 
 | 
 | ||||||
|  | @ -92,8 +91,7 @@ and the merge request is added to their | ||||||
| 
 | 
 | ||||||
| #### Multiple assignees **(PREMIUM)** | #### Multiple assignees **(PREMIUM)** | ||||||
| 
 | 
 | ||||||
| > - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/2004) in GitLab 11.11. | > Moved to GitLab Premium in 13.9 | ||||||
| > - Moved to GitLab Premium in 13.9 |  | ||||||
| 
 | 
 | ||||||
| Multiple people often review merge requests at the same time. | Multiple people often review merge requests at the same time. | ||||||
| GitLab allows you to have multiple assignees for merge requests | GitLab allows you to have multiple assignees for merge requests | ||||||
|  |  | ||||||
|  | @ -2,7 +2,6 @@ | ||||||
| stage: Create | stage: Create | ||||||
| group: Code Review | group: Code Review | ||||||
| info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments | info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments | ||||||
| type: reference, concepts |  | ||||||
| --- | --- | ||||||
| 
 | 
 | ||||||
| # Revert changes **(FREE)** | # Revert changes **(FREE)** | ||||||
|  | @ -12,11 +11,6 @@ by clicking the **Revert** button in merge requests and commit details. | ||||||
| 
 | 
 | ||||||
| ## Revert a merge request | ## Revert a merge request | ||||||
| 
 | 
 | ||||||
| NOTE: |  | ||||||
| The **Revert** button is available only for merge requests |  | ||||||
| created in GitLab 8.5 and later. However, you can still revert a merge request |  | ||||||
| by reverting the merge commit from the list of Commits page. |  | ||||||
| 
 |  | ||||||
| NOTE: | NOTE: | ||||||
| The **Revert** button is shown only for projects that use the | The **Revert** button is shown only for projects that use the | ||||||
| merge method "Merge Commit", which can be set under the project's | merge method "Merge Commit", which can be set under the project's | ||||||
|  |  | ||||||
|  | @ -39,8 +39,6 @@ changes appears as a system note. | ||||||
| 
 | 
 | ||||||
| ## Find the merge request that introduced a change | ## Find the merge request that introduced a change | ||||||
| 
 | 
 | ||||||
| > [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/2383) in GitLab 10.5. |  | ||||||
| 
 |  | ||||||
| When viewing the commit details page, GitLab links to the merge request (or | When viewing the commit details page, GitLab links to the merge request (or | ||||||
| merge requests, if it's in more than one) containing that commit. | merge requests, if it's in more than one) containing that commit. | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -2,7 +2,6 @@ | ||||||
| stage: Create | stage: Create | ||||||
| group: Editor | group: Editor | ||||||
| info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments | info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments | ||||||
| type: howto |  | ||||||
| --- | --- | ||||||
| 
 | 
 | ||||||
| # GitLab Web Editor **(FREE)** | # GitLab Web Editor **(FREE)** | ||||||
|  | @ -118,8 +117,6 @@ There are multiple ways to create a branch from the GitLab web interface. | ||||||
| 
 | 
 | ||||||
| ### Create a new branch from an issue | ### Create a new branch from an issue | ||||||
| 
 | 
 | ||||||
| > [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/2808) in GitLab 8.6. |  | ||||||
| 
 |  | ||||||
| If your development workflow requires an issue for every merge | If your development workflow requires an issue for every merge | ||||||
| request, you can create a branch directly from the issue to speed the process up. | request, you can create a branch directly from the issue to speed the process up. | ||||||
| The new branch, and later its merge request, are marked as related to this issue. | The new branch, and later its merge request, are marked as related to this issue. | ||||||
|  |  | ||||||
|  | @ -1,8 +1,7 @@ | ||||||
| --- | --- | ||||||
| stage: Create | stage: Create | ||||||
| group: Editor | group: Editor | ||||||
| info: "To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments" | info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments | ||||||
| type: reference, how-to |  | ||||||
| --- | --- | ||||||
| 
 | 
 | ||||||
| # Wiki **(FREE)** | # Wiki **(FREE)** | ||||||
|  | @ -87,11 +86,7 @@ Users with the [Developer role](../../permissions.md) can create new wiki pages: | ||||||
|    [special characters](#special-characters-in-page-titles) for subdirectories and formatting, |    [special characters](#special-characters-in-page-titles) for subdirectories and formatting, | ||||||
|    and have [length restrictions](#length-restrictions-for-file-and-directory-names). |    and have [length restrictions](#length-restrictions-for-file-and-directory-names). | ||||||
| 1. Add content to your wiki page. | 1. Add content to your wiki page. | ||||||
| 1. Optional. Attach a file, and GitLab stores it according to your installed version of GitLab: | 1. Optional. Attach a file, and GitLab stores it in the wiki's Git repository. | ||||||
|    - *Files added in [GitLab 11.3 and later](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/33475):* |  | ||||||
|      Files are stored in the wiki's Git repository. |  | ||||||
|    - *Files added GitLab 11.2 and earlier:* Files are stored in GitLab itself. To add |  | ||||||
|      the file to the wiki's Git repository, you must re-upload the file. |  | ||||||
| 1. Add a **Commit message**. Git requires a commit message, so GitLab creates one | 1. Add a **Commit message**. Git requires a commit message, so GitLab creates one | ||||||
|    if you don't enter one yourself. |    if you don't enter one yourself. | ||||||
| 1. Select **Create page**. | 1. Select **Create page**. | ||||||
|  | @ -227,9 +222,9 @@ You can see the changes made in a version of a wiki page, similar to versioned d | ||||||
| 
 | 
 | ||||||
| ## Track wiki events | ## Track wiki events | ||||||
| 
 | 
 | ||||||
| > - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/14902) in **GitLab 12.10.** | > - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/14902) in GitLab 12.10. | ||||||
| > - Git events were [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/216014) in **GitLab 13.0.** | > - Git events were [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/216014) in GitLab 13.0. | ||||||
| > - [Feature flag for Git events was removed](https://gitlab.com/gitlab-org/gitlab/-/issues/258665) in **GitLab 13.5** | > - [Feature flag for Git events was removed](https://gitlab.com/gitlab-org/gitlab/-/issues/258665) in GitLab 13.5. | ||||||
| 
 | 
 | ||||||
| GitLab tracks wiki creation, deletion, and update events. These events are displayed on these pages: | GitLab tracks wiki creation, deletion, and update events. These events are displayed on these pages: | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1,8 +1,7 @@ | ||||||
| --- | --- | ||||||
| stage: Create | stage: Create | ||||||
| group: Editor | group: Editor | ||||||
| info: "To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments" | info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments | ||||||
| type: index, reference, howto |  | ||||||
| --- | --- | ||||||
| 
 | 
 | ||||||
| # Searching in GitLab **(FREE)** | # Searching in GitLab **(FREE)** | ||||||
|  | @ -102,8 +101,7 @@ You can filter the **Issues** list to individual instances by their ID. For exam | ||||||
| 
 | 
 | ||||||
| ### Filtering merge requests by approvers **(PREMIUM)** | ### Filtering merge requests by approvers **(PREMIUM)** | ||||||
| 
 | 
 | ||||||
| > - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/9468) in GitLab 11.9. | > Moved to GitLab Premium in 13.9. | ||||||
| > - Moved to GitLab Premium in 13.9. |  | ||||||
| 
 | 
 | ||||||
| To filter merge requests by an individual approver, you can type (or select from | To filter merge requests by an individual approver, you can type (or select from | ||||||
| the dropdown) **Approver** and select the user. | the dropdown) **Approver** and select the user. | ||||||
|  |  | ||||||
|  | @ -3,8 +3,6 @@ | ||||||
| module Gitlab | module Gitlab | ||||||
|   module RackAttack |   module RackAttack | ||||||
|     module Request |     module Request | ||||||
|       include ::Gitlab::Utils::StrongMemoize |  | ||||||
| 
 |  | ||||||
|       FILES_PATH_REGEX = %r{^/api/v\d+/projects/[^/]+/repository/files/.+}.freeze |       FILES_PATH_REGEX = %r{^/api/v\d+/projects/[^/]+/repository/files/.+}.freeze | ||||||
|       GROUP_PATH_REGEX = %r{^/api/v\d+/groups/[^/]+/?$}.freeze |       GROUP_PATH_REGEX = %r{^/api/v\d+/groups/[^/]+/?$}.freeze | ||||||
| 
 | 
 | ||||||
|  | @ -32,15 +30,15 @@ module Gitlab | ||||||
|       end |       end | ||||||
| 
 | 
 | ||||||
|       def api_internal_request? |       def api_internal_request? | ||||||
|         path.match?(%r{^/api/v\d+/internal/}) |         path =~ %r{^/api/v\d+/internal/} | ||||||
|       end |       end | ||||||
| 
 | 
 | ||||||
|       def health_check_request? |       def health_check_request? | ||||||
|         path.match?(%r{^/-/(health|liveness|readiness|metrics)}) |         path =~ %r{^/-/(health|liveness|readiness|metrics)} | ||||||
|       end |       end | ||||||
| 
 | 
 | ||||||
|       def container_registry_event? |       def container_registry_event? | ||||||
|         path.match?(%r{^/api/v\d+/container_registry_event/}) |         path =~ %r{^/api/v\d+/container_registry_event/} | ||||||
|       end |       end | ||||||
| 
 | 
 | ||||||
|       def product_analytics_collector_request? |       def product_analytics_collector_request? | ||||||
|  | @ -60,7 +58,7 @@ module Gitlab | ||||||
|       end |       end | ||||||
| 
 | 
 | ||||||
|       def protected_path_regex |       def protected_path_regex | ||||||
|         path.match?(protected_paths_regex) |         path =~ protected_paths_regex | ||||||
|       end |       end | ||||||
| 
 | 
 | ||||||
|       def throttle?(throttle, authenticated:) |       def throttle?(throttle, authenticated:) | ||||||
|  | @ -72,7 +70,6 @@ module Gitlab | ||||||
|       def throttle_unauthenticated_api? |       def throttle_unauthenticated_api? | ||||||
|         api_request? && |         api_request? && | ||||||
|         !should_be_skipped? && |         !should_be_skipped? && | ||||||
|         !frontend_request? && |  | ||||||
|         !throttle_unauthenticated_packages_api? && |         !throttle_unauthenticated_packages_api? && | ||||||
|         !throttle_unauthenticated_files_api? && |         !throttle_unauthenticated_files_api? && | ||||||
|         !throttle_unauthenticated_deprecated_api? && |         !throttle_unauthenticated_deprecated_api? && | ||||||
|  | @ -81,7 +78,7 @@ module Gitlab | ||||||
|       end |       end | ||||||
| 
 | 
 | ||||||
|       def throttle_unauthenticated_web? |       def throttle_unauthenticated_web? | ||||||
|         (web_request? || frontend_request?) && |         web_request? && | ||||||
|         !should_be_skipped? && |         !should_be_skipped? && | ||||||
|         # TODO: Column will be renamed in https://gitlab.com/gitlab-org/gitlab/-/issues/340031 |         # TODO: Column will be renamed in https://gitlab.com/gitlab-org/gitlab/-/issues/340031 | ||||||
|         Gitlab::Throttle.settings.throttle_unauthenticated_enabled && |         Gitlab::Throttle.settings.throttle_unauthenticated_enabled && | ||||||
|  | @ -90,7 +87,6 @@ module Gitlab | ||||||
| 
 | 
 | ||||||
|       def throttle_authenticated_api? |       def throttle_authenticated_api? | ||||||
|         api_request? && |         api_request? && | ||||||
|         !frontend_request? && |  | ||||||
|         !throttle_authenticated_packages_api? && |         !throttle_authenticated_packages_api? && | ||||||
|         !throttle_authenticated_files_api? && |         !throttle_authenticated_files_api? && | ||||||
|         !throttle_authenticated_deprecated_api? && |         !throttle_authenticated_deprecated_api? && | ||||||
|  | @ -98,7 +94,7 @@ module Gitlab | ||||||
|       end |       end | ||||||
| 
 | 
 | ||||||
|       def throttle_authenticated_web? |       def throttle_authenticated_web? | ||||||
|         (web_request? || frontend_request?) && |         web_request? && | ||||||
|         !throttle_authenticated_git_lfs? && |         !throttle_authenticated_git_lfs? && | ||||||
|         Gitlab::Throttle.settings.throttle_authenticated_web_enabled |         Gitlab::Throttle.settings.throttle_authenticated_web_enabled | ||||||
|       end |       end | ||||||
|  | @ -182,24 +178,15 @@ module Gitlab | ||||||
|       end |       end | ||||||
| 
 | 
 | ||||||
|       def packages_api_path? |       def packages_api_path? | ||||||
|         path.match?(::Gitlab::Regex::Packages::API_PATH_REGEX) |         path =~ ::Gitlab::Regex::Packages::API_PATH_REGEX | ||||||
|       end |       end | ||||||
| 
 | 
 | ||||||
|       def git_lfs_path? |       def git_lfs_path? | ||||||
|         path.match?(Gitlab::PathRegex.repository_git_lfs_route_regex) |         path =~ Gitlab::PathRegex.repository_git_lfs_route_regex | ||||||
|       end |       end | ||||||
| 
 | 
 | ||||||
|       def files_api_path? |       def files_api_path? | ||||||
|         path.match?(FILES_PATH_REGEX) |         path =~ FILES_PATH_REGEX | ||||||
|       end |  | ||||||
| 
 |  | ||||||
|       def frontend_request? |  | ||||||
|         strong_memoize(:frontend_request) do |  | ||||||
|           next false unless env.include?('HTTP_X_CSRF_TOKEN') && session.include?(:_csrf_token) |  | ||||||
| 
 |  | ||||||
|           # CSRF tokens are not verified for GET/HEAD requests, so we pretend that we always have a POST request. |  | ||||||
|           Gitlab::RequestForgeryProtection.verified?(env.merge('REQUEST_METHOD' => 'POST')) |  | ||||||
|         end |  | ||||||
|       end |       end | ||||||
| 
 | 
 | ||||||
|       def deprecated_api_request? |       def deprecated_api_request? | ||||||
|  | @ -208,7 +195,7 @@ module Gitlab | ||||||
|         with_projects = params['with_projects'] |         with_projects = params['with_projects'] | ||||||
|         with_projects = true if with_projects.blank? |         with_projects = true if with_projects.blank? | ||||||
| 
 | 
 | ||||||
|         path.match?(GROUP_PATH_REGEX) && Gitlab::Utils.to_boolean(with_projects) |         path =~ GROUP_PATH_REGEX && Gitlab::Utils.to_boolean(with_projects) | ||||||
|       end |       end | ||||||
|     end |     end | ||||||
|   end |   end | ||||||
|  |  | ||||||
|  | @ -553,33 +553,11 @@ module Gitlab | ||||||
|           user_auth_by_provider: distinct_count_user_auth_by_provider(time_period), |           user_auth_by_provider: distinct_count_user_auth_by_provider(time_period), | ||||||
|           unique_users_all_imports: unique_users_all_imports(time_period), |           unique_users_all_imports: unique_users_all_imports(time_period), | ||||||
|           bulk_imports: { |           bulk_imports: { | ||||||
|             gitlab: DEPRECATED_VALUE, |  | ||||||
|             gitlab_v1: count(::BulkImport.where(**time_period, source_type: :gitlab)) |             gitlab_v1: count(::BulkImport.where(**time_period, source_type: :gitlab)) | ||||||
|           }, |           }, | ||||||
|           project_imports: project_imports(time_period), |           project_imports: project_imports(time_period), | ||||||
|           issue_imports: issue_imports(time_period), |           issue_imports: issue_imports(time_period), | ||||||
|           group_imports: group_imports(time_period), |           group_imports: group_imports(time_period) | ||||||
| 
 |  | ||||||
|           # Deprecated data to be removed |  | ||||||
|           projects_imported: { |  | ||||||
|             total: DEPRECATED_VALUE, |  | ||||||
|             gitlab_project: DEPRECATED_VALUE, |  | ||||||
|             gitlab: DEPRECATED_VALUE, |  | ||||||
|             github: DEPRECATED_VALUE, |  | ||||||
|             bitbucket: DEPRECATED_VALUE, |  | ||||||
|             bitbucket_server: DEPRECATED_VALUE, |  | ||||||
|             gitea: DEPRECATED_VALUE, |  | ||||||
|             git: DEPRECATED_VALUE, |  | ||||||
|             manifest: DEPRECATED_VALUE |  | ||||||
|           }, |  | ||||||
|           issues_imported: { |  | ||||||
|             jira: DEPRECATED_VALUE, |  | ||||||
|             fogbugz: DEPRECATED_VALUE, |  | ||||||
|             phabricator: DEPRECATED_VALUE, |  | ||||||
|             csv: DEPRECATED_VALUE |  | ||||||
|           }, |  | ||||||
|           groups_imported: DEPRECATED_VALUE |  | ||||||
|           # End of deprecated keys |  | ||||||
|         } |         } | ||||||
|       end |       end | ||||||
|       # rubocop: enable CodeReuse/ActiveRecord |       # rubocop: enable CodeReuse/ActiveRecord | ||||||
|  |  | ||||||
|  | @ -3,11 +3,15 @@ | ||||||
| require 'spec_helper' | require 'spec_helper' | ||||||
| 
 | 
 | ||||||
| RSpec.describe ApplicationCable::Connection, :clean_gitlab_redis_sessions do | RSpec.describe ApplicationCable::Connection, :clean_gitlab_redis_sessions do | ||||||
|   include SessionHelpers |   let(:session_id) { Rack::Session::SessionId.new('6919a6f1bb119dd7396fadc38fd18d0d') } | ||||||
| 
 | 
 | ||||||
|   context 'when session cookie is set' do |   context 'when session cookie is set' do | ||||||
|     before do |     before do | ||||||
|       stub_session(session_hash) |       Gitlab::Redis::Sessions.with do |redis| | ||||||
|  |         redis.set("session:gitlab:#{session_id.private_id}", Marshal.dump(session_hash)) | ||||||
|  |       end | ||||||
|  | 
 | ||||||
|  |       cookies[Gitlab::Application.config.session_options[:key]] = session_id.public_id | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     context 'when user is logged in' do |     context 'when user is logged in' do | ||||||
|  |  | ||||||
|  | @ -18,6 +18,7 @@ RSpec.describe Types::Ci::JobType do | ||||||
|       created_by_tag |       created_by_tag | ||||||
|       detailedStatus |       detailedStatus | ||||||
|       duration |       duration | ||||||
|  |       downstreamPipeline | ||||||
|       finished_at |       finished_at | ||||||
|       id |       id | ||||||
|       manual_job |       manual_job | ||||||
|  |  | ||||||
|  | @ -11,7 +11,7 @@ RSpec.describe GitlabSchema.types['CiRunner'] do | ||||||
|     expected_fields = %w[ |     expected_fields = %w[ | ||||||
|       id description contacted_at maximum_timeout access_level active status |       id description contacted_at maximum_timeout access_level active status | ||||||
|       version short_sha revision locked run_untagged ip_address runner_type tag_list |       version short_sha revision locked run_untagged ip_address runner_type tag_list | ||||||
|       project_count job_count admin_url user_permissions |       project_count job_count admin_url user_permissions executor_name | ||||||
|     ] |     ] | ||||||
| 
 | 
 | ||||||
|     expect(described_class).to include_graphql_fields(*expected_fields) |     expect(described_class).to include_graphql_fields(*expected_fields) | ||||||
|  |  | ||||||
|  | @ -5,19 +5,6 @@ require 'spec_helper' | ||||||
| RSpec.describe Gitlab::RackAttack::Request do | RSpec.describe Gitlab::RackAttack::Request do | ||||||
|   using RSpec::Parameterized::TableSyntax |   using RSpec::Parameterized::TableSyntax | ||||||
| 
 | 
 | ||||||
|   let(:env) { {} } |  | ||||||
|   let(:session) { {} } |  | ||||||
|   let(:request) do |  | ||||||
|     ::Rack::Attack::Request.new( |  | ||||||
|       env.reverse_merge( |  | ||||||
|         'REQUEST_METHOD' => 'GET', |  | ||||||
|         'PATH_INFO' => path, |  | ||||||
|         'rack.input' => StringIO.new, |  | ||||||
|         'rack.session' => session |  | ||||||
|       ) |  | ||||||
|     ) |  | ||||||
|   end |  | ||||||
| 
 |  | ||||||
|   describe 'FILES_PATH_REGEX' do |   describe 'FILES_PATH_REGEX' do | ||||||
|     subject { described_class::FILES_PATH_REGEX } |     subject { described_class::FILES_PATH_REGEX } | ||||||
| 
 | 
 | ||||||
|  | @ -29,63 +16,11 @@ RSpec.describe Gitlab::RackAttack::Request do | ||||||
|     it { is_expected.not_to match('/api/v4/projects/some/nested/repo/repository/files/README') } |     it { is_expected.not_to match('/api/v4/projects/some/nested/repo/repository/files/README') } | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   describe '#api_request?' do |  | ||||||
|     subject { request.api_request? } |  | ||||||
| 
 |  | ||||||
|     where(:path, :env, :expected) do |  | ||||||
|       '/'       | {} | false |  | ||||||
|       '/groups' | {} | false |  | ||||||
| 
 |  | ||||||
|       '/api'             | {} | true |  | ||||||
|       '/api/v4/groups/1' | {} | true |  | ||||||
|     end |  | ||||||
| 
 |  | ||||||
|     with_them do |  | ||||||
|       it { is_expected.to eq(expected) } |  | ||||||
|     end |  | ||||||
|   end |  | ||||||
| 
 |  | ||||||
|   describe '#web_request?' do |  | ||||||
|     subject { request.web_request? } |  | ||||||
| 
 |  | ||||||
|     where(:path, :env, :expected) do |  | ||||||
|       '/'       | {} | true |  | ||||||
|       '/groups' | {} | true |  | ||||||
| 
 |  | ||||||
|       '/api'             | {} | false |  | ||||||
|       '/api/v4/groups/1' | {} | false |  | ||||||
|     end |  | ||||||
| 
 |  | ||||||
|     with_them do |  | ||||||
|       it { is_expected.to eq(expected) } |  | ||||||
|     end |  | ||||||
|   end |  | ||||||
| 
 |  | ||||||
|   describe '#frontend_request?', :allow_forgery_protection do |  | ||||||
|     subject { request.send(:frontend_request?) } |  | ||||||
| 
 |  | ||||||
|     let(:path) { '/' } |  | ||||||
| 
 |  | ||||||
|     # Define these as local variables so we can use them in the `where` block. |  | ||||||
|     valid_token = SecureRandom.base64(ActionController::RequestForgeryProtection::AUTHENTICITY_TOKEN_LENGTH) |  | ||||||
|     other_token = SecureRandom.base64(ActionController::RequestForgeryProtection::AUTHENTICITY_TOKEN_LENGTH) |  | ||||||
| 
 |  | ||||||
|     where(:session, :env, :expected) do |  | ||||||
|       {}                           | {}                                     | false # rubocop:disable Lint/BinaryOperatorWithIdenticalOperands |  | ||||||
|       {}                           | { 'HTTP_X_CSRF_TOKEN' => valid_token } | false |  | ||||||
|       { _csrf_token: valid_token } | { 'HTTP_X_CSRF_TOKEN' => other_token } | false |  | ||||||
|       { _csrf_token: valid_token } | { 'HTTP_X_CSRF_TOKEN' => valid_token } | true |  | ||||||
|     end |  | ||||||
| 
 |  | ||||||
|     with_them do |  | ||||||
|       it { is_expected.to eq(expected) } |  | ||||||
|     end |  | ||||||
|   end |  | ||||||
| 
 |  | ||||||
|   describe '#deprecated_api_request?' do |   describe '#deprecated_api_request?' do | ||||||
|     subject { request.send(:deprecated_api_request?) } |     let(:env) { { 'REQUEST_METHOD' => 'GET', 'rack.input' => StringIO.new, 'PATH_INFO' => path, 'QUERY_STRING' => query } } | ||||||
|  |     let(:request) { ::Rack::Attack::Request.new(env) } | ||||||
| 
 | 
 | ||||||
|     let(:env) { { 'QUERY_STRING' => query } } |     subject { !!request.__send__(:deprecated_api_request?) } | ||||||
| 
 | 
 | ||||||
|     where(:path, :query, :expected) do |     where(:path, :query, :expected) do | ||||||
|       '/' | '' | false |       '/' | '' | false | ||||||
|  |  | ||||||
|  | @ -279,8 +279,7 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures do | ||||||
|       expect(described_class.usage_activity_by_stage_manage({})).to include( |       expect(described_class.usage_activity_by_stage_manage({})).to include( | ||||||
|         { |         { | ||||||
|           bulk_imports: { |           bulk_imports: { | ||||||
|             gitlab_v1: 2, |             gitlab_v1: 2 | ||||||
|             gitlab: Gitlab::UsageData::DEPRECATED_VALUE |  | ||||||
|           }, |           }, | ||||||
|           project_imports: { |           project_imports: { | ||||||
|             bitbucket: 2, |             bitbucket: 2, | ||||||
|  | @ -303,32 +302,13 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures do | ||||||
|           group_imports: { |           group_imports: { | ||||||
|             group_import: 2, |             group_import: 2, | ||||||
|             gitlab_migration: 2 |             gitlab_migration: 2 | ||||||
|           }, |           } | ||||||
|           projects_imported: { |  | ||||||
|             total: Gitlab::UsageData::DEPRECATED_VALUE, |  | ||||||
|             gitlab_project: Gitlab::UsageData::DEPRECATED_VALUE, |  | ||||||
|             gitlab: Gitlab::UsageData::DEPRECATED_VALUE, |  | ||||||
|             github: Gitlab::UsageData::DEPRECATED_VALUE, |  | ||||||
|             bitbucket: Gitlab::UsageData::DEPRECATED_VALUE, |  | ||||||
|             bitbucket_server: Gitlab::UsageData::DEPRECATED_VALUE, |  | ||||||
|             gitea: Gitlab::UsageData::DEPRECATED_VALUE, |  | ||||||
|             git: Gitlab::UsageData::DEPRECATED_VALUE, |  | ||||||
|             manifest: Gitlab::UsageData::DEPRECATED_VALUE |  | ||||||
|           }, |  | ||||||
|           issues_imported: { |  | ||||||
|             jira: Gitlab::UsageData::DEPRECATED_VALUE, |  | ||||||
|             fogbugz: Gitlab::UsageData::DEPRECATED_VALUE, |  | ||||||
|             phabricator: Gitlab::UsageData::DEPRECATED_VALUE, |  | ||||||
|             csv: Gitlab::UsageData::DEPRECATED_VALUE |  | ||||||
|           }, |  | ||||||
|           groups_imported: Gitlab::UsageData::DEPRECATED_VALUE |  | ||||||
|         } |         } | ||||||
|       ) |       ) | ||||||
|       expect(described_class.usage_activity_by_stage_manage(described_class.monthly_time_range_db_params)).to include( |       expect(described_class.usage_activity_by_stage_manage(described_class.monthly_time_range_db_params)).to include( | ||||||
|         { |         { | ||||||
|           bulk_imports: { |           bulk_imports: { | ||||||
|             gitlab_v1: 1, |             gitlab_v1: 1 | ||||||
|             gitlab: Gitlab::UsageData::DEPRECATED_VALUE |  | ||||||
|           }, |           }, | ||||||
|           project_imports: { |           project_imports: { | ||||||
|             bitbucket: 1, |             bitbucket: 1, | ||||||
|  | @ -351,25 +331,7 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures do | ||||||
|           group_imports: { |           group_imports: { | ||||||
|             group_import: 1, |             group_import: 1, | ||||||
|             gitlab_migration: 1 |             gitlab_migration: 1 | ||||||
|           }, |           } | ||||||
|           projects_imported: { |  | ||||||
|             total: Gitlab::UsageData::DEPRECATED_VALUE, |  | ||||||
|             gitlab_project: Gitlab::UsageData::DEPRECATED_VALUE, |  | ||||||
|             gitlab: Gitlab::UsageData::DEPRECATED_VALUE, |  | ||||||
|             github: Gitlab::UsageData::DEPRECATED_VALUE, |  | ||||||
|             bitbucket: Gitlab::UsageData::DEPRECATED_VALUE, |  | ||||||
|             bitbucket_server: Gitlab::UsageData::DEPRECATED_VALUE, |  | ||||||
|             gitea: Gitlab::UsageData::DEPRECATED_VALUE, |  | ||||||
|             git: Gitlab::UsageData::DEPRECATED_VALUE, |  | ||||||
|             manifest: Gitlab::UsageData::DEPRECATED_VALUE |  | ||||||
|           }, |  | ||||||
|           issues_imported: { |  | ||||||
|             jira: Gitlab::UsageData::DEPRECATED_VALUE, |  | ||||||
|             fogbugz: Gitlab::UsageData::DEPRECATED_VALUE, |  | ||||||
|             phabricator: Gitlab::UsageData::DEPRECATED_VALUE, |  | ||||||
|             csv: Gitlab::UsageData::DEPRECATED_VALUE |  | ||||||
|           }, |  | ||||||
|           groups_imported: Gitlab::UsageData::DEPRECATED_VALUE |  | ||||||
|         } |         } | ||||||
|       ) |       ) | ||||||
|     end |     end | ||||||
|  |  | ||||||
|  | @ -5,7 +5,6 @@ require 'mime/types' | ||||||
| 
 | 
 | ||||||
| RSpec.describe API::Commits do | RSpec.describe API::Commits do | ||||||
|   include ProjectForksHelper |   include ProjectForksHelper | ||||||
|   include SessionHelpers |  | ||||||
| 
 | 
 | ||||||
|   let(:user) { create(:user) } |   let(:user) { create(:user) } | ||||||
|   let(:guest) { create(:user).tap { |u| project.add_guest(u) } } |   let(:guest) { create(:user).tap { |u| project.add_guest(u) } } | ||||||
|  | @ -379,7 +378,14 @@ RSpec.describe API::Commits do | ||||||
| 
 | 
 | ||||||
|       context 'when using warden' do |       context 'when using warden' do | ||||||
|         it 'increments usage counters', :clean_gitlab_redis_sessions do |         it 'increments usage counters', :clean_gitlab_redis_sessions do | ||||||
|           stub_session('warden.user.user.key' => [[user.id], user.encrypted_password[0, 29]]) |           session_id = Rack::Session::SessionId.new('6919a6f1bb119dd7396fadc38fd18d0d') | ||||||
|  |           session_hash = { 'warden.user.user.key' => [[user.id], user.encrypted_password[0, 29]] } | ||||||
|  | 
 | ||||||
|  |           Gitlab::Redis::Sessions.with do |redis| | ||||||
|  |             redis.set("session:gitlab:#{session_id.private_id}", Marshal.dump(session_hash)) | ||||||
|  |           end | ||||||
|  | 
 | ||||||
|  |           cookies[Gitlab::Application.config.session_options[:key]] = session_id.public_id | ||||||
| 
 | 
 | ||||||
|           expect(::Gitlab::UsageDataCounters::WebIdeCounter).to receive(:increment_commits_count) |           expect(::Gitlab::UsageDataCounters::WebIdeCounter).to receive(:increment_commits_count) | ||||||
|           expect(::Gitlab::UsageDataCounters::EditorUniqueCounter).to receive(:track_web_ide_edit_action) |           expect(::Gitlab::UsageDataCounters::EditorUniqueCounter).to receive(:track_web_ide_edit_action) | ||||||
|  |  | ||||||
|  | @ -44,6 +44,10 @@ RSpec.describe 'Query.project.pipeline' do | ||||||
|             name |             name | ||||||
|             jobs { |             jobs { | ||||||
|               nodes { |               nodes { | ||||||
|  |                 downstreamPipeline { | ||||||
|  |                   id | ||||||
|  |                   path | ||||||
|  |                 } | ||||||
|                 name |                 name | ||||||
|                 needs { |                 needs { | ||||||
|                   nodes { #{all_graphql_fields_for('CiBuildNeed')} } |                   nodes { #{all_graphql_fields_for('CiBuildNeed')} } | ||||||
|  | @ -131,6 +135,8 @@ RSpec.describe 'Query.project.pipeline' do | ||||||
|       end |       end | ||||||
| 
 | 
 | ||||||
|       it 'does not generate N+1 queries', :request_store, :use_sql_query_cache do |       it 'does not generate N+1 queries', :request_store, :use_sql_query_cache do | ||||||
|  |         create(:ci_bridge, name: 'bridge-1', pipeline: pipeline, downstream_pipeline: create(:ci_pipeline)) | ||||||
|  | 
 | ||||||
|         post_graphql(query, current_user: user) |         post_graphql(query, current_user: user) | ||||||
| 
 | 
 | ||||||
|         control = ActiveRecord::QueryRecorder.new(skip_cached: false) do |         control = ActiveRecord::QueryRecorder.new(skip_cached: false) do | ||||||
|  | @ -139,6 +145,8 @@ RSpec.describe 'Query.project.pipeline' do | ||||||
| 
 | 
 | ||||||
|         create(:ci_build, name: 'test-a', pipeline: pipeline) |         create(:ci_build, name: 'test-a', pipeline: pipeline) | ||||||
|         create(:ci_build, name: 'test-b', pipeline: pipeline) |         create(:ci_build, name: 'test-b', pipeline: pipeline) | ||||||
|  |         create(:ci_bridge, name: 'bridge-2', pipeline: pipeline, downstream_pipeline: create(:ci_pipeline)) | ||||||
|  |         create(:ci_bridge, name: 'bridge-3', pipeline: pipeline, downstream_pipeline: create(:ci_pipeline)) | ||||||
| 
 | 
 | ||||||
|         expect do |         expect do | ||||||
|           post_graphql(query, current_user: user) |           post_graphql(query, current_user: user) | ||||||
|  |  | ||||||
|  | @ -11,7 +11,7 @@ RSpec.describe 'Query.runner(id)' do | ||||||
|   let_it_be(:active_instance_runner) do |   let_it_be(:active_instance_runner) do | ||||||
|     create(:ci_runner, :instance, description: 'Runner 1', contacted_at: 2.hours.ago, |     create(:ci_runner, :instance, description: 'Runner 1', contacted_at: 2.hours.ago, | ||||||
|            active: true, version: 'adfe156', revision: 'a', locked: true, ip_address: '127.0.0.1', maximum_timeout: 600, |            active: true, version: 'adfe156', revision: 'a', locked: true, ip_address: '127.0.0.1', maximum_timeout: 600, | ||||||
|            access_level: 0, tag_list: %w[tag1 tag2], run_untagged: true) |            access_level: 0, tag_list: %w[tag1 tag2], run_untagged: true, executor_type: :custom) | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   let_it_be(:inactive_instance_runner) do |   let_it_be(:inactive_instance_runner) do | ||||||
|  | @ -22,7 +22,7 @@ RSpec.describe 'Query.runner(id)' do | ||||||
|   let_it_be(:active_group_runner) do |   let_it_be(:active_group_runner) do | ||||||
|     create(:ci_runner, :group, groups: [group], description: 'Group runner 1', contacted_at: 2.hours.ago, |     create(:ci_runner, :group, groups: [group], description: 'Group runner 1', contacted_at: 2.hours.ago, | ||||||
|            active: true, version: 'adfe156', revision: 'a', locked: true, ip_address: '127.0.0.1', maximum_timeout: 600, |            active: true, version: 'adfe156', revision: 'a', locked: true, ip_address: '127.0.0.1', maximum_timeout: 600, | ||||||
|            access_level: 0, tag_list: %w[tag1 tag2], run_untagged: true) |            access_level: 0, tag_list: %w[tag1 tag2], run_untagged: true, executor_type: :shell) | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   def get_runner(id) |   def get_runner(id) | ||||||
|  | @ -69,6 +69,7 @@ RSpec.describe 'Query.runner(id)' do | ||||||
|         'runUntagged' => runner.run_untagged, |         'runUntagged' => runner.run_untagged, | ||||||
|         'ipAddress' => runner.ip_address, |         'ipAddress' => runner.ip_address, | ||||||
|         'runnerType' => runner.instance_type? ? 'INSTANCE_TYPE' : 'PROJECT_TYPE', |         'runnerType' => runner.instance_type? ? 'INSTANCE_TYPE' : 'PROJECT_TYPE', | ||||||
|  |         'executorName' => runner.executor_type&.dasherize, | ||||||
|         'jobCount' => 0, |         'jobCount' => 0, | ||||||
|         'projectCount' => nil, |         'projectCount' => nil, | ||||||
|         'adminUrl' => "http://localhost/admin/runners/#{runner.id}", |         'adminUrl' => "http://localhost/admin/runners/#{runner.id}", | ||||||
|  |  | ||||||
|  | @ -4,7 +4,6 @@ require 'spec_helper' | ||||||
| 
 | 
 | ||||||
| RSpec.describe 'Rack Attack global throttles', :use_clean_rails_memory_store_caching do | RSpec.describe 'Rack Attack global throttles', :use_clean_rails_memory_store_caching do | ||||||
|   include RackAttackSpecHelpers |   include RackAttackSpecHelpers | ||||||
|   include SessionHelpers |  | ||||||
| 
 | 
 | ||||||
|   let(:settings) { Gitlab::CurrentSettings.current_application_settings } |   let(:settings) { Gitlab::CurrentSettings.current_application_settings } | ||||||
| 
 | 
 | ||||||
|  | @ -64,22 +63,6 @@ RSpec.describe 'Rack Attack global throttles', :use_clean_rails_memory_store_cac | ||||||
|     end |     end | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   describe 'API requests from the frontend', :api, :clean_gitlab_redis_sessions do |  | ||||||
|     context 'when unauthenticated' do |  | ||||||
|       it_behaves_like 'rate-limited frontend API requests' do |  | ||||||
|         let(:throttle_setting_prefix) { 'throttle_unauthenticated' } |  | ||||||
|       end |  | ||||||
|     end |  | ||||||
| 
 |  | ||||||
|     context 'when authenticated' do |  | ||||||
|       it_behaves_like 'rate-limited frontend API requests' do |  | ||||||
|         let_it_be(:personal_access_token) { create(:personal_access_token) } |  | ||||||
| 
 |  | ||||||
|         let(:throttle_setting_prefix) { 'throttle_authenticated' } |  | ||||||
|       end |  | ||||||
|     end |  | ||||||
|   end |  | ||||||
| 
 |  | ||||||
|   describe 'API requests authenticated with personal access token', :api do |   describe 'API requests authenticated with personal access token', :api do | ||||||
|     let_it_be(:user) { create(:user) } |     let_it_be(:user) { create(:user) } | ||||||
|     let_it_be(:token) { create(:personal_access_token, user: user) } |     let_it_be(:token) { create(:personal_access_token, user: user) } | ||||||
|  |  | ||||||
|  | @ -26,14 +26,14 @@ module RackAttackSpecHelpers | ||||||
|     { 'AUTHORIZATION' => "Basic #{encoded_login}" } |     { 'AUTHORIZATION' => "Basic #{encoded_login}" } | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   def expect_rejection(name = nil, &block) |   def expect_rejection(&block) | ||||||
|     yield |     yield | ||||||
| 
 | 
 | ||||||
|     expect(response).to have_gitlab_http_status(:too_many_requests) |     expect(response).to have_gitlab_http_status(:too_many_requests) | ||||||
| 
 | 
 | ||||||
|     expect(response.headers.to_h).to include( |     expect(response.headers.to_h).to include( | ||||||
|       'RateLimit-Limit' => a_string_matching(/^\d+$/), |       'RateLimit-Limit' => a_string_matching(/^\d+$/), | ||||||
|       'RateLimit-Name' => name || a_string_matching(/^throttle_.*$/), |       'RateLimit-Name' => a_string_matching(/^throttle_.*$/), | ||||||
|       'RateLimit-Observed' => a_string_matching(/^\d+$/), |       'RateLimit-Observed' => a_string_matching(/^\d+$/), | ||||||
|       'RateLimit-Remaining' => a_string_matching(/^\d+$/), |       'RateLimit-Remaining' => a_string_matching(/^\d+$/), | ||||||
|       'Retry-After' => a_string_matching(/^\d+$/) |       'Retry-After' => a_string_matching(/^\d+$/) | ||||||
|  |  | ||||||
|  | @ -1,22 +1,6 @@ | ||||||
| # frozen_string_literal: true | # frozen_string_literal: true | ||||||
| 
 | 
 | ||||||
| module SessionHelpers | module SessionHelpers | ||||||
|   # Stub a session in Redis, for use in request specs where we can't mock the session directly. |  | ||||||
|   # This also needs the :clean_gitlab_redis_sessions tag on the spec. |  | ||||||
|   def stub_session(session_hash) |  | ||||||
|     unless RSpec.current_example.metadata[:clean_gitlab_redis_sessions] |  | ||||||
|       raise 'Add :clean_gitlab_redis_sessions to your spec!' |  | ||||||
|     end |  | ||||||
| 
 |  | ||||||
|     session_id = Rack::Session::SessionId.new(SecureRandom.hex) |  | ||||||
| 
 |  | ||||||
|     Gitlab::Redis::Sessions.with do |redis| |  | ||||||
|       redis.set("session:gitlab:#{session_id.private_id}", Marshal.dump(session_hash)) |  | ||||||
|     end |  | ||||||
| 
 |  | ||||||
|     cookies[Gitlab::Application.config.session_options[:key]] = session_id.public_id |  | ||||||
|   end |  | ||||||
| 
 |  | ||||||
|   def expect_single_session_with_authenticated_ttl |   def expect_single_session_with_authenticated_ttl | ||||||
|     expect_single_session_with_expiration(Settings.gitlab['session_expire_delay'] * 60) |     expect_single_session_with_expiration(Settings.gitlab['session_expire_delay'] * 60) | ||||||
|   end |   end | ||||||
|  |  | ||||||
|  | @ -10,8 +10,6 @@ RSpec.shared_examples 'when the snippet is not found' do | ||||||
| end | end | ||||||
| 
 | 
 | ||||||
| RSpec.shared_examples 'snippet edit usage data counters' do | RSpec.shared_examples 'snippet edit usage data counters' do | ||||||
|   include SessionHelpers |  | ||||||
| 
 |  | ||||||
|   context 'when user is sessionless' do |   context 'when user is sessionless' do | ||||||
|     it 'does not track usage data actions' do |     it 'does not track usage data actions' do | ||||||
|       expect(::Gitlab::UsageDataCounters::EditorUniqueCounter).not_to receive(:track_snippet_editor_edit_action) |       expect(::Gitlab::UsageDataCounters::EditorUniqueCounter).not_to receive(:track_snippet_editor_edit_action) | ||||||
|  | @ -22,7 +20,14 @@ RSpec.shared_examples 'snippet edit usage data counters' do | ||||||
| 
 | 
 | ||||||
|   context 'when user is not sessionless', :clean_gitlab_redis_sessions do |   context 'when user is not sessionless', :clean_gitlab_redis_sessions do | ||||||
|     before do |     before do | ||||||
|       stub_session('warden.user.user.key' => [[current_user.id], current_user.encrypted_password[0, 29]]) |       session_id = Rack::Session::SessionId.new('6919a6f1bb119dd7396fadc38fd18d0d') | ||||||
|  |       session_hash = { 'warden.user.user.key' => [[current_user.id], current_user.encrypted_password[0, 29]] } | ||||||
|  | 
 | ||||||
|  |       Gitlab::Redis::Sessions.with do |redis| | ||||||
|  |         redis.set("session:gitlab:#{session_id.private_id}", Marshal.dump(session_hash)) | ||||||
|  |       end | ||||||
|  | 
 | ||||||
|  |       cookies[Gitlab::Application.config.session_options[:key]] = session_id.public_id | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     it 'tracks usage data actions', :clean_gitlab_redis_sessions do |     it 'tracks usage data actions', :clean_gitlab_redis_sessions do | ||||||
|  |  | ||||||
|  | @ -580,88 +580,3 @@ RSpec.shared_examples 'rate-limited unauthenticated requests' do | ||||||
|     end |     end | ||||||
|   end |   end | ||||||
| end | end | ||||||
| 
 |  | ||||||
| # Requires let variables: |  | ||||||
| # * throttle_setting_prefix: "throttle_authenticated", "throttle_unauthenticated" |  | ||||||
| RSpec.shared_examples 'rate-limited frontend API requests' do |  | ||||||
|   let(:requests_per_period) { 1 } |  | ||||||
|   let(:csrf_token) { SecureRandom.base64(ActionController::RequestForgeryProtection::AUTHENTICITY_TOKEN_LENGTH) } |  | ||||||
|   let(:csrf_session) { { _csrf_token: csrf_token } } |  | ||||||
|   let(:personal_access_token) { nil } |  | ||||||
| 
 |  | ||||||
|   let(:api_path) { '/projects' } |  | ||||||
| 
 |  | ||||||
|   # These don't actually exist, so a 404 is the expected response. |  | ||||||
|   let(:files_api_path) { '/projects/1/repository/files/ref/path' } |  | ||||||
|   let(:packages_api_path) { '/projects/1/packages/foo' } |  | ||||||
|   let(:deprecated_api_path) { '/groups/1?with_projects=true' } |  | ||||||
| 
 |  | ||||||
|   def get_api(path: api_path, csrf: false) |  | ||||||
|     headers = csrf ? { 'X-CSRF-Token' => csrf_token } : nil |  | ||||||
|     get api(path, personal_access_token: personal_access_token), headers: headers |  | ||||||
|   end |  | ||||||
| 
 |  | ||||||
|   def expect_not_found(&block) |  | ||||||
|     yield |  | ||||||
| 
 |  | ||||||
|     expect(response).to have_gitlab_http_status(:not_found) |  | ||||||
|   end |  | ||||||
| 
 |  | ||||||
|   before do |  | ||||||
|     stub_application_setting( |  | ||||||
|       "#{throttle_setting_prefix}_enabled" => true, |  | ||||||
|       "#{throttle_setting_prefix}_requests_per_period" => requests_per_period, |  | ||||||
|       "#{throttle_setting_prefix}_api_enabled" => true, |  | ||||||
|       "#{throttle_setting_prefix}_api_requests_per_period" => requests_per_period, |  | ||||||
|       "#{throttle_setting_prefix}_web_enabled" => true, |  | ||||||
|       "#{throttle_setting_prefix}_web_requests_per_period" => requests_per_period, |  | ||||||
|       "#{throttle_setting_prefix}_files_api_enabled" => true, |  | ||||||
|       "#{throttle_setting_prefix}_packages_api_enabled" => true, |  | ||||||
|       "#{throttle_setting_prefix}_deprecated_api_enabled" => true |  | ||||||
|     ) |  | ||||||
| 
 |  | ||||||
|     stub_session(csrf_session) |  | ||||||
|   end |  | ||||||
| 
 |  | ||||||
|   context 'with a CSRF token' do |  | ||||||
|     it 'uses the rate limit for web requests' do |  | ||||||
|       requests_per_period.times { get_api csrf: true } |  | ||||||
| 
 |  | ||||||
|       expect_rejection("#{throttle_setting_prefix}_web") { get_api csrf: true } |  | ||||||
|       expect_rejection("#{throttle_setting_prefix}_web") { get_api csrf: true, path: files_api_path } |  | ||||||
|       expect_rejection("#{throttle_setting_prefix}_web") { get_api csrf: true, path: packages_api_path } |  | ||||||
|       expect_rejection("#{throttle_setting_prefix}_web") { get_api csrf: true, path: deprecated_api_path } |  | ||||||
| 
 |  | ||||||
|       # API rate limit is not triggered yet |  | ||||||
|       expect_ok { get_api } |  | ||||||
|       expect_not_found { get_api path: files_api_path } |  | ||||||
|       expect_not_found { get_api path: packages_api_path } |  | ||||||
|       expect_not_found { get_api path: deprecated_api_path } |  | ||||||
|     end |  | ||||||
| 
 |  | ||||||
|     context 'without a CSRF session' do |  | ||||||
|       let(:csrf_session) { nil } |  | ||||||
| 
 |  | ||||||
|       it 'always uses the rate limit for API requests' do |  | ||||||
|         requests_per_period.times { get_api csrf: true } |  | ||||||
| 
 |  | ||||||
|         expect_rejection("#{throttle_setting_prefix}_api") { get_api csrf: true } |  | ||||||
|         expect_rejection("#{throttle_setting_prefix}_api") { get_api } |  | ||||||
|       end |  | ||||||
|     end |  | ||||||
|   end |  | ||||||
| 
 |  | ||||||
|   context 'without a CSRF token' do |  | ||||||
|     it 'uses the rate limit for API requests' do |  | ||||||
|       requests_per_period.times { get_api } |  | ||||||
| 
 |  | ||||||
|       expect_rejection("#{throttle_setting_prefix}_api") { get_api } |  | ||||||
| 
 |  | ||||||
|       # Web and custom API rate limits are not triggered yet |  | ||||||
|       expect_ok { get_api csrf: true } |  | ||||||
|       expect_not_found { get_api path: files_api_path } |  | ||||||
|       expect_not_found { get_api path: packages_api_path } |  | ||||||
|       expect_not_found { get_api path: deprecated_api_path } |  | ||||||
|     end |  | ||||||
|   end |  | ||||||
| end |  | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue