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 | ||||
|   extends: | ||||
|     - .qa-base | ||||
|   timeout: 4h | ||||
|   timeout: 3h | ||||
|   variables: | ||||
|     QA_SCENARIO: "Test::Instance::Any" | ||||
|     QA_SCENARIO: "Test::Instance::Smoke" | ||||
|     RELEASE: "${CI_REGISTRY}/${CI_PROJECT_PATH}/gitlab-ee-qa:${CI_COMMIT_SHA}" | ||||
|     GITLAB_QA_OPTS: --address "https://gitlab.${ENVIRONMENT}.release.gke.gitlab.net" | ||||
|     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(:linked_work_items, project) | ||||
|     push_frontend_feature_flag(:display_work_item_epic_issue_sidebar, project) | ||||
|     push_frontend_feature_flag(:notifications_todos_buttons, current_user) | ||||
|   end | ||||
| 
 | ||||
|   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(:display_work_item_epic_issue_sidebar, project) | ||||
|     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) | ||||
|   end | ||||
| 
 | ||||
|  |  | |||
|  | @ -24,7 +24,8 @@ module Projects | |||
|           auto_fix_user_path: auto_fix_user_path, | ||||
|           security_training_enabled: project.security_training_available?, | ||||
|           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 | ||||
| 
 | ||||
|  | @ -98,6 +99,7 @@ module Projects | |||
| 
 | ||||
|       def continuous_vulnerability_scans_enabled; end | ||||
|       def container_scanning_for_registry_enabled; end | ||||
|       def pre_receive_secret_detection_enabled; 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 | ||||
| rollout_issue_url: | ||||
| milestone: '16.1' | ||||
|  | @ -7,4 +7,12 @@ feature_categories: | |||
| description: Persists incoming alert data including its payload | ||||
| introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/29864 | ||||
| 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 | ||||
| introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/43634 | ||||
| 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 | ||||
| feature_categories: | ||||
| - 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 | ||||
| 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 | ||||
| milestone: '14.7' | ||||
| 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 | ||||
| introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/60685 | ||||
| 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 | ||||
| introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/47407 | ||||
| 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 | ||||
| milestone: '15.6' | ||||
| gitlab_schema: gitlab_main_cell | ||||
| sharding_key: | ||||
|   project_id: projects | ||||
|  |  | |||
|  | @ -7,4 +7,12 @@ feature_categories: | |||
| description: Persists timeline events for an incident | ||||
| introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/74530 | ||||
| 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 | ||||
| introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/9334 | ||||
| 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 | ||||
| introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/9744 | ||||
| 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 | ||||
| introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/6590 | ||||
| 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 | ||||
| feature_categories: | ||||
| - service_desk | ||||
| description: Holds all the credentials for custom email | ||||
|   addresses for Service Desk | ||||
| description: Holds all the credentials for custom email addresses for Service Desk | ||||
| introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/114917 | ||||
| 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 | ||||
| introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/112938 | ||||
| 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 | ||||
| introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/19515 | ||||
| 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 | ||||
| introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/25863 | ||||
| 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 | ||||
| introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/17890 | ||||
| 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, | ||||
|     remove_group 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_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_sast boolean DEFAULT true 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 | ||||
|  |  | |||
|  | @ -1769,7 +1769,7 @@ Parameters: | |||
| | --------- | ---- | -------- | ----------- | | ||||
| | `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`). | | ||||
| | `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. | | ||||
| | `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. | | ||||
|  |  | |||
|  | @ -19,7 +19,7 @@ info: | |||
|     name: CC BY-SA 4.0 | ||||
|     url: 'https://gitlab.com/gitlab-org/gitlab/-/blob/master/LICENSE' | ||||
| servers: | ||||
| - url: https://www.gitlab.com/api/ | ||||
| - url: https://www.gitlab.com/api/v4 | ||||
| security: | ||||
|   - ApiKeyAuth: [] | ||||
| tags: | ||||
|  | @ -176,7 +176,7 @@ tags: | |||
| - name: unleash_api | ||||
|   description: Operations related to Unleash API | ||||
| paths: | ||||
|   /api/v4/groups/{id}/badges/{badge_id}: | ||||
|   /groups/{id}/badges/{badge_id}: | ||||
|     get: | ||||
|       tags: | ||||
|       - badges | ||||
|  | @ -271,7 +271,7 @@ paths: | |||
|         204: | ||||
|           description: Removes a badge from the group. | ||||
|           content: {} | ||||
|   /api/v4/groups/{id}/badges: | ||||
|   /groups/{id}/badges: | ||||
|     get: | ||||
|       tags: | ||||
|       - badges | ||||
|  | @ -353,7 +353,7 @@ paths: | |||
|             application/json: | ||||
|               schema: | ||||
|                 $ref: '#/components/schemas/API_Entities_Badge' | ||||
|   /api/v4/groups/{id}/badges/render: | ||||
|   /groups/{id}/badges/render: | ||||
|     get: | ||||
|       tags: | ||||
|       - badges | ||||
|  | @ -387,7 +387,7 @@ paths: | |||
|             application/json: | ||||
|               schema: | ||||
|                 $ref: '#/components/schemas/API_Entities_BasicBadgeDetails' | ||||
|   /api/v4/groups/{id}/access_requests/{user_id}: | ||||
|   /groups/{id}/access_requests/{user_id}: | ||||
|     delete: | ||||
|       tags: | ||||
|       - access_requests | ||||
|  | @ -413,7 +413,7 @@ paths: | |||
|         204: | ||||
|           description: Denies an access request for the given user. | ||||
|           content: {} | ||||
|   /api/v4/groups/{id}/access_requests/{user_id}/approve: | ||||
|   /groups/{id}/access_requests/{user_id}/approve: | ||||
|     put: | ||||
|       tags: | ||||
|       - access_requests | ||||
|  | @ -461,7 +461,7 @@ paths: | |||
|                 state: active | ||||
|                 created_at: 2012-10-22T14:13:35Z | ||||
|                 access_level: 20 | ||||
|   /api/v4/groups/{id}/access_requests: | ||||
|   /groups/{id}/access_requests: | ||||
|     get: | ||||
|       tags: | ||||
|       - access_requests | ||||
|  | @ -526,7 +526,7 @@ paths: | |||
|                 state: active | ||||
|                 created_at: 2012-10-22T14:13:35Z | ||||
|                 access_level: 20 | ||||
|   /api/v4/projects/{id}/repository/merged_branches: | ||||
|   /projects/{id}/repository/merged_branches: | ||||
|     delete: | ||||
|       tags: | ||||
|       - branches | ||||
|  | @ -546,7 +546,7 @@ paths: | |||
|         404: | ||||
|           description: 404 Project Not Found | ||||
|           content: {} | ||||
|   /api/v4/projects/{id}/repository/branches/{branch}: | ||||
|   /projects/{id}/repository/branches/{branch}: | ||||
|     get: | ||||
|       tags: | ||||
|       - branches | ||||
|  | @ -625,7 +625,7 @@ paths: | |||
|         404: | ||||
|           description: Not Found | ||||
|           content: {} | ||||
|   /api/v4/projects/{id}/repository/branches: | ||||
|   /projects/{id}/repository/branches: | ||||
|     get: | ||||
|       tags: | ||||
|       - branches | ||||
|  | @ -722,7 +722,7 @@ paths: | |||
|         400: | ||||
|           description: Failed to create branch | ||||
|           content: {} | ||||
|   /api/v4/projects/{id}/repository/branches/{branch}/unprotect: | ||||
|   /projects/{id}/repository/branches/{branch}/unprotect: | ||||
|     put: | ||||
|       tags: | ||||
|       - branches | ||||
|  | @ -751,7 +751,7 @@ paths: | |||
|         404: | ||||
|           description: 404 Project Not Found | ||||
|           content: {} | ||||
|   /api/v4/projects/{id}/repository/branches/{branch}/protect: | ||||
|   /projects/{id}/repository/branches/{branch}/protect: | ||||
|     put: | ||||
|       tags: | ||||
|       - branches | ||||
|  | @ -791,7 +791,7 @@ paths: | |||
|         404: | ||||
|           description: 404 Branch Not Found | ||||
|           content: {} | ||||
|   /api/v4/projects/{id}/badges/{badge_id}: | ||||
|   /projects/{id}/badges/{badge_id}: | ||||
|     get: | ||||
|       tags: | ||||
|       - badges | ||||
|  | @ -886,7 +886,7 @@ paths: | |||
|         204: | ||||
|           description: Removes a badge from the project. | ||||
|           content: {} | ||||
|   /api/v4/projects/{id}/badges: | ||||
|   /projects/{id}/badges: | ||||
|     get: | ||||
|       tags: | ||||
|       - badges | ||||
|  | @ -969,7 +969,7 @@ paths: | |||
|             application/json: | ||||
|               schema: | ||||
|                 $ref: '#/components/schemas/API_Entities_Badge' | ||||
|   /api/v4/projects/{id}/badges/render: | ||||
|   /projects/{id}/badges/render: | ||||
|     get: | ||||
|       tags: | ||||
|       - badges | ||||
|  | @ -1003,7 +1003,7 @@ paths: | |||
|             application/json: | ||||
|               schema: | ||||
|                 $ref: '#/components/schemas/API_Entities_BasicBadgeDetails' | ||||
|   /api/v4/projects/{id}/access_requests/{user_id}: | ||||
|   /projects/{id}/access_requests/{user_id}: | ||||
|     delete: | ||||
|       tags: | ||||
|       - access_requests | ||||
|  | @ -1029,7 +1029,7 @@ paths: | |||
|         204: | ||||
|           description: Denies an access request for the given user. | ||||
|           content: {} | ||||
|   /api/v4/projects/{id}/access_requests/{user_id}/approve: | ||||
|   /projects/{id}/access_requests/{user_id}/approve: | ||||
|     put: | ||||
|       tags: | ||||
|       - access_requests | ||||
|  | @ -1077,7 +1077,7 @@ paths: | |||
|                 state: active | ||||
|                 created_at: 2012-10-22T14:13:35Z | ||||
|                 access_level: 20 | ||||
|   /api/v4/projects/{id}/access_requests: | ||||
|   /projects/{id}/access_requests: | ||||
|     get: | ||||
|       tags: | ||||
|       - access_requests | ||||
|  | @ -1142,7 +1142,7 @@ paths: | |||
|                 state: active | ||||
|                 created_at: 2012-10-22T14:13:35Z | ||||
|                 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: | ||||
|       tags: | ||||
|       - alert_management | ||||
|  | @ -1232,7 +1232,7 @@ paths: | |||
|         422: | ||||
|           description: Unprocessable entity | ||||
|           content: {} | ||||
|   /api/v4/projects/{id}/alert_management_alerts/{alert_iid}/metric_images: | ||||
|   /projects/{id}/alert_management_alerts/{alert_iid}/metric_images: | ||||
|     get: | ||||
|       tags: | ||||
|       - alert_management | ||||
|  | @ -1311,7 +1311,7 @@ paths: | |||
|         403: | ||||
|           description: Forbidden | ||||
|           content: {} | ||||
|   /api/v4/projects/{id}/alert_management_alerts/{alert_iid}/metric_images/authorize: | ||||
|   /projects/{id}/alert_management_alerts/{alert_iid}/metric_images/authorize: | ||||
|     post: | ||||
|       tags: | ||||
|       - alert_management | ||||
|  | @ -1338,7 +1338,7 @@ paths: | |||
|         403: | ||||
|           description: Forbidden | ||||
|           content: {} | ||||
|   /api/v4/admin/batched_background_migrations/{id}: | ||||
|   /admin/batched_background_migrations/{id}: | ||||
|     get: | ||||
|       tags: | ||||
|       - batched_background_migrations | ||||
|  | @ -1380,7 +1380,7 @@ paths: | |||
|         404: | ||||
|           description: 404 Not found | ||||
|           content: {} | ||||
|   /api/v4/admin/batched_background_migrations: | ||||
|   /admin/batched_background_migrations: | ||||
|     get: | ||||
|       tags: | ||||
|       - batched_background_migrations | ||||
|  | @ -1414,7 +1414,7 @@ paths: | |||
|         403: | ||||
|           description: 403 Forbidden | ||||
|           content: {} | ||||
|   /api/v4/admin/batched_background_migrations/{id}/resume: | ||||
|   /admin/batched_background_migrations/{id}/resume: | ||||
|     put: | ||||
|       tags: | ||||
|       - batched_background_migrations | ||||
|  | @ -1462,7 +1462,7 @@ paths: | |||
|         422: | ||||
|           description: You can resume only `paused` batched background migrations. | ||||
|           content: {} | ||||
|   /api/v4/admin/batched_background_migrations/{id}/pause: | ||||
|   /admin/batched_background_migrations/{id}/pause: | ||||
|     put: | ||||
|       tags: | ||||
|       - batched_background_migrations | ||||
|  | @ -1510,7 +1510,7 @@ paths: | |||
|         422: | ||||
|           description: You can pause only `active` batched background migrations. | ||||
|           content: {} | ||||
|   /api/v4/admin/ci/variables/{key}: | ||||
|   /admin/ci/variables/{key}: | ||||
|     get: | ||||
|       tags: | ||||
|       - ci_variables | ||||
|  | @ -1601,7 +1601,7 @@ paths: | |||
|         404: | ||||
|           description: Instance Variable Not Found | ||||
|           content: {} | ||||
|   /api/v4/admin/ci/variables: | ||||
|   /admin/ci/variables: | ||||
|     get: | ||||
|       tags: | ||||
|       - ci_variables | ||||
|  | @ -1675,7 +1675,7 @@ paths: | |||
|         400: | ||||
|           description: 400 Bad Request | ||||
|           content: {} | ||||
|   /api/v4/admin/databases/{database_name}/dictionary/tables/{table_name}: | ||||
|   /admin/databases/{database_name}/dictionary/tables/{table_name}: | ||||
|     get: | ||||
|       tags: | ||||
|       - admin | ||||
|  | @ -1713,7 +1713,7 @@ paths: | |||
|         404: | ||||
|           description: 404 Not found | ||||
|           content: {} | ||||
|   /api/v4/admin/clusters/{cluster_id}: | ||||
|   /admin/clusters/{cluster_id}: | ||||
|     get: | ||||
|       tags: | ||||
|       - clusters | ||||
|  | @ -1845,7 +1845,7 @@ paths: | |||
|         404: | ||||
|           description: Not found | ||||
|           content: {} | ||||
|   /api/v4/admin/clusters/add: | ||||
|   /admin/clusters/add: | ||||
|     post: | ||||
|       tags: | ||||
|       - clusters | ||||
|  | @ -1928,7 +1928,7 @@ paths: | |||
|         404: | ||||
|           description: Not found | ||||
|           content: {} | ||||
|   /api/v4/admin/clusters: | ||||
|   /admin/clusters: | ||||
|     get: | ||||
|       tags: | ||||
|       - clusters | ||||
|  | @ -1948,7 +1948,7 @@ paths: | |||
|         403: | ||||
|           description: Forbidden | ||||
|           content: {} | ||||
|   /api/v4/admin/migrations/{timestamp}/mark: | ||||
|   /admin/migrations/{timestamp}/mark: | ||||
|     post: | ||||
|       tags: | ||||
|       - migrations | ||||
|  | @ -1993,7 +1993,7 @@ paths: | |||
|         422: | ||||
|           description: You can mark only pending migrations | ||||
|           content: {} | ||||
|   /api/v4/applications/{id}: | ||||
|   /applications/{id}: | ||||
|     delete: | ||||
|       tags: | ||||
|       - applications | ||||
|  | @ -2012,7 +2012,7 @@ paths: | |||
|         204: | ||||
|           description: Delete an application | ||||
|           content: {} | ||||
|   /api/v4/applications: | ||||
|   /applications: | ||||
|     get: | ||||
|       tags: | ||||
|       - applications | ||||
|  | @ -2068,7 +2068,7 @@ paths: | |||
|             application/json: | ||||
|               schema: | ||||
|                 $ref: '#/components/schemas/API_Entities_ApplicationWithSecret' | ||||
|   /api/v4/avatar: | ||||
|   /avatar: | ||||
|     get: | ||||
|       tags: | ||||
|       - avatar | ||||
|  | @ -2094,7 +2094,7 @@ paths: | |||
|             application/json: | ||||
|               schema: | ||||
|                 $ref: '#/components/schemas/API_Entities_Avatar' | ||||
|   /api/v4/broadcast_messages/{id}: | ||||
|   /broadcast_messages/{id}: | ||||
|     get: | ||||
|       tags: | ||||
|       - broadcast_messages | ||||
|  | @ -2204,7 +2204,7 @@ paths: | |||
|             application/json: | ||||
|               schema: | ||||
|                 $ref: '#/components/schemas/API_Entities_BroadcastMessage' | ||||
|   /api/v4/broadcast_messages: | ||||
|   /broadcast_messages: | ||||
|     get: | ||||
|       tags: | ||||
|       - broadcast_messages | ||||
|  | @ -2295,7 +2295,7 @@ paths: | |||
|             application/json: | ||||
|               schema: | ||||
|                 $ref: '#/components/schemas/API_Entities_BroadcastMessage' | ||||
|   /api/v4/bulk_imports/{import_id}/entities/{entity_id}: | ||||
|   /bulk_imports/{import_id}/entities/{entity_id}: | ||||
|     get: | ||||
|       tags: | ||||
|       - bulk_imports | ||||
|  | @ -2333,7 +2333,7 @@ paths: | |||
|         503: | ||||
|           description: Service unavailable | ||||
|           content: {} | ||||
|   /api/v4/bulk_imports/{import_id}/entities: | ||||
|   /bulk_imports/{import_id}/entities: | ||||
|     get: | ||||
|       tags: | ||||
|       - bulk_imports | ||||
|  | @ -2391,7 +2391,7 @@ paths: | |||
|         503: | ||||
|           description: Service unavailable | ||||
|           content: {} | ||||
|   /api/v4/bulk_imports/{import_id}: | ||||
|   /bulk_imports/{import_id}: | ||||
|     get: | ||||
|       tags: | ||||
|       - bulk_imports | ||||
|  | @ -2422,7 +2422,7 @@ paths: | |||
|         503: | ||||
|           description: Service unavailable | ||||
|           content: {} | ||||
|   /api/v4/bulk_imports/entities: | ||||
|   /bulk_imports/entities: | ||||
|     get: | ||||
|       tags: | ||||
|       - bulk_imports | ||||
|  | @ -2483,7 +2483,7 @@ paths: | |||
|         503: | ||||
|           description: Service unavailable | ||||
|           content: {} | ||||
|   /api/v4/bulk_imports: | ||||
|   /bulk_imports: | ||||
|     get: | ||||
|       tags: | ||||
|       - bulk_imports | ||||
|  | @ -2624,7 +2624,7 @@ paths: | |||
|         503: | ||||
|           description: Service unavailable | ||||
|           content: {} | ||||
|   /api/v4/application/appearance: | ||||
|   /application/appearance: | ||||
|     get: | ||||
|       tags: | ||||
|       - application | ||||
|  | @ -2707,7 +2707,7 @@ paths: | |||
|             application/json: | ||||
|               schema: | ||||
|                 $ref: '#/components/schemas/API_Entities_Appearance' | ||||
|   /api/v4/application/plan_limits: | ||||
|   /application/plan_limits: | ||||
|     get: | ||||
|       tags: | ||||
|       - plan_limits | ||||
|  | @ -2869,7 +2869,7 @@ paths: | |||
|         403: | ||||
|           description: Forbidden | ||||
|           content: {} | ||||
|   /api/v4/metadata: | ||||
|   /metadata: | ||||
|     get: | ||||
|       tags: | ||||
|       - metadata | ||||
|  | @ -2886,7 +2886,7 @@ paths: | |||
|         401: | ||||
|           description: Unauthorized | ||||
|           content: {} | ||||
|   /api/v4/version: | ||||
|   /version: | ||||
|     get: | ||||
|       tags: | ||||
|       - metadata | ||||
|  | @ -2904,7 +2904,7 @@ paths: | |||
|         401: | ||||
|           description: Unauthorized | ||||
|           content: {} | ||||
|   /api/v4/projects/{id}/jobs: | ||||
|   /projects/{id}/jobs: | ||||
|     get: | ||||
|       tags: | ||||
|       - jobs | ||||
|  | @ -2934,7 +2934,7 @@ paths: | |||
|                 type: array | ||||
|                 items: | ||||
|                   $ref: '#/components/schemas/API_Entities_Job' | ||||
|   /api/v4/projects/{id}/jobs/{job_id}: | ||||
|   /projects/{id}/jobs/{job_id}: | ||||
|     get: | ||||
|       tags: | ||||
|       - jobs | ||||
|  | @ -2960,7 +2960,7 @@ paths: | |||
|             application/json: | ||||
|               schema: | ||||
|                 $ref: '#/components/schemas/API_Entities_Job' | ||||
|   /api/v4/projects/{id}/jobs/{job_id}/play: | ||||
|   /projects/{id}/jobs/{job_id}/play: | ||||
|     post: | ||||
|       tags: | ||||
|       - 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.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 |           | 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 top-level group settings.                                                                                                                                                                                                                                                               | | ||||
| | 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 --> | ||||
| 
 | ||||
|  | @ -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 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 |           | 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 | ||||
| **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: | ||||
| 
 | ||||
| - 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 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 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. On the left sidebar, select **Usage Quotas**. | ||||
| 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. | ||||
| 
 | ||||
| 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 | ||||
| [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               | `medium`               | 2           | | ||||
|  | @ -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. | ||||
| 
 | ||||
| ### 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 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 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 | ||||
| [`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 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) | ||||
| 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. 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. 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. 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. 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): | ||||
|  |  | |||
|  | @ -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 `[]`  | | ||||
| | `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 | ||||
| 
 | ||||
|  |  | |||
|  | @ -60,12 +60,12 @@ For other 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: | ||||
| **Tier:** Premium, Ultimate | ||||
| **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. | ||||
| 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, | ||||
|  |  | |||
|  | @ -413,7 +413,7 @@ The following package managers use lockfiles that GitLab analyzers are capable o | |||
|     </tr> | ||||
|     <tr> | ||||
|       <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> | ||||
|         <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>, | ||||
|  | @ -453,10 +453,10 @@ The following package managers use lockfiles that GitLab analyzers are capable o | |||
|   <li> | ||||
|     <a id="notes-regarding-parsing-lockfiles-4"></a> | ||||
|     <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> | ||||
|       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> | ||||
|     <ul> | ||||
|       <li> | ||||
|  |  | |||
|  | @ -258,6 +258,74 @@ Note the following: | |||
|   - 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.   | ||||
| 
 | ||||
| ## 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 | ||||
| 
 | ||||
| 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`. | ||||
| 
 | ||||
| ### 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           | | ||||
| | **[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**  | | ||||
| | 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 | ||||
| [protected paths](#protected-paths-throttle) and | ||||
|  |  | |||
|  | @ -40,6 +40,8 @@ To configure the bot in Telegram: | |||
| 
 | ||||
| ## 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: | ||||
| 
 | ||||
| 1. To enable the integration: | ||||
|  |  | |||
|  | @ -48,7 +48,7 @@ module Gitlab | |||
|             'media_src' => "'self' data: blob: http: https:", | ||||
|             'script_src' => ContentSecurityPolicy::Directives.script_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'", | ||||
|             'report_uri' => nil | ||||
|           } | ||||
|  |  | |||
|  | @ -22,6 +22,10 @@ module Gitlab | |||
|       def self.style_src | ||||
|         "'self' 'unsafe-inline'" | ||||
|       end | ||||
| 
 | ||||
|       def self.worker_src | ||||
|         "'self' #{Gitlab::Utils.append_path(Gitlab.config.gitlab.url, 'assets/')} blob: data:" | ||||
|       end | ||||
|     end | ||||
|   end | ||||
| end | ||||
|  |  | |||
|  | @ -108,6 +108,12 @@ RSpec.describe Gitlab::ContentSecurityPolicy::ConfigLoader, feature_category: :s | |||
|       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 | ||||
|       let(:webpack_dev_server_host) { 'webpack-dev-server.com' } | ||||
|       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(style_src).to eq(::Gitlab::ContentSecurityPolicy::Directives.style_src) | ||||
|           expect(font_src).to eq("'self'") | ||||
|           expect(worker_src).to eq("http://localhost/assets/ blob: data:") | ||||
|           expect(worker_src).to eq(::Gitlab::ContentSecurityPolicy::Directives.worker_src) | ||||
|           expect(frame_src).to eq(::Gitlab::ContentSecurityPolicy::Directives.frame_src) | ||||
|         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 | ||||
| 
 | ||||
|   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 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue