Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
		
							parent
							
								
									f0b7977608
								
							
						
					
					
						commit
						cc310f2111
					
				|  | @ -55,9 +55,9 @@ release-environments-qa: | ||||||
|   stage: qa |   stage: qa | ||||||
|   extends: |   extends: | ||||||
|     - .qa-base |     - .qa-base | ||||||
|   timeout: 4h |   timeout: 3h | ||||||
|   variables: |   variables: | ||||||
|     QA_SCENARIO: "Test::Instance::Any" |     QA_SCENARIO: "Test::Instance::Smoke" | ||||||
|     RELEASE: "${CI_REGISTRY}/${CI_PROJECT_PATH}/gitlab-ee-qa:${CI_COMMIT_SHA}" |     RELEASE: "${CI_REGISTRY}/${CI_PROJECT_PATH}/gitlab-ee-qa:${CI_COMMIT_SHA}" | ||||||
|     GITLAB_QA_OPTS: --address "https://gitlab.${ENVIRONMENT}.release.gke.gitlab.net" |     GITLAB_QA_OPTS: --address "https://gitlab.${ENVIRONMENT}.release.gke.gitlab.net" | ||||||
|     GITLAB_INITIAL_ROOT_PASSWORD: "${RELEASE_ENVIRONMENTS_ROOT_PASSWORD}" |     GITLAB_INITIAL_ROOT_PASSWORD: "${RELEASE_ENVIRONMENTS_ROOT_PASSWORD}" | ||||||
|  |  | ||||||
|  | @ -50,6 +50,7 @@ class Projects::IssuesController < Projects::ApplicationController | ||||||
|     push_frontend_feature_flag(:issues_list_drawer, project) |     push_frontend_feature_flag(:issues_list_drawer, project) | ||||||
|     push_frontend_feature_flag(:linked_work_items, project) |     push_frontend_feature_flag(:linked_work_items, project) | ||||||
|     push_frontend_feature_flag(:display_work_item_epic_issue_sidebar, project) |     push_frontend_feature_flag(:display_work_item_epic_issue_sidebar, project) | ||||||
|  |     push_frontend_feature_flag(:notifications_todos_buttons, current_user) | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   before_action only: [:index, :show] do |   before_action only: [:index, :show] do | ||||||
|  | @ -69,7 +70,6 @@ class Projects::IssuesController < Projects::ApplicationController | ||||||
|     push_frontend_feature_flag(:epic_widget_edit_confirmation, project) |     push_frontend_feature_flag(:epic_widget_edit_confirmation, project) | ||||||
|     push_frontend_feature_flag(:display_work_item_epic_issue_sidebar, project) |     push_frontend_feature_flag(:display_work_item_epic_issue_sidebar, project) | ||||||
|     push_force_frontend_feature_flag(:linked_work_items, project.linked_work_items_feature_flag_enabled?) |     push_force_frontend_feature_flag(:linked_work_items, project.linked_work_items_feature_flag_enabled?) | ||||||
|     push_frontend_feature_flag(:notifications_todos_buttons, current_user) |  | ||||||
|     push_frontend_feature_flag(:mention_autocomplete_backend_filtering, project) |     push_frontend_feature_flag(:mention_autocomplete_backend_filtering, project) | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -24,7 +24,8 @@ module Projects | ||||||
|           auto_fix_user_path: auto_fix_user_path, |           auto_fix_user_path: auto_fix_user_path, | ||||||
|           security_training_enabled: project.security_training_available?, |           security_training_enabled: project.security_training_available?, | ||||||
|           continuous_vulnerability_scans_enabled: continuous_vulnerability_scans_enabled, |           continuous_vulnerability_scans_enabled: continuous_vulnerability_scans_enabled, | ||||||
|           container_scanning_for_registry_enabled: container_scanning_for_registry_enabled |           container_scanning_for_registry_enabled: container_scanning_for_registry_enabled, | ||||||
|  |           pre_receive_secret_detection_enabled: pre_receive_secret_detection_enabled | ||||||
|         } |         } | ||||||
|       end |       end | ||||||
| 
 | 
 | ||||||
|  | @ -98,6 +99,7 @@ module Projects | ||||||
| 
 | 
 | ||||||
|       def continuous_vulnerability_scans_enabled; end |       def continuous_vulnerability_scans_enabled; end | ||||||
|       def container_scanning_for_registry_enabled; end |       def container_scanning_for_registry_enabled; end | ||||||
|  |       def pre_receive_secret_detection_enabled; end | ||||||
|     end |     end | ||||||
|   end |   end | ||||||
| end | end | ||||||
|  |  | ||||||
|  | @ -0,0 +1,47 @@ | ||||||
|  | { | ||||||
|  |   "$schema": "http://json-schema.org/draft-07/schema#", | ||||||
|  |   "description": "Permissions on custom roles", | ||||||
|  |   "type": "object", | ||||||
|  |   "additionalProperties": false, | ||||||
|  |   "properties": { | ||||||
|  |     "admin_cicd_variables": { | ||||||
|  |       "type": "boolean" | ||||||
|  |     }, | ||||||
|  |     "admin_group_member": { | ||||||
|  |       "type": "boolean" | ||||||
|  |     }, | ||||||
|  |     "admin_merge_request": { | ||||||
|  |       "type": "boolean" | ||||||
|  |     }, | ||||||
|  |     "admin_terraform_state": { | ||||||
|  |       "type": "boolean" | ||||||
|  |     }, | ||||||
|  |     "admin_vulnerability": { | ||||||
|  |       "type": "boolean" | ||||||
|  |     }, | ||||||
|  |     "archive_project": { | ||||||
|  |       "type": "boolean" | ||||||
|  |     }, | ||||||
|  |     "manage_group_access_tokens": { | ||||||
|  |       "type": "boolean" | ||||||
|  |     }, | ||||||
|  |     "manage_project_access_tokens": { | ||||||
|  |       "type": "boolean" | ||||||
|  |     }, | ||||||
|  |     "read_code": { | ||||||
|  |       "type": "boolean" | ||||||
|  |     }, | ||||||
|  |     "read_dependency": { | ||||||
|  |       "type": "boolean" | ||||||
|  |     }, | ||||||
|  |     "read_vulnerability": { | ||||||
|  |       "type": "boolean" | ||||||
|  |     }, | ||||||
|  |     "remove_group": { | ||||||
|  |       "type": "boolean" | ||||||
|  |     }, | ||||||
|  |     "remove_project": { | ||||||
|  |       "type": "boolean" | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | @ -1,5 +1,5 @@ | ||||||
| --- | --- | ||||||
| name: code_suggestions_tokens_api | name: ai_duo_code_suggestions_switch | ||||||
| introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/120892 | introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/120892 | ||||||
| rollout_issue_url: | rollout_issue_url: | ||||||
| milestone: '16.1' | milestone: '16.1' | ||||||
|  | @ -7,4 +7,12 @@ feature_categories: | ||||||
| description: Persists incoming alert data including its payload | description: Persists incoming alert data including its payload | ||||||
| introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/29864 | introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/29864 | ||||||
| milestone: '13.0' | milestone: '13.0' | ||||||
| gitlab_schema: gitlab_main | gitlab_schema: gitlab_main_cell | ||||||
|  | allow_cross_joins: | ||||||
|  | - gitlab_main_clusterwide | ||||||
|  | allow_cross_transactions: | ||||||
|  | - gitlab_main_clusterwide | ||||||
|  | allow_cross_foreign_keys: | ||||||
|  | - gitlab_main_clusterwide | ||||||
|  | sharding_key: | ||||||
|  |   project_id: projects | ||||||
|  |  | ||||||
|  | @ -7,4 +7,12 @@ feature_categories: | ||||||
| description: Persists settings for alert HTTP integrations | description: Persists settings for alert HTTP integrations | ||||||
| introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/43634 | introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/43634 | ||||||
| milestone: '13.5' | milestone: '13.5' | ||||||
| gitlab_schema: gitlab_main | gitlab_schema: gitlab_main_cell | ||||||
|  | allow_cross_joins: | ||||||
|  | - gitlab_main_clusterwide | ||||||
|  | allow_cross_transactions: | ||||||
|  | - gitlab_main_clusterwide | ||||||
|  | allow_cross_foreign_keys: | ||||||
|  | - gitlab_main_clusterwide | ||||||
|  | sharding_key: | ||||||
|  |   project_id: projects | ||||||
|  |  | ||||||
|  | @ -4,7 +4,16 @@ classes: | ||||||
| - CustomerRelations::Contact | - CustomerRelations::Contact | ||||||
| feature_categories: | feature_categories: | ||||||
| - service_desk | - service_desk | ||||||
| description: Contacts, against which time can be spent by users on issues using the CRM functionality | description: Contacts, against which time can be spent by users on issues using the | ||||||
|  |   CRM functionality | ||||||
| introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/67985 | introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/67985 | ||||||
| milestone: '14.3' | milestone: '14.3' | ||||||
| gitlab_schema: gitlab_main | gitlab_schema: gitlab_main_cell | ||||||
|  | allow_cross_joins: | ||||||
|  | - gitlab_main_clusterwide | ||||||
|  | allow_cross_transactions: | ||||||
|  | - gitlab_main_clusterwide | ||||||
|  | allow_cross_foreign_keys: | ||||||
|  | - gitlab_main_clusterwide | ||||||
|  | sharding_key: | ||||||
|  |   group_id: namespaces | ||||||
|  |  | ||||||
|  | @ -8,3 +8,5 @@ description: Group-level settings for CRM-related features | ||||||
| introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/76983 | introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/76983 | ||||||
| milestone: '14.7' | milestone: '14.7' | ||||||
| gitlab_schema: gitlab_main_cell | gitlab_schema: gitlab_main_cell | ||||||
|  | sharding_key: | ||||||
|  |   group_id: namespaces | ||||||
|  |  | ||||||
|  | @ -7,4 +7,12 @@ feature_categories: | ||||||
| description: Persists information about escalation policies in a project | description: Persists information about escalation policies in a project | ||||||
| introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/60685 | introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/60685 | ||||||
| milestone: '13.12' | milestone: '13.12' | ||||||
| gitlab_schema: gitlab_main | gitlab_schema: gitlab_main_cell | ||||||
|  | allow_cross_joins: | ||||||
|  | - gitlab_main_clusterwide | ||||||
|  | allow_cross_transactions: | ||||||
|  | - gitlab_main_clusterwide | ||||||
|  | allow_cross_foreign_keys: | ||||||
|  | - gitlab_main_clusterwide | ||||||
|  | sharding_key: | ||||||
|  |   project_id: projects | ||||||
|  |  | ||||||
|  | @ -8,4 +8,12 @@ feature_categories: | ||||||
| description: Persists on-call schedules for incident management in a project | description: Persists on-call schedules for incident management in a project | ||||||
| introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/47407 | introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/47407 | ||||||
| milestone: '13.7' | milestone: '13.7' | ||||||
| gitlab_schema: gitlab_main | gitlab_schema: gitlab_main_cell | ||||||
|  | allow_cross_joins: | ||||||
|  | - gitlab_main_clusterwide | ||||||
|  | allow_cross_transactions: | ||||||
|  | - gitlab_main_clusterwide | ||||||
|  | allow_cross_foreign_keys: | ||||||
|  | - gitlab_main_clusterwide | ||||||
|  | sharding_key: | ||||||
|  |   project_id: projects | ||||||
|  |  | ||||||
|  | @ -8,3 +8,5 @@ description: Persists tags for timeline events in a project. | ||||||
| introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/100271 | introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/100271 | ||||||
| milestone: '15.6' | milestone: '15.6' | ||||||
| gitlab_schema: gitlab_main_cell | gitlab_schema: gitlab_main_cell | ||||||
|  | sharding_key: | ||||||
|  |   project_id: projects | ||||||
|  |  | ||||||
|  | @ -7,4 +7,12 @@ feature_categories: | ||||||
| description: Persists timeline events for an incident | description: Persists timeline events for an incident | ||||||
| introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/74530 | introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/74530 | ||||||
| milestone: '14.6' | milestone: '14.6' | ||||||
| gitlab_schema: gitlab_main | gitlab_schema: gitlab_main_cell | ||||||
|  | allow_cross_joins: | ||||||
|  | - gitlab_main_clusterwide | ||||||
|  | allow_cross_transactions: | ||||||
|  | - gitlab_main_clusterwide | ||||||
|  | allow_cross_foreign_keys: | ||||||
|  | - gitlab_main_clusterwide | ||||||
|  | sharding_key: | ||||||
|  |   project_id: projects | ||||||
|  |  | ||||||
|  | @ -7,4 +7,12 @@ feature_categories: | ||||||
| description: Persists project-level tokens for manual Prometheus installations | description: Persists project-level tokens for manual Prometheus installations | ||||||
| introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/9334 | introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/9334 | ||||||
| milestone: '11.8' | milestone: '11.8' | ||||||
| gitlab_schema: gitlab_main | gitlab_schema: gitlab_main_cell | ||||||
|  | allow_cross_joins: | ||||||
|  | - gitlab_main_clusterwide | ||||||
|  | allow_cross_transactions: | ||||||
|  | - gitlab_main_clusterwide | ||||||
|  | allow_cross_foreign_keys: | ||||||
|  | - gitlab_main_clusterwide | ||||||
|  | sharding_key: | ||||||
|  |   project_id: projects | ||||||
|  |  | ||||||
|  | @ -7,4 +7,12 @@ feature_categories: | ||||||
| description: Persists project settings for incident management | description: Persists project settings for incident management | ||||||
| introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/9744 | introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/9744 | ||||||
| milestone: '11.9' | milestone: '11.9' | ||||||
| gitlab_schema: gitlab_main | gitlab_schema: gitlab_main_cell | ||||||
|  | allow_cross_joins: | ||||||
|  | - gitlab_main_clusterwide | ||||||
|  | allow_cross_transactions: | ||||||
|  | - gitlab_main_clusterwide | ||||||
|  | allow_cross_foreign_keys: | ||||||
|  | - gitlab_main_clusterwide | ||||||
|  | sharding_key: | ||||||
|  |   project_id: projects | ||||||
|  |  | ||||||
|  | @ -7,4 +7,12 @@ feature_categories: | ||||||
| description: Persists information about prometheus alerts from an environment | description: Persists information about prometheus alerts from an environment | ||||||
| introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/6590 | introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/6590 | ||||||
| milestone: '11.2' | milestone: '11.2' | ||||||
| gitlab_schema: gitlab_main | gitlab_schema: gitlab_main_cell | ||||||
|  | allow_cross_joins: | ||||||
|  | - gitlab_main_clusterwide | ||||||
|  | allow_cross_transactions: | ||||||
|  | - gitlab_main_clusterwide | ||||||
|  | allow_cross_foreign_keys: | ||||||
|  | - gitlab_main_clusterwide | ||||||
|  | sharding_key: | ||||||
|  |   project_id: projects | ||||||
|  |  | ||||||
|  | @ -4,8 +4,15 @@ classes: | ||||||
| - ServiceDesk::CustomEmailCredential | - ServiceDesk::CustomEmailCredential | ||||||
| feature_categories: | feature_categories: | ||||||
| - service_desk | - service_desk | ||||||
| description: Holds all the credentials for custom email | description: Holds all the credentials for custom email addresses for Service Desk | ||||||
|   addresses for Service Desk |  | ||||||
| introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/114917 | introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/114917 | ||||||
| milestone: '15.11' | milestone: '15.11' | ||||||
| gitlab_schema: gitlab_main | gitlab_schema: gitlab_main_cell | ||||||
|  | allow_cross_joins: | ||||||
|  | - gitlab_main_clusterwide | ||||||
|  | allow_cross_transactions: | ||||||
|  | - gitlab_main_clusterwide | ||||||
|  | allow_cross_foreign_keys: | ||||||
|  | - gitlab_main_clusterwide | ||||||
|  | sharding_key: | ||||||
|  |   project_id: projects | ||||||
|  |  | ||||||
|  | @ -8,4 +8,12 @@ description: Holds the verification state and additional information for custom | ||||||
|   addresses for Service Desk |   addresses for Service Desk | ||||||
| introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/112938 | introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/112938 | ||||||
| milestone: '15.10' | milestone: '15.10' | ||||||
| gitlab_schema: gitlab_main | gitlab_schema: gitlab_main_cell | ||||||
|  | allow_cross_joins: | ||||||
|  | - gitlab_main_clusterwide | ||||||
|  | allow_cross_transactions: | ||||||
|  | - gitlab_main_clusterwide | ||||||
|  | allow_cross_foreign_keys: | ||||||
|  | - gitlab_main_clusterwide | ||||||
|  | sharding_key: | ||||||
|  |   project_id: projects | ||||||
|  |  | ||||||
|  | @ -7,4 +7,12 @@ feature_categories: | ||||||
| description: Settings related to Service Desk such as templates to use for email notifications | description: Settings related to Service Desk such as templates to use for email notifications | ||||||
| introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/19515 | introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/19515 | ||||||
| milestone: '12.6' | milestone: '12.6' | ||||||
| gitlab_schema: gitlab_main | gitlab_schema: gitlab_main_cell | ||||||
|  | allow_cross_joins: | ||||||
|  | - gitlab_main_clusterwide | ||||||
|  | allow_cross_transactions: | ||||||
|  | - gitlab_main_clusterwide | ||||||
|  | allow_cross_foreign_keys: | ||||||
|  | - gitlab_main_clusterwide | ||||||
|  | sharding_key: | ||||||
|  |   project_id: projects | ||||||
|  |  | ||||||
|  | @ -7,4 +7,12 @@ feature_categories: | ||||||
| description: Project settings related to Status Page | description: Project settings related to Status Page | ||||||
| introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/25863 | introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/25863 | ||||||
| milestone: '12.9' | milestone: '12.9' | ||||||
| gitlab_schema: gitlab_main | gitlab_schema: gitlab_main_cell | ||||||
|  | allow_cross_joins: | ||||||
|  | - gitlab_main_clusterwide | ||||||
|  | allow_cross_transactions: | ||||||
|  | - gitlab_main_clusterwide | ||||||
|  | allow_cross_foreign_keys: | ||||||
|  | - gitlab_main_clusterwide | ||||||
|  | sharding_key: | ||||||
|  |   project_id: projects | ||||||
|  |  | ||||||
|  | @ -7,4 +7,12 @@ feature_categories: | ||||||
| description: Persists Zoom meetings, its associations and its metadata | description: Persists Zoom meetings, its associations and its metadata | ||||||
| introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/17890 | introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/17890 | ||||||
| milestone: '12.5' | milestone: '12.5' | ||||||
| gitlab_schema: gitlab_main | gitlab_schema: gitlab_main_cell | ||||||
|  | allow_cross_joins: | ||||||
|  | - gitlab_main_clusterwide | ||||||
|  | allow_cross_transactions: | ||||||
|  | - gitlab_main_clusterwide | ||||||
|  | allow_cross_foreign_keys: | ||||||
|  | - gitlab_main_clusterwide | ||||||
|  | sharding_key: | ||||||
|  |   project_id: projects | ||||||
|  |  | ||||||
|  | @ -0,0 +1,9 @@ | ||||||
|  | # frozen_string_literal: true | ||||||
|  | 
 | ||||||
|  | class AddPermissionsToMemberRoles < Gitlab::Database::Migration[2.2] | ||||||
|  |   milestone '16.11' | ||||||
|  | 
 | ||||||
|  |   def change | ||||||
|  |     add_column :member_roles, :permissions, :jsonb, null: false, default: {} | ||||||
|  |   end | ||||||
|  | end | ||||||
|  | @ -0,0 +1,72 @@ | ||||||
|  | # frozen_string_literal: true | ||||||
|  | 
 | ||||||
|  | class CopyPermissionsOnMemberRoles < Gitlab::Database::Migration[2.2] | ||||||
|  |   include Gitlab::Database::SchemaHelpers | ||||||
|  | 
 | ||||||
|  |   milestone '16.11' | ||||||
|  |   disable_ddl_transaction! | ||||||
|  | 
 | ||||||
|  |   FUNCTION_NAME = 'copy_member_roles_permissions' | ||||||
|  |   TRIGGER_NAME = 'trigger_copy_member_roles_permissions' | ||||||
|  | 
 | ||||||
|  |   def up | ||||||
|  |     execute(<<~SQL) | ||||||
|  |       CREATE OR REPLACE FUNCTION #{FUNCTION_NAME}() | ||||||
|  |         RETURNS trigger | ||||||
|  |         LANGUAGE plpgsql | ||||||
|  |       AS $$ | ||||||
|  |         BEGIN | ||||||
|  |           -- when permissions have not changed | ||||||
|  |           IF (current_query() !~ '\ypermissions\y') THEN | ||||||
|  |             NEW.permissions = to_jsonb (( | ||||||
|  |               SELECT | ||||||
|  |                 perm_cols | ||||||
|  |               FROM ( | ||||||
|  |                 SELECT | ||||||
|  |                   NEW.admin_cicd_variables, | ||||||
|  |                   NEW.admin_group_member, | ||||||
|  |                   NEW.admin_merge_request, | ||||||
|  |                   NEW.admin_terraform_state, | ||||||
|  |                   NEW.admin_vulnerability, | ||||||
|  |                   NEW.archive_project, | ||||||
|  |                   NEW.manage_group_access_tokens, | ||||||
|  |                   NEW.manage_project_access_tokens, | ||||||
|  |                   NEW.read_code, | ||||||
|  |                   NEW.read_dependency, | ||||||
|  |                   NEW.read_vulnerability, | ||||||
|  |                   NEW.remove_group, | ||||||
|  |                   NEW.remove_project) perm_cols)); | ||||||
|  |           -- when permissions have changed | ||||||
|  |           ELSE | ||||||
|  |             NEW.admin_cicd_variables = COALESCE((NEW.permissions->'admin_cicd_variables')::BOOLEAN, FALSE); | ||||||
|  |             NEW.admin_group_member = COALESCE((NEW.permissions->'admin_group_member')::BOOLEAN, FALSE); | ||||||
|  |             NEW.admin_merge_request = COALESCE((NEW.permissions->'admin_merge_request')::BOOLEAN, FALSE); | ||||||
|  |             NEW.admin_terraform_state = COALESCE((NEW.permissions->'admin_terraform_state')::BOOLEAN, FALSE); | ||||||
|  |             NEW.admin_vulnerability = COALESCE((NEW.permissions->'admin_vulnerability')::BOOLEAN, FALSE); | ||||||
|  |             NEW.archive_project = COALESCE((NEW.permissions->'archive_project')::BOOLEAN, FALSE); | ||||||
|  |             NEW.manage_group_access_tokens = COALESCE((NEW.permissions->'manage_group_access_tokens')::BOOLEAN, FALSE); | ||||||
|  |             NEW.manage_project_access_tokens = COALESCE((NEW.permissions->'manage_project_access_tokens')::BOOLEAN, FALSE); | ||||||
|  |             NEW.read_code = COALESCE((NEW.permissions->'read_code')::BOOLEAN, FALSE); | ||||||
|  |             NEW.read_dependency = COALESCE((NEW.permissions->'read_dependency')::BOOLEAN, FALSE); | ||||||
|  |             NEW.read_vulnerability = COALESCE((NEW.permissions->'read_vulnerability')::BOOLEAN, FALSE); | ||||||
|  |             NEW.remove_group = COALESCE((NEW.permissions->'remove_group')::BOOLEAN, FALSE); | ||||||
|  |             NEW.remove_project = COALESCE((NEW.permissions->'remove_project')::BOOLEAN, FALSE); | ||||||
|  |           END IF; | ||||||
|  |           RETURN NEW; | ||||||
|  |         END; | ||||||
|  |       $$ | ||||||
|  |     SQL | ||||||
|  | 
 | ||||||
|  |     execute(<<~SQL) | ||||||
|  |       CREATE OR REPLACE TRIGGER #{TRIGGER_NAME} | ||||||
|  |       BEFORE INSERT OR UPDATE ON member_roles | ||||||
|  |       FOR EACH ROW | ||||||
|  |       EXECUTE FUNCTION #{FUNCTION_NAME}(); | ||||||
|  |     SQL | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   def down | ||||||
|  |     drop_trigger(:member_roles, TRIGGER_NAME) | ||||||
|  |     drop_function(FUNCTION_NAME) | ||||||
|  |   end | ||||||
|  | end | ||||||
|  | @ -0,0 +1,32 @@ | ||||||
|  | # frozen_string_literal: true | ||||||
|  | 
 | ||||||
|  | class MigrateCustomPermissions < Gitlab::Database::Migration[2.2] | ||||||
|  |   milestone '16.11' | ||||||
|  |   restrict_gitlab_migration gitlab_schema: :gitlab_main | ||||||
|  |   disable_ddl_transaction! | ||||||
|  | 
 | ||||||
|  |   PERMISSION_COLUMNS = %w[ | ||||||
|  |     admin_cicd_variables | ||||||
|  |     admin_group_member | ||||||
|  |     admin_merge_request | ||||||
|  |     admin_terraform_state | ||||||
|  |     admin_vulnerability | ||||||
|  |     archive_project | ||||||
|  |     manage_group_access_tokens | ||||||
|  |     manage_project_access_tokens | ||||||
|  |     read_code | ||||||
|  |     read_dependency | ||||||
|  |     read_vulnerability | ||||||
|  |     remove_group | ||||||
|  |     remove_project | ||||||
|  |   ].join(', ') | ||||||
|  | 
 | ||||||
|  |   def up | ||||||
|  |     update_value = Arel.sql("(SELECT to_jsonb ((SELECT perm_cols FROM (SELECT #{PERMISSION_COLUMNS}) perm_cols)))") | ||||||
|  |     update_column_in_batches(:member_roles, :permissions, update_value) | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   def down | ||||||
|  |     update_column_in_batches(:member_roles, :permissions, '{}') | ||||||
|  |   end | ||||||
|  | end | ||||||
|  | @ -0,0 +1,18 @@ | ||||||
|  | # frozen_string_literal: true | ||||||
|  | 
 | ||||||
|  | class AddPreReceiveSecretDetectionEnabledToProjectSecuritySettings < Gitlab::Database::Migration[2.2] | ||||||
|  |   milestone '16.11' | ||||||
|  | 
 | ||||||
|  |   enable_lock_retries! | ||||||
|  |   TABLE_NAME = :project_security_settings | ||||||
|  |   COLUMN_NAME = :pre_receive_secret_detection_enabled | ||||||
|  | 
 | ||||||
|  |   def up | ||||||
|  |     add_column TABLE_NAME, COLUMN_NAME, :boolean, null: false, | ||||||
|  |       default: false | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   def down | ||||||
|  |     remove_column TABLE_NAME, COLUMN_NAME | ||||||
|  |   end | ||||||
|  | end | ||||||
|  | @ -0,0 +1,72 @@ | ||||||
|  | # frozen_string_literal: true | ||||||
|  | 
 | ||||||
|  | class RemoveCopyPermissionsOnMemberRoles < Gitlab::Database::Migration[2.2] | ||||||
|  |   include Gitlab::Database::SchemaHelpers | ||||||
|  | 
 | ||||||
|  |   milestone '16.11' | ||||||
|  |   disable_ddl_transaction! | ||||||
|  | 
 | ||||||
|  |   FUNCTION_NAME = 'copy_member_roles_permissions' | ||||||
|  |   TRIGGER_NAME = 'trigger_copy_member_roles_permissions' | ||||||
|  | 
 | ||||||
|  |   def up | ||||||
|  |     drop_trigger(:member_roles, TRIGGER_NAME) | ||||||
|  |     drop_function(FUNCTION_NAME) | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   def down | ||||||
|  |     execute(<<~SQL) | ||||||
|  |       CREATE OR REPLACE FUNCTION #{FUNCTION_NAME}() | ||||||
|  |         RETURNS trigger | ||||||
|  |         LANGUAGE plpgsql | ||||||
|  |       AS $$ | ||||||
|  |         BEGIN | ||||||
|  |           -- when permissions have not changed | ||||||
|  |           IF (current_query() !~ '\ypermissions\y') THEN | ||||||
|  |             NEW.permissions = to_jsonb (( | ||||||
|  |               SELECT | ||||||
|  |                 perm_cols | ||||||
|  |               FROM ( | ||||||
|  |                 SELECT | ||||||
|  |                   NEW.admin_cicd_variables, | ||||||
|  |                   NEW.admin_group_member, | ||||||
|  |                   NEW.admin_merge_request, | ||||||
|  |                   NEW.admin_terraform_state, | ||||||
|  |                   NEW.admin_vulnerability, | ||||||
|  |                   NEW.archive_project, | ||||||
|  |                   NEW.manage_group_access_tokens, | ||||||
|  |                   NEW.manage_project_access_tokens, | ||||||
|  |                   NEW.read_code, | ||||||
|  |                   NEW.read_dependency, | ||||||
|  |                   NEW.read_vulnerability, | ||||||
|  |                   NEW.remove_group, | ||||||
|  |                   NEW.remove_project) perm_cols)); | ||||||
|  |           -- when permissions have changed | ||||||
|  |           ELSE | ||||||
|  |             NEW.admin_cicd_variables = COALESCE((NEW.permissions->'admin_cicd_variables')::BOOLEAN, FALSE); | ||||||
|  |             NEW.admin_group_member = COALESCE((NEW.permissions->'admin_group_member')::BOOLEAN, FALSE); | ||||||
|  |             NEW.admin_merge_request = COALESCE((NEW.permissions->'admin_merge_request')::BOOLEAN, FALSE); | ||||||
|  |             NEW.admin_terraform_state = COALESCE((NEW.permissions->'admin_terraform_state')::BOOLEAN, FALSE); | ||||||
|  |             NEW.admin_vulnerability = COALESCE((NEW.permissions->'admin_vulnerability')::BOOLEAN, FALSE); | ||||||
|  |             NEW.archive_project = COALESCE((NEW.permissions->'archive_project')::BOOLEAN, FALSE); | ||||||
|  |             NEW.manage_group_access_tokens = COALESCE((NEW.permissions->'manage_group_access_tokens')::BOOLEAN, FALSE); | ||||||
|  |             NEW.manage_project_access_tokens = COALESCE((NEW.permissions->'manage_project_access_tokens')::BOOLEAN, FALSE); | ||||||
|  |             NEW.read_code = COALESCE((NEW.permissions->'read_code')::BOOLEAN, FALSE); | ||||||
|  |             NEW.read_dependency = COALESCE((NEW.permissions->'read_dependency')::BOOLEAN, FALSE); | ||||||
|  |             NEW.read_vulnerability = COALESCE((NEW.permissions->'read_vulnerability')::BOOLEAN, FALSE); | ||||||
|  |             NEW.remove_group = COALESCE((NEW.permissions->'remove_group')::BOOLEAN, FALSE); | ||||||
|  |             NEW.remove_project = COALESCE((NEW.permissions->'remove_project')::BOOLEAN, FALSE); | ||||||
|  |           END IF; | ||||||
|  |           RETURN NEW; | ||||||
|  |         END; | ||||||
|  |       $$ | ||||||
|  |     SQL | ||||||
|  | 
 | ||||||
|  |     execute(<<~SQL) | ||||||
|  |       CREATE OR REPLACE TRIGGER #{TRIGGER_NAME} | ||||||
|  |       BEFORE INSERT OR UPDATE ON member_roles | ||||||
|  |       FOR EACH ROW | ||||||
|  |       EXECUTE FUNCTION #{FUNCTION_NAME}(); | ||||||
|  |     SQL | ||||||
|  |   end | ||||||
|  | end | ||||||
|  | @ -0,0 +1 @@ | ||||||
|  | e87e345f4f1c23d7da6139d650f2495d19f29861bc4687a500004cb16d66ff1c | ||||||
|  | @ -0,0 +1 @@ | ||||||
|  | b62e7414bc855cffc756356a4d737a7180ef059d5247b46af06ad004a40ed052 | ||||||
|  | @ -0,0 +1 @@ | ||||||
|  | e288768e45871e930fa0ecd6fb2ebeec2ac8ab838ce3957a2f73c398bfd7a619 | ||||||
|  | @ -0,0 +1 @@ | ||||||
|  | 9440a6ae18916cd700585f419d6bc22e0a44f4eeeef3402f0522bd26dce79be9 | ||||||
|  | @ -0,0 +1 @@ | ||||||
|  | c7f58b9a72200dcbf1895ee1d9d0f75eca278211cadd1c325565f253c250c224 | ||||||
|  | @ -10794,6 +10794,7 @@ CREATE TABLE member_roles ( | ||||||
|     admin_cicd_variables boolean DEFAULT false NOT NULL, |     admin_cicd_variables boolean DEFAULT false NOT NULL, | ||||||
|     remove_group boolean DEFAULT false NOT NULL, |     remove_group boolean DEFAULT false NOT NULL, | ||||||
|     occupies_seat boolean DEFAULT false NOT NULL, |     occupies_seat boolean DEFAULT false NOT NULL, | ||||||
|  |     permissions jsonb DEFAULT '{}'::jsonb NOT NULL, | ||||||
|     CONSTRAINT check_4364846f58 CHECK ((char_length(description) <= 255)), |     CONSTRAINT check_4364846f58 CHECK ((char_length(description) <= 255)), | ||||||
|     CONSTRAINT check_9907916995 CHECK ((char_length(name) <= 255)) |     CONSTRAINT check_9907916995 CHECK ((char_length(name) <= 255)) | ||||||
| ); | ); | ||||||
|  | @ -14346,7 +14347,8 @@ CREATE TABLE project_security_settings ( | ||||||
|     auto_fix_dependency_scanning boolean DEFAULT true NOT NULL, |     auto_fix_dependency_scanning boolean DEFAULT true NOT NULL, | ||||||
|     auto_fix_sast boolean DEFAULT true NOT NULL, |     auto_fix_sast boolean DEFAULT true NOT NULL, | ||||||
|     continuous_vulnerability_scans_enabled boolean DEFAULT false NOT NULL, |     continuous_vulnerability_scans_enabled boolean DEFAULT false NOT NULL, | ||||||
|     container_scanning_for_registry_enabled boolean DEFAULT false NOT NULL |     container_scanning_for_registry_enabled boolean DEFAULT false NOT NULL, | ||||||
|  |     pre_receive_secret_detection_enabled boolean DEFAULT false NOT NULL | ||||||
| ); | ); | ||||||
| 
 | 
 | ||||||
| CREATE SEQUENCE project_security_settings_project_id_seq | CREATE SEQUENCE project_security_settings_project_id_seq | ||||||
|  |  | ||||||
|  | @ -1769,7 +1769,7 @@ Parameters: | ||||||
| | --------- | ---- | -------- | ----------- | | | --------- | ---- | -------- | ----------- | | ||||||
| | `token`   | string | true | The Telegram bot token (for example, `123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11`). | | | `token`   | string | true | The Telegram bot token (for example, `123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11`). | | ||||||
| | `room` | string | true | Unique identifier for the target chat or the username of the target channel (in the format `@channelusername`). | | | `room` | string | true | Unique identifier for the target chat or the username of the target channel (in the format `@channelusername`). | | ||||||
| | `thread` | integer | false | Unique identifier for the target message thread (topic in a forum supergroup). | | | `thread` | integer | false | Unique identifier for the target message thread (topic in a forum supergroup). [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/441097) in GitLab 16.11. | | ||||||
| | `notify_only_broken_pipelines` | boolean | false | Send notifications for broken pipelines. | | | `notify_only_broken_pipelines` | boolean | false | Send notifications for broken pipelines. | | ||||||
| | `branches_to_be_notified` | string | false | Branches to send notifications for ([introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/134361) in GitLab 16.5). Valid options are `all`, `default`, `protected`, and `default_and_protected`. The default value is `default`. | | | `branches_to_be_notified` | string | false | Branches to send notifications for ([introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/134361) in GitLab 16.5). Valid options are `all`, `default`, `protected`, and `default_and_protected`. The default value is `default`. | | ||||||
| | `push_events` | boolean | true | Enable notifications for push events. | | | `push_events` | boolean | true | Enable notifications for push events. | | ||||||
|  |  | ||||||
|  | @ -19,7 +19,7 @@ info: | ||||||
|     name: CC BY-SA 4.0 |     name: CC BY-SA 4.0 | ||||||
|     url: 'https://gitlab.com/gitlab-org/gitlab/-/blob/master/LICENSE' |     url: 'https://gitlab.com/gitlab-org/gitlab/-/blob/master/LICENSE' | ||||||
| servers: | servers: | ||||||
| - url: https://www.gitlab.com/api/ | - url: https://www.gitlab.com/api/v4 | ||||||
| security: | security: | ||||||
|   - ApiKeyAuth: [] |   - ApiKeyAuth: [] | ||||||
| tags: | tags: | ||||||
|  | @ -176,7 +176,7 @@ tags: | ||||||
| - name: unleash_api | - name: unleash_api | ||||||
|   description: Operations related to Unleash API |   description: Operations related to Unleash API | ||||||
| paths: | paths: | ||||||
|   /api/v4/groups/{id}/badges/{badge_id}: |   /groups/{id}/badges/{badge_id}: | ||||||
|     get: |     get: | ||||||
|       tags: |       tags: | ||||||
|       - badges |       - badges | ||||||
|  | @ -271,7 +271,7 @@ paths: | ||||||
|         204: |         204: | ||||||
|           description: Removes a badge from the group. |           description: Removes a badge from the group. | ||||||
|           content: {} |           content: {} | ||||||
|   /api/v4/groups/{id}/badges: |   /groups/{id}/badges: | ||||||
|     get: |     get: | ||||||
|       tags: |       tags: | ||||||
|       - badges |       - badges | ||||||
|  | @ -353,7 +353,7 @@ paths: | ||||||
|             application/json: |             application/json: | ||||||
|               schema: |               schema: | ||||||
|                 $ref: '#/components/schemas/API_Entities_Badge' |                 $ref: '#/components/schemas/API_Entities_Badge' | ||||||
|   /api/v4/groups/{id}/badges/render: |   /groups/{id}/badges/render: | ||||||
|     get: |     get: | ||||||
|       tags: |       tags: | ||||||
|       - badges |       - badges | ||||||
|  | @ -387,7 +387,7 @@ paths: | ||||||
|             application/json: |             application/json: | ||||||
|               schema: |               schema: | ||||||
|                 $ref: '#/components/schemas/API_Entities_BasicBadgeDetails' |                 $ref: '#/components/schemas/API_Entities_BasicBadgeDetails' | ||||||
|   /api/v4/groups/{id}/access_requests/{user_id}: |   /groups/{id}/access_requests/{user_id}: | ||||||
|     delete: |     delete: | ||||||
|       tags: |       tags: | ||||||
|       - access_requests |       - access_requests | ||||||
|  | @ -413,7 +413,7 @@ paths: | ||||||
|         204: |         204: | ||||||
|           description: Denies an access request for the given user. |           description: Denies an access request for the given user. | ||||||
|           content: {} |           content: {} | ||||||
|   /api/v4/groups/{id}/access_requests/{user_id}/approve: |   /groups/{id}/access_requests/{user_id}/approve: | ||||||
|     put: |     put: | ||||||
|       tags: |       tags: | ||||||
|       - access_requests |       - access_requests | ||||||
|  | @ -461,7 +461,7 @@ paths: | ||||||
|                 state: active |                 state: active | ||||||
|                 created_at: 2012-10-22T14:13:35Z |                 created_at: 2012-10-22T14:13:35Z | ||||||
|                 access_level: 20 |                 access_level: 20 | ||||||
|   /api/v4/groups/{id}/access_requests: |   /groups/{id}/access_requests: | ||||||
|     get: |     get: | ||||||
|       tags: |       tags: | ||||||
|       - access_requests |       - access_requests | ||||||
|  | @ -526,7 +526,7 @@ paths: | ||||||
|                 state: active |                 state: active | ||||||
|                 created_at: 2012-10-22T14:13:35Z |                 created_at: 2012-10-22T14:13:35Z | ||||||
|                 access_level: 20 |                 access_level: 20 | ||||||
|   /api/v4/projects/{id}/repository/merged_branches: |   /projects/{id}/repository/merged_branches: | ||||||
|     delete: |     delete: | ||||||
|       tags: |       tags: | ||||||
|       - branches |       - branches | ||||||
|  | @ -546,7 +546,7 @@ paths: | ||||||
|         404: |         404: | ||||||
|           description: 404 Project Not Found |           description: 404 Project Not Found | ||||||
|           content: {} |           content: {} | ||||||
|   /api/v4/projects/{id}/repository/branches/{branch}: |   /projects/{id}/repository/branches/{branch}: | ||||||
|     get: |     get: | ||||||
|       tags: |       tags: | ||||||
|       - branches |       - branches | ||||||
|  | @ -625,7 +625,7 @@ paths: | ||||||
|         404: |         404: | ||||||
|           description: Not Found |           description: Not Found | ||||||
|           content: {} |           content: {} | ||||||
|   /api/v4/projects/{id}/repository/branches: |   /projects/{id}/repository/branches: | ||||||
|     get: |     get: | ||||||
|       tags: |       tags: | ||||||
|       - branches |       - branches | ||||||
|  | @ -722,7 +722,7 @@ paths: | ||||||
|         400: |         400: | ||||||
|           description: Failed to create branch |           description: Failed to create branch | ||||||
|           content: {} |           content: {} | ||||||
|   /api/v4/projects/{id}/repository/branches/{branch}/unprotect: |   /projects/{id}/repository/branches/{branch}/unprotect: | ||||||
|     put: |     put: | ||||||
|       tags: |       tags: | ||||||
|       - branches |       - branches | ||||||
|  | @ -751,7 +751,7 @@ paths: | ||||||
|         404: |         404: | ||||||
|           description: 404 Project Not Found |           description: 404 Project Not Found | ||||||
|           content: {} |           content: {} | ||||||
|   /api/v4/projects/{id}/repository/branches/{branch}/protect: |   /projects/{id}/repository/branches/{branch}/protect: | ||||||
|     put: |     put: | ||||||
|       tags: |       tags: | ||||||
|       - branches |       - branches | ||||||
|  | @ -791,7 +791,7 @@ paths: | ||||||
|         404: |         404: | ||||||
|           description: 404 Branch Not Found |           description: 404 Branch Not Found | ||||||
|           content: {} |           content: {} | ||||||
|   /api/v4/projects/{id}/badges/{badge_id}: |   /projects/{id}/badges/{badge_id}: | ||||||
|     get: |     get: | ||||||
|       tags: |       tags: | ||||||
|       - badges |       - badges | ||||||
|  | @ -886,7 +886,7 @@ paths: | ||||||
|         204: |         204: | ||||||
|           description: Removes a badge from the project. |           description: Removes a badge from the project. | ||||||
|           content: {} |           content: {} | ||||||
|   /api/v4/projects/{id}/badges: |   /projects/{id}/badges: | ||||||
|     get: |     get: | ||||||
|       tags: |       tags: | ||||||
|       - badges |       - badges | ||||||
|  | @ -969,7 +969,7 @@ paths: | ||||||
|             application/json: |             application/json: | ||||||
|               schema: |               schema: | ||||||
|                 $ref: '#/components/schemas/API_Entities_Badge' |                 $ref: '#/components/schemas/API_Entities_Badge' | ||||||
|   /api/v4/projects/{id}/badges/render: |   /projects/{id}/badges/render: | ||||||
|     get: |     get: | ||||||
|       tags: |       tags: | ||||||
|       - badges |       - badges | ||||||
|  | @ -1003,7 +1003,7 @@ paths: | ||||||
|             application/json: |             application/json: | ||||||
|               schema: |               schema: | ||||||
|                 $ref: '#/components/schemas/API_Entities_BasicBadgeDetails' |                 $ref: '#/components/schemas/API_Entities_BasicBadgeDetails' | ||||||
|   /api/v4/projects/{id}/access_requests/{user_id}: |   /projects/{id}/access_requests/{user_id}: | ||||||
|     delete: |     delete: | ||||||
|       tags: |       tags: | ||||||
|       - access_requests |       - access_requests | ||||||
|  | @ -1029,7 +1029,7 @@ paths: | ||||||
|         204: |         204: | ||||||
|           description: Denies an access request for the given user. |           description: Denies an access request for the given user. | ||||||
|           content: {} |           content: {} | ||||||
|   /api/v4/projects/{id}/access_requests/{user_id}/approve: |   /projects/{id}/access_requests/{user_id}/approve: | ||||||
|     put: |     put: | ||||||
|       tags: |       tags: | ||||||
|       - access_requests |       - access_requests | ||||||
|  | @ -1077,7 +1077,7 @@ paths: | ||||||
|                 state: active |                 state: active | ||||||
|                 created_at: 2012-10-22T14:13:35Z |                 created_at: 2012-10-22T14:13:35Z | ||||||
|                 access_level: 20 |                 access_level: 20 | ||||||
|   /api/v4/projects/{id}/access_requests: |   /projects/{id}/access_requests: | ||||||
|     get: |     get: | ||||||
|       tags: |       tags: | ||||||
|       - access_requests |       - access_requests | ||||||
|  | @ -1142,7 +1142,7 @@ paths: | ||||||
|                 state: active |                 state: active | ||||||
|                 created_at: 2012-10-22T14:13:35Z |                 created_at: 2012-10-22T14:13:35Z | ||||||
|                 access_level: 20 |                 access_level: 20 | ||||||
|   /api/v4/projects/{id}/alert_management_alerts/{alert_iid}/metric_images/{metric_image_id}: |   /projects/{id}/alert_management_alerts/{alert_iid}/metric_images/{metric_image_id}: | ||||||
|     put: |     put: | ||||||
|       tags: |       tags: | ||||||
|       - alert_management |       - alert_management | ||||||
|  | @ -1232,7 +1232,7 @@ paths: | ||||||
|         422: |         422: | ||||||
|           description: Unprocessable entity |           description: Unprocessable entity | ||||||
|           content: {} |           content: {} | ||||||
|   /api/v4/projects/{id}/alert_management_alerts/{alert_iid}/metric_images: |   /projects/{id}/alert_management_alerts/{alert_iid}/metric_images: | ||||||
|     get: |     get: | ||||||
|       tags: |       tags: | ||||||
|       - alert_management |       - alert_management | ||||||
|  | @ -1311,7 +1311,7 @@ paths: | ||||||
|         403: |         403: | ||||||
|           description: Forbidden |           description: Forbidden | ||||||
|           content: {} |           content: {} | ||||||
|   /api/v4/projects/{id}/alert_management_alerts/{alert_iid}/metric_images/authorize: |   /projects/{id}/alert_management_alerts/{alert_iid}/metric_images/authorize: | ||||||
|     post: |     post: | ||||||
|       tags: |       tags: | ||||||
|       - alert_management |       - alert_management | ||||||
|  | @ -1338,7 +1338,7 @@ paths: | ||||||
|         403: |         403: | ||||||
|           description: Forbidden |           description: Forbidden | ||||||
|           content: {} |           content: {} | ||||||
|   /api/v4/admin/batched_background_migrations/{id}: |   /admin/batched_background_migrations/{id}: | ||||||
|     get: |     get: | ||||||
|       tags: |       tags: | ||||||
|       - batched_background_migrations |       - batched_background_migrations | ||||||
|  | @ -1380,7 +1380,7 @@ paths: | ||||||
|         404: |         404: | ||||||
|           description: 404 Not found |           description: 404 Not found | ||||||
|           content: {} |           content: {} | ||||||
|   /api/v4/admin/batched_background_migrations: |   /admin/batched_background_migrations: | ||||||
|     get: |     get: | ||||||
|       tags: |       tags: | ||||||
|       - batched_background_migrations |       - batched_background_migrations | ||||||
|  | @ -1414,7 +1414,7 @@ paths: | ||||||
|         403: |         403: | ||||||
|           description: 403 Forbidden |           description: 403 Forbidden | ||||||
|           content: {} |           content: {} | ||||||
|   /api/v4/admin/batched_background_migrations/{id}/resume: |   /admin/batched_background_migrations/{id}/resume: | ||||||
|     put: |     put: | ||||||
|       tags: |       tags: | ||||||
|       - batched_background_migrations |       - batched_background_migrations | ||||||
|  | @ -1462,7 +1462,7 @@ paths: | ||||||
|         422: |         422: | ||||||
|           description: You can resume only `paused` batched background migrations. |           description: You can resume only `paused` batched background migrations. | ||||||
|           content: {} |           content: {} | ||||||
|   /api/v4/admin/batched_background_migrations/{id}/pause: |   /admin/batched_background_migrations/{id}/pause: | ||||||
|     put: |     put: | ||||||
|       tags: |       tags: | ||||||
|       - batched_background_migrations |       - batched_background_migrations | ||||||
|  | @ -1510,7 +1510,7 @@ paths: | ||||||
|         422: |         422: | ||||||
|           description: You can pause only `active` batched background migrations. |           description: You can pause only `active` batched background migrations. | ||||||
|           content: {} |           content: {} | ||||||
|   /api/v4/admin/ci/variables/{key}: |   /admin/ci/variables/{key}: | ||||||
|     get: |     get: | ||||||
|       tags: |       tags: | ||||||
|       - ci_variables |       - ci_variables | ||||||
|  | @ -1601,7 +1601,7 @@ paths: | ||||||
|         404: |         404: | ||||||
|           description: Instance Variable Not Found |           description: Instance Variable Not Found | ||||||
|           content: {} |           content: {} | ||||||
|   /api/v4/admin/ci/variables: |   /admin/ci/variables: | ||||||
|     get: |     get: | ||||||
|       tags: |       tags: | ||||||
|       - ci_variables |       - ci_variables | ||||||
|  | @ -1675,7 +1675,7 @@ paths: | ||||||
|         400: |         400: | ||||||
|           description: 400 Bad Request |           description: 400 Bad Request | ||||||
|           content: {} |           content: {} | ||||||
|   /api/v4/admin/databases/{database_name}/dictionary/tables/{table_name}: |   /admin/databases/{database_name}/dictionary/tables/{table_name}: | ||||||
|     get: |     get: | ||||||
|       tags: |       tags: | ||||||
|       - admin |       - admin | ||||||
|  | @ -1713,7 +1713,7 @@ paths: | ||||||
|         404: |         404: | ||||||
|           description: 404 Not found |           description: 404 Not found | ||||||
|           content: {} |           content: {} | ||||||
|   /api/v4/admin/clusters/{cluster_id}: |   /admin/clusters/{cluster_id}: | ||||||
|     get: |     get: | ||||||
|       tags: |       tags: | ||||||
|       - clusters |       - clusters | ||||||
|  | @ -1845,7 +1845,7 @@ paths: | ||||||
|         404: |         404: | ||||||
|           description: Not found |           description: Not found | ||||||
|           content: {} |           content: {} | ||||||
|   /api/v4/admin/clusters/add: |   /admin/clusters/add: | ||||||
|     post: |     post: | ||||||
|       tags: |       tags: | ||||||
|       - clusters |       - clusters | ||||||
|  | @ -1928,7 +1928,7 @@ paths: | ||||||
|         404: |         404: | ||||||
|           description: Not found |           description: Not found | ||||||
|           content: {} |           content: {} | ||||||
|   /api/v4/admin/clusters: |   /admin/clusters: | ||||||
|     get: |     get: | ||||||
|       tags: |       tags: | ||||||
|       - clusters |       - clusters | ||||||
|  | @ -1948,7 +1948,7 @@ paths: | ||||||
|         403: |         403: | ||||||
|           description: Forbidden |           description: Forbidden | ||||||
|           content: {} |           content: {} | ||||||
|   /api/v4/admin/migrations/{timestamp}/mark: |   /admin/migrations/{timestamp}/mark: | ||||||
|     post: |     post: | ||||||
|       tags: |       tags: | ||||||
|       - migrations |       - migrations | ||||||
|  | @ -1993,7 +1993,7 @@ paths: | ||||||
|         422: |         422: | ||||||
|           description: You can mark only pending migrations |           description: You can mark only pending migrations | ||||||
|           content: {} |           content: {} | ||||||
|   /api/v4/applications/{id}: |   /applications/{id}: | ||||||
|     delete: |     delete: | ||||||
|       tags: |       tags: | ||||||
|       - applications |       - applications | ||||||
|  | @ -2012,7 +2012,7 @@ paths: | ||||||
|         204: |         204: | ||||||
|           description: Delete an application |           description: Delete an application | ||||||
|           content: {} |           content: {} | ||||||
|   /api/v4/applications: |   /applications: | ||||||
|     get: |     get: | ||||||
|       tags: |       tags: | ||||||
|       - applications |       - applications | ||||||
|  | @ -2068,7 +2068,7 @@ paths: | ||||||
|             application/json: |             application/json: | ||||||
|               schema: |               schema: | ||||||
|                 $ref: '#/components/schemas/API_Entities_ApplicationWithSecret' |                 $ref: '#/components/schemas/API_Entities_ApplicationWithSecret' | ||||||
|   /api/v4/avatar: |   /avatar: | ||||||
|     get: |     get: | ||||||
|       tags: |       tags: | ||||||
|       - avatar |       - avatar | ||||||
|  | @ -2094,7 +2094,7 @@ paths: | ||||||
|             application/json: |             application/json: | ||||||
|               schema: |               schema: | ||||||
|                 $ref: '#/components/schemas/API_Entities_Avatar' |                 $ref: '#/components/schemas/API_Entities_Avatar' | ||||||
|   /api/v4/broadcast_messages/{id}: |   /broadcast_messages/{id}: | ||||||
|     get: |     get: | ||||||
|       tags: |       tags: | ||||||
|       - broadcast_messages |       - broadcast_messages | ||||||
|  | @ -2204,7 +2204,7 @@ paths: | ||||||
|             application/json: |             application/json: | ||||||
|               schema: |               schema: | ||||||
|                 $ref: '#/components/schemas/API_Entities_BroadcastMessage' |                 $ref: '#/components/schemas/API_Entities_BroadcastMessage' | ||||||
|   /api/v4/broadcast_messages: |   /broadcast_messages: | ||||||
|     get: |     get: | ||||||
|       tags: |       tags: | ||||||
|       - broadcast_messages |       - broadcast_messages | ||||||
|  | @ -2295,7 +2295,7 @@ paths: | ||||||
|             application/json: |             application/json: | ||||||
|               schema: |               schema: | ||||||
|                 $ref: '#/components/schemas/API_Entities_BroadcastMessage' |                 $ref: '#/components/schemas/API_Entities_BroadcastMessage' | ||||||
|   /api/v4/bulk_imports/{import_id}/entities/{entity_id}: |   /bulk_imports/{import_id}/entities/{entity_id}: | ||||||
|     get: |     get: | ||||||
|       tags: |       tags: | ||||||
|       - bulk_imports |       - bulk_imports | ||||||
|  | @ -2333,7 +2333,7 @@ paths: | ||||||
|         503: |         503: | ||||||
|           description: Service unavailable |           description: Service unavailable | ||||||
|           content: {} |           content: {} | ||||||
|   /api/v4/bulk_imports/{import_id}/entities: |   /bulk_imports/{import_id}/entities: | ||||||
|     get: |     get: | ||||||
|       tags: |       tags: | ||||||
|       - bulk_imports |       - bulk_imports | ||||||
|  | @ -2391,7 +2391,7 @@ paths: | ||||||
|         503: |         503: | ||||||
|           description: Service unavailable |           description: Service unavailable | ||||||
|           content: {} |           content: {} | ||||||
|   /api/v4/bulk_imports/{import_id}: |   /bulk_imports/{import_id}: | ||||||
|     get: |     get: | ||||||
|       tags: |       tags: | ||||||
|       - bulk_imports |       - bulk_imports | ||||||
|  | @ -2422,7 +2422,7 @@ paths: | ||||||
|         503: |         503: | ||||||
|           description: Service unavailable |           description: Service unavailable | ||||||
|           content: {} |           content: {} | ||||||
|   /api/v4/bulk_imports/entities: |   /bulk_imports/entities: | ||||||
|     get: |     get: | ||||||
|       tags: |       tags: | ||||||
|       - bulk_imports |       - bulk_imports | ||||||
|  | @ -2483,7 +2483,7 @@ paths: | ||||||
|         503: |         503: | ||||||
|           description: Service unavailable |           description: Service unavailable | ||||||
|           content: {} |           content: {} | ||||||
|   /api/v4/bulk_imports: |   /bulk_imports: | ||||||
|     get: |     get: | ||||||
|       tags: |       tags: | ||||||
|       - bulk_imports |       - bulk_imports | ||||||
|  | @ -2624,7 +2624,7 @@ paths: | ||||||
|         503: |         503: | ||||||
|           description: Service unavailable |           description: Service unavailable | ||||||
|           content: {} |           content: {} | ||||||
|   /api/v4/application/appearance: |   /application/appearance: | ||||||
|     get: |     get: | ||||||
|       tags: |       tags: | ||||||
|       - application |       - application | ||||||
|  | @ -2707,7 +2707,7 @@ paths: | ||||||
|             application/json: |             application/json: | ||||||
|               schema: |               schema: | ||||||
|                 $ref: '#/components/schemas/API_Entities_Appearance' |                 $ref: '#/components/schemas/API_Entities_Appearance' | ||||||
|   /api/v4/application/plan_limits: |   /application/plan_limits: | ||||||
|     get: |     get: | ||||||
|       tags: |       tags: | ||||||
|       - plan_limits |       - plan_limits | ||||||
|  | @ -2869,7 +2869,7 @@ paths: | ||||||
|         403: |         403: | ||||||
|           description: Forbidden |           description: Forbidden | ||||||
|           content: {} |           content: {} | ||||||
|   /api/v4/metadata: |   /metadata: | ||||||
|     get: |     get: | ||||||
|       tags: |       tags: | ||||||
|       - metadata |       - metadata | ||||||
|  | @ -2886,7 +2886,7 @@ paths: | ||||||
|         401: |         401: | ||||||
|           description: Unauthorized |           description: Unauthorized | ||||||
|           content: {} |           content: {} | ||||||
|   /api/v4/version: |   /version: | ||||||
|     get: |     get: | ||||||
|       tags: |       tags: | ||||||
|       - metadata |       - metadata | ||||||
|  | @ -2904,7 +2904,7 @@ paths: | ||||||
|         401: |         401: | ||||||
|           description: Unauthorized |           description: Unauthorized | ||||||
|           content: {} |           content: {} | ||||||
|   /api/v4/projects/{id}/jobs: |   /projects/{id}/jobs: | ||||||
|     get: |     get: | ||||||
|       tags: |       tags: | ||||||
|       - jobs |       - jobs | ||||||
|  | @ -2934,7 +2934,7 @@ paths: | ||||||
|                 type: array |                 type: array | ||||||
|                 items: |                 items: | ||||||
|                   $ref: '#/components/schemas/API_Entities_Job' |                   $ref: '#/components/schemas/API_Entities_Job' | ||||||
|   /api/v4/projects/{id}/jobs/{job_id}: |   /projects/{id}/jobs/{job_id}: | ||||||
|     get: |     get: | ||||||
|       tags: |       tags: | ||||||
|       - jobs |       - jobs | ||||||
|  | @ -2960,7 +2960,7 @@ paths: | ||||||
|             application/json: |             application/json: | ||||||
|               schema: |               schema: | ||||||
|                 $ref: '#/components/schemas/API_Entities_Job' |                 $ref: '#/components/schemas/API_Entities_Job' | ||||||
|   /api/v4/projects/{id}/jobs/{job_id}/play: |   /projects/{id}/jobs/{job_id}/play: | ||||||
|     post: |     post: | ||||||
|       tags: |       tags: | ||||||
|       - jobs |       - jobs | ||||||
|  |  | ||||||
|  | @ -421,8 +421,9 @@ scope. | ||||||
| | GitLab Rails app | `%16.0`   | Adapt `register_{group|project}_runner` permissions to take [application setting](https://gitlab.com/gitlab-org/gitlab/-/issues/386712) in consideration. | | | GitLab Rails app | `%16.0`   | Adapt `register_{group|project}_runner` permissions to take [application setting](https://gitlab.com/gitlab-org/gitlab/-/issues/386712) in consideration. | | ||||||
| | GitLab Rails app | `%16.1`   | Make [`POST /api/v4/runners` endpoint](../../../api/runners.md#create-an-instance-runner) permanently return `HTTP 410 Gone` if either `allow_runner_registration_token` setting disables registration tokens.<br/>A future v5 version of the API should return `HTTP 404 Not Found`. | | | GitLab Rails app | `%16.1`   | Make [`POST /api/v4/runners` endpoint](../../../api/runners.md#create-an-instance-runner) permanently return `HTTP 410 Gone` if either `allow_runner_registration_token` setting disables registration tokens.<br/>A future v5 version of the API should return `HTTP 404 Not Found`. | | ||||||
| | GitLab Rails app | `%16.1`   | Add runner group metadata to the runner list. | | | GitLab Rails app | `%16.1`   | Add runner group metadata to the runner list. | | ||||||
| | GitLab Rails app |           | Add UI to allow disabling use of registration tokens in top-level group settings.                                                                                                                                                                                                                                                               | | | GitLab Rails app | `%16.11`  | Add UI to allow disabling use of registration tokens in top-level group settings.                                                                                                                                                                                                                                                               | | ||||||
| | GitLab Rails app |           | Hide legacy UI showing registration with a registration token, if it disabled on in top-level group settings or by admins.                                                                                                                                                                                                         | | | GitLab Rails app | `%16.11`  | Add UI to allow disabling use of registration tokens in admin panel. | | ||||||
|  | | GitLab Rails app | `%16.11`  | Hide legacy UI showing registration with a registration token, if it disabled on in top-level group settings or by admins.                                                                                                                                                                                                         | | ||||||
| 
 | 
 | ||||||
| <!-- markdownlint-enable MD056 --> | <!-- markdownlint-enable MD056 --> | ||||||
| 
 | 
 | ||||||
|  | @ -432,7 +433,6 @@ scope. | ||||||
| |------------------|----------:|---------| | |------------------|----------:|---------| | ||||||
| | GitLab Rails app |   `%17.0` | Disable registration tokens for all groups by running database migration (only on GitLab.com) | | | GitLab Rails app |   `%17.0` | Disable registration tokens for all groups by running database migration (only on GitLab.com) | | ||||||
| | GitLab Rails app |   `%17.0` | Disable registration tokens on the instance level by running database migration (except GitLab.com) | | | GitLab Rails app |   `%17.0` | Disable registration tokens on the instance level by running database migration (except GitLab.com) | | ||||||
| | GitLab Rails app |   `%17.0` | Disable registration tokens on the instance level for GitLab.com | |  | ||||||
| | GitLab Rails app |   `%16.3` | Implement new `:create_runner` PPGAT scope so that we don't require a full `api` scope. | | | GitLab Rails app |   `%16.3` | Implement new `:create_runner` PPGAT scope so that we don't require a full `api` scope. | | ||||||
| | GitLab Rails app |           | Document gotchas when [automatically rotating runner tokens](../../../ci/runners/configure_runners.md#automatically-rotate-runner-authentication-tokens) with multiple machines. | | | GitLab Rails app |           | Document gotchas when [automatically rotating runner tokens](../../../ci/runners/configure_runners.md#automatically-rotate-runner-authentication-tokens) with multiple machines. | | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -147,14 +147,14 @@ DETAILS: | ||||||
| **Tier:** Free, Premium, Ultimate | **Tier:** Free, Premium, Ultimate | ||||||
| **Offering:** GitLab.com | **Offering:** GitLab.com | ||||||
| 
 | 
 | ||||||
| If you're using GitLab SaaS, you can purchase additional packs of compute minutes. | If you're using GitLab.com, you can purchase additional packs of compute minutes. | ||||||
| These additional compute minutes: | These additional compute minutes: | ||||||
| 
 | 
 | ||||||
| - Are used only after the monthly quota included in your subscription runs out. | - Are used only after the monthly quota included in your subscription runs out. | ||||||
| - Are carried over to the next month, if any remain at the end of the month. | - Are carried over to the next month, if any remain at the end of the month. | ||||||
| - Are valid for 12 months from date of purchase or until all compute minutes are consumed, whichever comes first. Expiry of compute minutes is not enforced. | - Are valid for 12 months from date of purchase or until all compute minutes are consumed, whichever comes first. Expiry of compute minutes is not enforced. | ||||||
| 
 | 
 | ||||||
| For example, with a GitLab SaaS Premium license: | For example, with a GitLab.com Premium license: | ||||||
| 
 | 
 | ||||||
| - You have `10,000` monthly compute minutes. | - You have `10,000` monthly compute minutes. | ||||||
| - You purchase an additional `5,000` compute minutes. | - You purchase an additional `5,000` compute minutes. | ||||||
|  | @ -207,7 +207,7 @@ To purchase additional compute minutes for your personal namespace: | ||||||
| 1. Select **Edit profile**. | 1. Select **Edit profile**. | ||||||
| 1. On the left sidebar, select **Usage Quotas**. | 1. On the left sidebar, select **Usage Quotas**. | ||||||
| 1. Select **Buy additional compute minutes**. GitLab redirects you to the Customers Portal. | 1. Select **Buy additional compute minutes**. GitLab redirects you to the Customers Portal. | ||||||
| 1. Locate the subscription card that's linked to your personal namespace on GitLab SaaS, select **Buy more compute minutes**, | 1. Locate the subscription card that's linked to your personal namespace on GitLab.com, select **Buy more compute minutes**, | ||||||
|    and complete the details of the transaction. |    and complete the details of the transaction. | ||||||
| 
 | 
 | ||||||
| After your payment is processed, the additional compute minutes are added to your personal | After your payment is processed, the additional compute minutes are added to your personal | ||||||
|  | @ -279,11 +279,11 @@ For this reduced cost factor: | ||||||
| GitLab administrators can add a namespace to the reduced cost factor | GitLab administrators can add a namespace to the reduced cost factor | ||||||
| [with a flag](../../administration/feature_flags.md) named `ci_minimal_cost_factor_for_gitlab_namespaces`. | [with a flag](../../administration/feature_flags.md) named `ci_minimal_cost_factor_for_gitlab_namespaces`. | ||||||
| 
 | 
 | ||||||
| ### Additional costs on GitLab SaaS | ### GitLab-hosted runner costs | ||||||
| 
 | 
 | ||||||
| GitLab SaaS runners have different cost factors, depending on the runner type (Linux, Windows, macOS) and the virtual machine configuration. | GitLab-hosted runners have different cost factors, depending on the runner type (Linux, Windows, macOS) and the virtual machine configuration. | ||||||
| 
 | 
 | ||||||
| | GitLab SaaS runner type      | Machine Size           | Cost factor | | | GitLab-hosted runner type    | Machine Size           | Cost factor | | ||||||
| |:-----------------------------|:-----------------------|:------------| | |:-----------------------------|:-----------------------|:------------| | ||||||
| | Linux OS amd64               | `small`                | 1           | | | Linux OS amd64               | `small`                | 1           | | ||||||
| | Linux OS amd64               | `medium`               | 2           | | | Linux OS amd64               | `medium`               | 2           | | ||||||
|  | @ -291,8 +291,8 @@ GitLab SaaS runners have different cost factors, depending on the runner type (L | ||||||
| | Linux OS amd64               | `xlarge`               | 6           | | | Linux OS amd64               | `xlarge`               | 6           | | ||||||
| | Linux OS amd64               | `2xlarge`              | 12          | | | Linux OS amd64               | `2xlarge`              | 12          | | ||||||
| | Linux OS amd64 + GPU-enabled | `medium`, GPU standard | 7           | | | Linux OS amd64 + GPU-enabled | `medium`, GPU standard | 7           | | ||||||
| | macOS M1                     | `medium`               | 6 (**Status:** Beta)    | | | macOS M1                     | `medium`               | 6 (**Status:** Beta) | | ||||||
| | Windows Server               | -                      | 1 (**Status:** Beta)    | | | Windows Server               | -                      | 1 (**Status:** Beta) | | ||||||
| 
 | 
 | ||||||
| ### Monthly reset of compute usage | ### Monthly reset of compute usage | ||||||
| 
 | 
 | ||||||
|  | @ -336,9 +336,9 @@ The grace period for running jobs is `1,000` compute minutes. | ||||||
| 
 | 
 | ||||||
| Jobs on project runners are not affected by the compute quota. | Jobs on project runners are not affected by the compute quota. | ||||||
| 
 | 
 | ||||||
| ### GitLab SaaS usage notifications | ### GitLab.com usage notifications | ||||||
| 
 | 
 | ||||||
| On GitLab SaaS an in-app banner is displayed and an email notification sent to the namespace owners when: | On GitLab.com an in-app banner is displayed and an email notification sent to the namespace owners when: | ||||||
| 
 | 
 | ||||||
| - The remaining compute minutes is below 30% of the quota. | - The remaining compute minutes is below 30% of the quota. | ||||||
| - The remaining compute minutes is below 5% of the quota. | - The remaining compute minutes is below 5% of the quota. | ||||||
|  |  | ||||||
|  | @ -32,7 +32,7 @@ For Free, Premium, and Ultimate plan customers, jobs on these instances consume | ||||||
| The `small` machine type is set as default. If no [tag](../../yaml/index.md#tags) keyword in your `.gitlab-ci.yml` file is specified, | The `small` machine type is set as default. If no [tag](../../yaml/index.md#tags) keyword in your `.gitlab-ci.yml` file is specified, | ||||||
| the jobs will run on this default runner. | the jobs will run on this default runner. | ||||||
| 
 | 
 | ||||||
| There are [different rates of compute minutes consumption](../../pipelines/cicd_minutes.md#additional-costs-on-gitlab-saas), based on the type of machine that is used. | There are [different rates of compute minutes consumption](../../pipelines/cicd_minutes.md#gitlab-hosted-runner-costs), based on the type of machine that is used. | ||||||
| 
 | 
 | ||||||
| All hosted runners on Linux currently run on | All hosted runners on Linux currently run on | ||||||
| [`n2d-standard`](https://cloud.google.com/compute/docs/general-purpose-machines#n2d_machines) general-purpose compute from GCP. | [`n2d-standard`](https://cloud.google.com/compute/docs/general-purpose-machines#n2d_machines) general-purpose compute from GCP. | ||||||
|  |  | ||||||
|  | @ -23,7 +23,7 @@ Your jobs can run on: | ||||||
| - [Hosted runners on Windows](saas/windows_saas_runner.md) ([Beta](../../policy/experiment-beta-support.md#beta)) | - [Hosted runners on Windows](saas/windows_saas_runner.md) ([Beta](../../policy/experiment-beta-support.md#beta)) | ||||||
| - [Hosted runners on macOS](saas/macos_saas_runner.md) ([Beta](../../policy/experiment-beta-support.md#beta)) | - [Hosted runners on macOS](saas/macos_saas_runner.md) ([Beta](../../policy/experiment-beta-support.md#beta)) | ||||||
| 
 | 
 | ||||||
| For more information about the cost factor applied to the machine type based on size, see [cost factor](../../ci/pipelines/cicd_minutes.md#cost-factor). | For more information about the cost factor applied to the machine type based on size, see [cost factor](../../ci/pipelines/cicd_minutes.md#gitlab-hosted-runner-costs). | ||||||
| The number of minutes you can use on these runners depends on the [maximum number of units of compute](../pipelines/cicd_minutes.md) | The number of minutes you can use on these runners depends on the [maximum number of units of compute](../pipelines/cicd_minutes.md) | ||||||
| in your [subscription plan](https://about.gitlab.com/pricing/). | in your [subscription plan](https://about.gitlab.com/pricing/). | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -30,10 +30,10 @@ This should enable everyone to see locally any change in an IDE being sent to th | ||||||
|         1. You will see completion request URLs being fetched that match the Git remote URL for your GDK. |         1. You will see completion request URLs being fetched that match the Git remote URL for your GDK. | ||||||
| 1. Main Application (GDK): | 1. Main Application (GDK): | ||||||
|    1. Install the [GitLab Development Kit](https://gitlab.com/gitlab-org/gitlab-development-kit/-/blob/main/doc/index.md#one-line-installation). |    1. Install the [GitLab Development Kit](https://gitlab.com/gitlab-org/gitlab-development-kit/-/blob/main/doc/index.md#one-line-installation). | ||||||
|    1. Enable Feature Flag ```code_suggestions_tokens_api```: |    1. Enable Feature Flag ```ai_duo_code_suggestions_switch```: | ||||||
|       1. In your terminal, go to your `gitlab-development-kit` > `gitlab` directory. |       1. In your terminal, go to your `gitlab-development-kit` > `gitlab` directory. | ||||||
|       1. Run `gdk rails console` or `bundle exec rails c` to start a Rails console. |       1. Run `gdk rails console` or `bundle exec rails c` to start a Rails console. | ||||||
|       1. [Enable the Feature Flag](../../administration/feature_flags.md#enable-or-disable-the-feature) for the code suggestions tokens API by calling `Feature.enable(:code_suggestions_tokens_api)` from the console. |       1. [Enable the Feature Flag](../../administration/feature_flags.md#enable-or-disable-the-feature) for the code suggestions tokens API by calling `Feature.enable(:ai_duo_code_suggestions_switch)` from the console. | ||||||
|    1. Set the AI Gateway URL environmental variable by running `export AI_GATEWAY_URL=http://localhost:5052`. |    1. Set the AI Gateway URL environmental variable by running `export AI_GATEWAY_URL=http://localhost:5052`. | ||||||
|    1. Run your GDK server with `gdk start` if it's not already running. |    1. Run your GDK server with `gdk start` if it's not already running. | ||||||
| 1. [Setup AI Gateway](https://gitlab.com/gitlab-org/modelops/applied-ml/code-suggestions/ai-assist): | 1. [Setup AI Gateway](https://gitlab.com/gitlab-org/modelops/applied-ml/code-suggestions/ai-assist): | ||||||
|  |  | ||||||
|  | @ -193,9 +193,9 @@ security dashboard. | ||||||
| | `requirements` | no | The list of custom permissions this ability is dependent on. For instance `admin_vulnerability` is dependent on `read_vulnerability`. If none, then enter `[]`  | | | `requirements` | no | The list of custom permissions this ability is dependent on. For instance `admin_vulnerability` is dependent on `read_vulnerability`. If none, then enter `[]`  | | ||||||
| | `available_from_access_level` | no | The access level from which this ability is available, if applicable. See the section on [understanding logic for individual abilities](#understanding-logic-for-individual-abilities) for help on determining the base access level for an ability. | | | `available_from_access_level` | no | The access level from which this ability is available, if applicable. See the section on [understanding logic for individual abilities](#understanding-logic-for-individual-abilities) for help on determining the base access level for an ability. | | ||||||
| 
 | 
 | ||||||
| #### Step 2: Create a migration file | #### Step 2: Create a spec file and update validation schema | ||||||
| 
 | 
 | ||||||
| - Run `bundle exec rails generate gitlab:custom_roles:code --ability <ABILITY_NAME>` which will generate a migration file to add the ability as a boolean column to the `member_roles` table. | - Run `bundle exec rails generate gitlab:custom_roles:code --ability <ABILITY_NAME>` which will update the permissions validation schema file and create an empty spec file. | ||||||
| 
 | 
 | ||||||
| #### Step 3: Update policies | #### Step 3: Update policies | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -60,12 +60,12 @@ For other features: | ||||||
| 
 | 
 | ||||||
| ### Disable GitLab Duo features | ### Disable GitLab Duo features | ||||||
| 
 | 
 | ||||||
| > - [Settings to disable AI features were introduced](https://gitlab.com/groups/gitlab-org/-/epics/12404) in GitLab 16.10. |  | ||||||
| 
 |  | ||||||
| DETAILS: | DETAILS: | ||||||
| **Tier:** Premium, Ultimate | **Tier:** Premium, Ultimate | ||||||
| **Offering:** GitLab.com, Self-managed, GitLab Dedicated | **Offering:** GitLab.com, Self-managed, GitLab Dedicated | ||||||
| 
 | 
 | ||||||
|  | > - [Settings to disable AI features introduced](https://gitlab.com/groups/gitlab-org/-/epics/12404) in GitLab 16.10. | ||||||
|  | 
 | ||||||
| You can disable GitLab Duo AI features for a group, project, or instance. | You can disable GitLab Duo AI features for a group, project, or instance. | ||||||
| When it's disabled, any attempt to use GitLab Duo features on the group, project, or instance is blocked and an error is displayed. | When it's disabled, any attempt to use GitLab Duo features on the group, project, or instance is blocked and an error is displayed. | ||||||
| GitLab Duo features are also blocked for resources in the group or project, like epics, | GitLab Duo features are also blocked for resources in the group or project, like epics, | ||||||
|  |  | ||||||
|  | @ -413,7 +413,7 @@ The following package managers use lockfiles that GitLab analyzers are capable o | ||||||
|     </tr> |     </tr> | ||||||
|     <tr> |     <tr> | ||||||
|       <td>yarn</td> |       <td>yarn</td> | ||||||
|       <td>v1, v2<sup><b><a href="#notes-regarding-parsing-lockfiles-4">4</a></b></sup>, v3<sup><b><a href="#notes-regarding-parsing-lockfiles-4">4</a></b></sup></td> |       <td>versions 1, 2, 3, 4<sup><b><a href="#notes-regarding-parsing-lockfiles-4">4</a></b></sup></td> | ||||||
|       <td> |       <td> | ||||||
|         <a href="https://gitlab.com/gitlab-org/security-products/analyzers/gemnasium/-/blob/master/qa/fixtures/js-yarn/classic/default/yarn.lock#L2">1.x</a>, |         <a href="https://gitlab.com/gitlab-org/security-products/analyzers/gemnasium/-/blob/master/qa/fixtures/js-yarn/classic/default/yarn.lock#L2">1.x</a>, | ||||||
|         <a href="https://gitlab.com/gitlab-org/security-products/analyzers/gemnasium/-/blob/master/qa/fixtures/js-yarn/berry/v2/default/yarn.lock">2.x</a>, |         <a href="https://gitlab.com/gitlab-org/security-products/analyzers/gemnasium/-/blob/master/qa/fixtures/js-yarn/berry/v2/default/yarn.lock">2.x</a>, | ||||||
|  | @ -453,10 +453,10 @@ The following package managers use lockfiles that GitLab analyzers are capable o | ||||||
|   <li> |   <li> | ||||||
|     <a id="notes-regarding-parsing-lockfiles-4"></a> |     <a id="notes-regarding-parsing-lockfiles-4"></a> | ||||||
|     <p> |     <p> | ||||||
|       Support for Yarn <code>v2</code> and <code>v3</code> was <a href="https://gitlab.com/gitlab-org/gitlab/-/issues/263358">introduced in GitLab 15.11</a>. However, this feature is also available to versions of GitLab 15.0 and later. |       Support for Yarn version 4 was <a href="https://gitlab.com/gitlab-org/gitlab/-/issues/431752">introduced</a> in GitLab 16.11. | ||||||
|     </p> |     </p> | ||||||
|     <p> |     <p> | ||||||
|       The following features are not supported for Yarn <code>v2</code> or <code>v3</code>: |       The following features are not supported for Yarn Berry: | ||||||
|     </p> |     </p> | ||||||
|     <ul> |     <ul> | ||||||
|       <li> |       <li> | ||||||
|  |  | ||||||
|  | @ -258,6 +258,74 @@ Note the following: | ||||||
|   - If the CI/CD variables suffixed `_DISABLED_ANALYZERS` were declared in a policy, their values were |   - If the CI/CD variables suffixed `_DISABLED_ANALYZERS` were declared in a policy, their values were | ||||||
|     ignored, regardless of where they were defined: policy, group, or project.   |     ignored, regardless of where they were defined: policy, group, or project.   | ||||||
| 
 | 
 | ||||||
|  | ## Security policy scopes | ||||||
|  | 
 | ||||||
|  | > - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/135398) in GitLab 16.7 [with a flag](../../../administration/feature_flags.md) named `security_policies_policy_scope`. Enabled by default. | ||||||
|  | > - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/443594) in GitLab 16.11. Feature flag `security_policies_policy_scope` removed. | ||||||
|  | 
 | ||||||
|  | Security policy enforcement depends first on establishing a link between the group, subgroup, or | ||||||
|  | project on which you want to enforce policies, and the security policy project that contains the | ||||||
|  | policies. For example, if you are linking policies to a group, a group owner must create the link to | ||||||
|  | the security policy project. Then, all policies in the security policy project are inherited by all | ||||||
|  | projects in the group. | ||||||
|  | 
 | ||||||
|  | You can refine a security policy's scope to: | ||||||
|  | 
 | ||||||
|  | - _Include_ only projects containing a compliance framework label. | ||||||
|  | - _Include_ or _exclude_ selected projects from enforcement. | ||||||
|  | 
 | ||||||
|  | ### Policy scope schema | ||||||
|  | 
 | ||||||
|  | | Field | Type | Required | Possible values | Description | | ||||||
|  | |-------|------|----------|-----------------|-------------| | ||||||
|  | | `policy_scope` | `object` | false | `compliance_frameworks`, `projects` | Scopes the policy based on compliance framework labels or projects you define. | | ||||||
|  | 
 | ||||||
|  | #### `policy_scope` scope type | ||||||
|  | 
 | ||||||
|  | | Field | Type | Possible values | Description | | ||||||
|  | |-------|------|-----------------|-------------| | ||||||
|  | | `compliance_frameworks` | `array` |  | List of IDs of the compliance frameworks in scope of enforcement, in an array of objects with key `id`. | | ||||||
|  | | `projects` | `object` |  `including`, `excluding` | Use `excluding:` or `including:` then list the IDs of the projects you wish to include or exclude, in an array of objects with key `id`. | | ||||||
|  | 
 | ||||||
|  | #### Example `policy.yml` with security policy scopes | ||||||
|  | 
 | ||||||
|  | ```yaml | ||||||
|  | --- | ||||||
|  | scan_execution_policy: | ||||||
|  | - name: Enforce DAST in every release pipeline | ||||||
|  |   description: This policy enforces pipeline configuration to have a job with DAST scan for release branches | ||||||
|  |   enabled: true | ||||||
|  |   rules: | ||||||
|  |   - type: pipeline | ||||||
|  |     branches: | ||||||
|  |     - release/* | ||||||
|  |   actions: | ||||||
|  |   - scan: dast | ||||||
|  |     scanner_profile: Scanner Profile A | ||||||
|  |     site_profile: Site Profile B | ||||||
|  |   policy_scope: | ||||||
|  |     compliance_frameworks: | ||||||
|  |       - id: 2 | ||||||
|  |       - id: 11 | ||||||
|  | - name: Enforce Secret Detection and Container Scanning in every default branch pipeline | ||||||
|  |   description: This policy enforces pipeline configuration to have a job with Secret Detection and Container Scanning scans for the default branch | ||||||
|  |   enabled: true | ||||||
|  |   rules: | ||||||
|  |   - type: pipeline | ||||||
|  |     branches: | ||||||
|  |     - main | ||||||
|  |   actions: | ||||||
|  |   - scan: secret_detection | ||||||
|  |   - scan: sast | ||||||
|  |     variables: | ||||||
|  |       SAST_EXCLUDED_ANALYZERS: brakeman | ||||||
|  |   policy_scope: | ||||||
|  |     projects: | ||||||
|  |       excluding: | ||||||
|  |         - id: 24 | ||||||
|  |         - id: 27 | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
| ## Example security policies project | ## Example security policies project | ||||||
| 
 | 
 | ||||||
| You can use this example in a `.gitlab/security-policies/policy.yml` file stored in a | You can use this example in a `.gitlab/security-policies/policy.yml` file stored in a | ||||||
|  | @ -438,81 +506,3 @@ scan_execution_policy: | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| In this example a `test job` is injected into the `test` stage of the pipeline, printing `Hello World`. | In this example a `test job` is injected into the `test` stage of the pipeline, printing `Hello World`. | ||||||
| 
 |  | ||||||
| ### Security policy scopes |  | ||||||
| 
 |  | ||||||
| Prerequisites: |  | ||||||
| 
 |  | ||||||
| - To enable the pipeline execution policy action feature, a group owner or administrator must enable |  | ||||||
|   the experimental feature: |  | ||||||
| 
 |  | ||||||
|   1. On the left sidebar, select **Search or go to** and find your group. |  | ||||||
|   1. Select **Settings > General**. |  | ||||||
|   1. Expand **Permissions and group features**. |  | ||||||
|   1. Select the **Security Policy Scopes** checkbox. |  | ||||||
|   1. Optional. Select **Enforce for all subgroups**. |  | ||||||
| 
 |  | ||||||
|      If the setting is not enforced for all subgroups, subgroup owners can manage the setting per subgroup. |  | ||||||
| 
 |  | ||||||
| Security policy enforcement depends first on establishing a link between the group, subgroup, or |  | ||||||
| project on which you want to enforce policies, and the security policy project that contains the |  | ||||||
| policies. For example, if you are linking policies to a group, a group owner must create the link to |  | ||||||
| the security policy project. Then, all policies in the security policy project are inherited by all |  | ||||||
| projects in the group. |  | ||||||
| 
 |  | ||||||
| You can refine a security policy's scope to: |  | ||||||
| 
 |  | ||||||
| - _Include_ only projects containing a compliance framework label. |  | ||||||
| - _Include_ or _exclude_ selected projects from enforcement. |  | ||||||
| 
 |  | ||||||
| #### Policy scope schema |  | ||||||
| 
 |  | ||||||
| | Field | Type | Required | Possible values | Description | |  | ||||||
| |-------|------|----------|-----------------|-------------| |  | ||||||
| | `policy_scope` | `object` | false | `compliance_frameworks`, `projects` | Scopes the policy based on compliance framework labels or projects you define. | |  | ||||||
| 
 |  | ||||||
| #### `policy_scope` scope type |  | ||||||
| 
 |  | ||||||
| | Field | Type | Possible values | Description | |  | ||||||
| |-------|------|-----------------|-------------| |  | ||||||
| | `compliance_frameworks` | `array` |  | List of IDs of the compliance frameworks in scope of enforcement, in an array of objects with key `id`. | |  | ||||||
| | `projects` | `object` |  `including`, `excluding` | Use `excluding:` or `including:` then list the IDs of the projects you wish to include or exclude, in an array of objects with key `id`. | |  | ||||||
| 
 |  | ||||||
| #### Example `policy.yml` with security policy scopes |  | ||||||
| 
 |  | ||||||
| ```yaml |  | ||||||
| --- |  | ||||||
| scan_execution_policy: |  | ||||||
| - name: Enforce DAST in every release pipeline |  | ||||||
|   description: This policy enforces pipeline configuration to have a job with DAST scan for release branches |  | ||||||
|   enabled: true |  | ||||||
|   rules: |  | ||||||
|   - type: pipeline |  | ||||||
|     branches: |  | ||||||
|     - release/* |  | ||||||
|   actions: |  | ||||||
|   - scan: dast |  | ||||||
|     scanner_profile: Scanner Profile A |  | ||||||
|     site_profile: Site Profile B |  | ||||||
|   policy_scope: |  | ||||||
|     compliance_frameworks: |  | ||||||
|       - id: 2 |  | ||||||
|       - id: 11 |  | ||||||
| - name: Enforce Secret Detection and Container Scanning in every default branch pipeline |  | ||||||
|   description: This policy enforces pipeline configuration to have a job with Secret Detection and Container Scanning scans for the default branch |  | ||||||
|   enabled: true |  | ||||||
|   rules: |  | ||||||
|   - type: pipeline |  | ||||||
|     branches: |  | ||||||
|     - main |  | ||||||
|   actions: |  | ||||||
|   - scan: secret_detection |  | ||||||
|   - scan: sast |  | ||||||
|     variables: |  | ||||||
|       SAST_EXCLUDED_ANALYZERS: brakeman |  | ||||||
|   policy_scope: |  | ||||||
|     projects: |  | ||||||
|       excluding: |  | ||||||
|         - id: 24 |  | ||||||
|         - id: 27 |  | ||||||
| ``` |  | ||||||
|  |  | ||||||
|  | @ -384,6 +384,7 @@ The following table describes the rate limits for GitLab.com: | ||||||
| | **Alert integration endpoint** requests (for a given **project**)          | **3600** requests per hour           | | | **Alert integration endpoint** requests (for a given **project**)          | **3600** requests per hour           | | ||||||
| | **[Pull mirroring](../project/repository/mirror/pull.md)** intervals       | **5** minutes                        | | | **[Pull mirroring](../project/repository/mirror/pull.md)** intervals       | **5** minutes                        | | ||||||
| | **API Requests** (from a given **user**) to `/api/v4/users/:id`            | **300** requests per **10 minutes**  | | | **API Requests** (from a given **user**) to `/api/v4/users/:id`            | **300** requests per **10 minutes**  | | ||||||
|  | | GitLab package cloud requests for a given IP address ([introduced](https://gitlab.com/gitlab-com/gl-infra/production-engineering/-/issues/24083) in GitLab 16.11) | 3,000 requests per minute | | ||||||
| 
 | 
 | ||||||
| More details are available on the rate limits for | More details are available on the rate limits for | ||||||
| [protected paths](#protected-paths-throttle) and | [protected paths](#protected-paths-throttle) and | ||||||
|  |  | ||||||
|  | @ -40,6 +40,8 @@ To configure the bot in Telegram: | ||||||
| 
 | 
 | ||||||
| ## Set up the Telegram integration in GitLab | ## Set up the Telegram integration in GitLab | ||||||
| 
 | 
 | ||||||
|  | > - **Message thread ID** [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/441097) in GitLab 16.11. | ||||||
|  | 
 | ||||||
| After you invite the bot to a Telegram channel, you can configure GitLab to send notifications: | After you invite the bot to a Telegram channel, you can configure GitLab to send notifications: | ||||||
| 
 | 
 | ||||||
| 1. To enable the integration: | 1. To enable the integration: | ||||||
|  |  | ||||||
|  | @ -48,7 +48,7 @@ module Gitlab | ||||||
|             'media_src' => "'self' data: blob: http: https:", |             'media_src' => "'self' data: blob: http: https:", | ||||||
|             'script_src' => ContentSecurityPolicy::Directives.script_src, |             'script_src' => ContentSecurityPolicy::Directives.script_src, | ||||||
|             'style_src' => ContentSecurityPolicy::Directives.style_src, |             'style_src' => ContentSecurityPolicy::Directives.style_src, | ||||||
|             'worker_src' => "#{Gitlab::Utils.append_path(Gitlab.config.gitlab.url, 'assets/')} blob: data:", |             'worker_src' => ContentSecurityPolicy::Directives.worker_src, | ||||||
|             'object_src' => "'none'", |             'object_src' => "'none'", | ||||||
|             'report_uri' => nil |             'report_uri' => nil | ||||||
|           } |           } | ||||||
|  |  | ||||||
|  | @ -22,6 +22,10 @@ module Gitlab | ||||||
|       def self.style_src |       def self.style_src | ||||||
|         "'self' 'unsafe-inline'" |         "'self' 'unsafe-inline'" | ||||||
|       end |       end | ||||||
|  | 
 | ||||||
|  |       def self.worker_src | ||||||
|  |         "'self' #{Gitlab::Utils.append_path(Gitlab.config.gitlab.url, 'assets/')} blob: data:" | ||||||
|  |       end | ||||||
|     end |     end | ||||||
|   end |   end | ||||||
| end | end | ||||||
|  |  | ||||||
|  | @ -108,6 +108,12 @@ RSpec.describe Gitlab::ContentSecurityPolicy::ConfigLoader, feature_category: :s | ||||||
|       end |       end | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|  |     describe 'the worker-src directive' do | ||||||
|  |       it 'can be loaded from local origins' do | ||||||
|  |         expect(worker_src).to eq("'self' http://localhost/assets/ blob: data:") | ||||||
|  |       end | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|     describe 'Webpack dev server websocket connections' do |     describe 'Webpack dev server websocket connections' do | ||||||
|       let(:webpack_dev_server_host) { 'webpack-dev-server.com' } |       let(:webpack_dev_server_host) { 'webpack-dev-server.com' } | ||||||
|       let(:webpack_dev_server_port) { '9999' } |       let(:webpack_dev_server_port) { '9999' } | ||||||
|  | @ -319,7 +325,7 @@ RSpec.describe Gitlab::ContentSecurityPolicy::ConfigLoader, feature_category: :s | ||||||
|           expect(script_src).to eq(::Gitlab::ContentSecurityPolicy::Directives.script_src) |           expect(script_src).to eq(::Gitlab::ContentSecurityPolicy::Directives.script_src) | ||||||
|           expect(style_src).to eq(::Gitlab::ContentSecurityPolicy::Directives.style_src) |           expect(style_src).to eq(::Gitlab::ContentSecurityPolicy::Directives.style_src) | ||||||
|           expect(font_src).to eq("'self'") |           expect(font_src).to eq("'self'") | ||||||
|           expect(worker_src).to eq("http://localhost/assets/ blob: data:") |           expect(worker_src).to eq(::Gitlab::ContentSecurityPolicy::Directives.worker_src) | ||||||
|           expect(frame_src).to eq(::Gitlab::ContentSecurityPolicy::Directives.frame_src) |           expect(frame_src).to eq(::Gitlab::ContentSecurityPolicy::Directives.frame_src) | ||||||
|         end |         end | ||||||
|       end |       end | ||||||
|  |  | ||||||
|  | @ -0,0 +1,26 @@ | ||||||
|  | # frozen_string_literal: true | ||||||
|  | 
 | ||||||
|  | require 'spec_helper' | ||||||
|  | require_migration! | ||||||
|  | 
 | ||||||
|  | RSpec.describe MigrateCustomPermissions, feature_category: :permissions do | ||||||
|  |   let(:member_roles) { table(:member_roles) } | ||||||
|  |   let!(:member_role_a) { member_roles.create!(name: 'a', base_access_level: 10, read_code: true) } | ||||||
|  |   let!(:member_role_b) { member_roles.create!(name: 'b', base_access_level: 10, archive_project: true) } | ||||||
|  |   let(:boolean_permissions_where) { { read_code: true } } | ||||||
|  |   let(:jsonb_permissions_where) { "member_roles.permissions @> ('{\"read_code\":true}')::jsonb" } | ||||||
|  | 
 | ||||||
|  |   it 'correctly migrates up and down' do | ||||||
|  |     disable_migrations_output do | ||||||
|  |       reversible_migration do |migration| | ||||||
|  |         migration.before -> { | ||||||
|  |           expect(member_roles.where(boolean_permissions_where).pluck(:id)).to contain_exactly(member_role_a.id) | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         migration.after -> { | ||||||
|  |           expect(member_roles.where(jsonb_permissions_where).pluck(:id)).to contain_exactly(member_role_a.id) | ||||||
|  |         } | ||||||
|  |       end | ||||||
|  |     end | ||||||
|  |   end | ||||||
|  | end | ||||||
|  | @ -54,4 +54,55 @@ RSpec.describe ProjectExportJob, feature_category: :importers, type: :model do | ||||||
|       end |       end | ||||||
|     end |     end | ||||||
|   end |   end | ||||||
|  | 
 | ||||||
|  |   describe 'status transitions' do | ||||||
|  |     let(:queued)   { ProjectExportJob::STATUS[:queued] } | ||||||
|  |     let(:started)  { ProjectExportJob::STATUS[:started] } | ||||||
|  |     let(:failed)   { ProjectExportJob::STATUS[:failed] } | ||||||
|  |     let(:finished) { ProjectExportJob::STATUS[:finished] } | ||||||
|  | 
 | ||||||
|  |     context 'when a new ProjectExportJob is created' do | ||||||
|  |       let(:project_export_job) { create(:project_export_job) } | ||||||
|  | 
 | ||||||
|  |       it 'is initialized in the queued state' do | ||||||
|  |         expect(project_export_job).to be_queued | ||||||
|  |       end | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     context 'when the ProjectExportJob is in queued state' do | ||||||
|  |       let(:project_export_job) { create(:project_export_job) } | ||||||
|  | 
 | ||||||
|  |       it 'can transition to started state' do | ||||||
|  |         expect { project_export_job.start }.to change { project_export_job.status }.from(queued).to(started) | ||||||
|  |       end | ||||||
|  | 
 | ||||||
|  |       it 'can transition to failed state' do | ||||||
|  |         expect { project_export_job.fail_op }.to change { project_export_job.status }.from(queued).to(failed) | ||||||
|  |       end | ||||||
|  | 
 | ||||||
|  |       it 'cannnot transition to finished state' do | ||||||
|  |         expect { project_export_job.finish }.not_to change { project_export_job.status } | ||||||
|  |       end | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     context 'when the ProjectExportJob is in started state' do | ||||||
|  |       let(:project_export_job) { create(:project_export_job, status: started) } | ||||||
|  | 
 | ||||||
|  |       it 'can transition to finished state' do | ||||||
|  |         expect { project_export_job.finish }.to change { project_export_job.status }.from(started).to(finished) | ||||||
|  |       end | ||||||
|  | 
 | ||||||
|  |       it 'can transition to failed state' do | ||||||
|  |         expect { project_export_job.fail_op }.to change { project_export_job.status }.from(started).to(failed) | ||||||
|  |       end | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     context 'when the ProjectExportJob is in finished state' do | ||||||
|  |       let(:project_export_job) { create(:project_export_job, status: finished) } | ||||||
|  | 
 | ||||||
|  |       it 'does not transition further' do | ||||||
|  |         expect { project_export_job.fail_op }.not_to change { project_export_job.status } | ||||||
|  |       end | ||||||
|  |     end | ||||||
|  |   end | ||||||
| end | end | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue