diff --git a/.gitlab/ci/global.gitlab-ci.yml b/.gitlab/ci/global.gitlab-ci.yml index 511447188d1..b37760fdef9 100644 --- a/.gitlab/ci/global.gitlab-ci.yml +++ b/.gitlab/ci/global.gitlab-ci.yml @@ -10,7 +10,6 @@ - unknown_failure exit_codes: - 111 # low free disk space https://gitlab.com/gitlab-org/gitlab/-/issues/498142 - - 112 # Known flaky tests .default-utils-before_script: before_script: diff --git a/.rubocop_todo/layout/line_length.yml b/.rubocop_todo/layout/line_length.yml index b58bc74e27a..56ed72287bc 100644 --- a/.rubocop_todo/layout/line_length.yml +++ b/.rubocop_todo/layout/line_length.yml @@ -18,21 +18,6 @@ Layout/LineLength: - 'app/controllers/concerns/membership_actions.rb' - 'app/controllers/concerns/notes_actions.rb' - 'app/controllers/groups/milestones_controller.rb' - - 'app/controllers/groups_controller.rb' - - 'app/controllers/import/base_controller.rb' - - 'app/controllers/import/bitbucket_controller.rb' - - 'app/controllers/import/bitbucket_server_controller.rb' - - 'app/controllers/import/bulk_imports_controller.rb' - - 'app/controllers/import/fogbugz_controller.rb' - - 'app/controllers/import/gitea_controller.rb' - - 'app/controllers/import/gitlab_groups_controller.rb' - - 'app/controllers/import/gitlab_projects_controller.rb' - - 'app/controllers/invites_controller.rb' - - 'app/controllers/jira_connect/events_controller.rb' - - 'app/controllers/jira_connect/subscriptions_controller.rb' - - 'app/controllers/jwt_controller.rb' - - 'app/controllers/omniauth_callbacks_controller.rb' - - 'app/controllers/profiles/chat_names_controller.rb' - 'app/controllers/projects/issues_controller.rb' - 'app/controllers/projects/jobs_controller.rb' - 'app/controllers/projects/labels_controller.rb' diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION index 43cd1219129..6775dda15c9 100644 --- a/GITALY_SERVER_VERSION +++ b/GITALY_SERVER_VERSION @@ -1 +1 @@ -b1891e7ed098a0628dda95037f63d7f145b65adc +8772e7bbd79d8fd2ba9137eef510b22fa2f8382f diff --git a/Gemfile b/Gemfile index a943800f584..c52697bddee 100644 --- a/Gemfile +++ b/Gemfile @@ -278,7 +278,7 @@ gem 'rack', '~> 2.2.9' # rubocop:todo Gemfile/MissingFeatureCategory gem 'rack-timeout', '~> 0.7.0', require: 'rack/timeout/base' # rubocop:todo Gemfile/MissingFeatureCategory group :puma do - gem 'puma', '= 6.4.3', require: false, feature_category: :shared + gem 'puma', '= 6.5.0', require: false, feature_category: :shared gem 'sd_notify', '~> 0.1.0', require: false # rubocop:todo Gemfile/MissingFeatureCategory end diff --git a/Gemfile.checksum b/Gemfile.checksum index fe7a680ebf5..35d20f3741d 100644 --- a/Gemfile.checksum +++ b/Gemfile.checksum @@ -526,8 +526,8 @@ {"name":"pry-rails","version":"0.3.9","platform":"ruby","checksum":"468662575abb6b67f4a9831219f99290d5eae7bf186e64dd810d0a3e4a8cc4b1"}, {"name":"pry-shell","version":"0.6.4","platform":"ruby","checksum":"ad024882d29912b071a7de65ebea538b242d2dc1498c60c7c2352ef94769f208"}, {"name":"public_suffix","version":"6.0.1","platform":"ruby","checksum":"61d44e1cab5cbbbe5b31068481cf16976dd0dc1b6b07bd95617ef8c5e3e00c6f"}, -{"name":"puma","version":"6.4.3","platform":"java","checksum":"373fcfacacaafd0f5a24db18cb99b3f2decb5c5316470169852559aa80adc8ab"}, -{"name":"puma","version":"6.4.3","platform":"ruby","checksum":"24a4645c006811d83f2480057d1f54a96e7627b6b90e1c99b260b9dc630eb43e"}, +{"name":"puma","version":"6.5.0","platform":"java","checksum":"a58eea585d291aa33796add9884208bc1591da5d8e61886f8ac74d080b298c40"}, +{"name":"puma","version":"6.5.0","platform":"ruby","checksum":"94d1b75cab7f356d52e4f1b17b9040a090889b341dbeee6ee3703f441dc189f2"}, {"name":"pyu-ruby-sasl","version":"0.0.3.3","platform":"ruby","checksum":"5683a6bc5738db5a1bf5ceddeaf545405fb241b4184dd4f2587e679a7e9497e5"}, {"name":"raabro","version":"1.4.0","platform":"ruby","checksum":"d4fa9ff5172391edb92b242eed8be802d1934b1464061ae5e70d80962c5da882"}, {"name":"racc","version":"1.8.1","platform":"java","checksum":"54f2e6d1e1b91c154013277d986f52a90e5ececbe91465d29172e49342732b98"}, diff --git a/Gemfile.lock b/Gemfile.lock index c6ac026d429..235309d76a9 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1458,7 +1458,7 @@ GEM tty-markdown tty-prompt public_suffix (6.0.1) - puma (6.4.3) + puma (6.5.0) nio4r (~> 2.0) pyu-ruby-sasl (0.0.3.3) raabro (1.4.0) @@ -2235,7 +2235,7 @@ DEPENDENCIES pry-byebug pry-rails (~> 0.3.9) pry-shell (~> 0.6.4) - puma (= 6.4.3) + puma (= 6.5.0) rack (~> 2.2.9) rack-attack (~> 6.7.0) rack-cors (~> 2.0.1) diff --git a/Gemfile.next.checksum b/Gemfile.next.checksum index 965d1c72df2..eb4dd0acdbf 100644 --- a/Gemfile.next.checksum +++ b/Gemfile.next.checksum @@ -533,8 +533,8 @@ {"name":"psych","version":"5.2.0","platform":"java","checksum":"da3a7995e652365faa210d7658a291141c9a15bf05a4d9a48a13856b04f36960"}, {"name":"psych","version":"5.2.0","platform":"ruby","checksum":"6603fe756bcaf14daa25bc17625f36c90931dcf70452ac1e8da19760dc310573"}, {"name":"public_suffix","version":"6.0.1","platform":"ruby","checksum":"61d44e1cab5cbbbe5b31068481cf16976dd0dc1b6b07bd95617ef8c5e3e00c6f"}, -{"name":"puma","version":"6.4.3","platform":"java","checksum":"373fcfacacaafd0f5a24db18cb99b3f2decb5c5316470169852559aa80adc8ab"}, -{"name":"puma","version":"6.4.3","platform":"ruby","checksum":"24a4645c006811d83f2480057d1f54a96e7627b6b90e1c99b260b9dc630eb43e"}, +{"name":"puma","version":"6.5.0","platform":"java","checksum":"a58eea585d291aa33796add9884208bc1591da5d8e61886f8ac74d080b298c40"}, +{"name":"puma","version":"6.5.0","platform":"ruby","checksum":"94d1b75cab7f356d52e4f1b17b9040a090889b341dbeee6ee3703f441dc189f2"}, {"name":"pyu-ruby-sasl","version":"0.0.3.3","platform":"ruby","checksum":"5683a6bc5738db5a1bf5ceddeaf545405fb241b4184dd4f2587e679a7e9497e5"}, {"name":"raabro","version":"1.4.0","platform":"ruby","checksum":"d4fa9ff5172391edb92b242eed8be802d1934b1464061ae5e70d80962c5da882"}, {"name":"racc","version":"1.8.1","platform":"java","checksum":"54f2e6d1e1b91c154013277d986f52a90e5ececbe91465d29172e49342732b98"}, diff --git a/Gemfile.next.lock b/Gemfile.next.lock index a21514e8547..0f6f23da253 100644 --- a/Gemfile.next.lock +++ b/Gemfile.next.lock @@ -1475,7 +1475,7 @@ GEM psych (5.2.0) stringio public_suffix (6.0.1) - puma (6.4.3) + puma (6.5.0) nio4r (~> 2.0) pyu-ruby-sasl (0.0.3.3) raabro (1.4.0) @@ -2262,7 +2262,7 @@ DEPENDENCIES pry-byebug pry-rails (~> 0.3.9) pry-shell (~> 0.6.4) - puma (= 6.4.3) + puma (= 6.5.0) rack (~> 2.2.9) rack-attack (~> 6.7.0) rack-cors (~> 2.0.1) diff --git a/app/assets/javascripts/notes/i18n.js b/app/assets/javascripts/notes/i18n.js index 1cc1311faa5..ba7322b7530 100644 --- a/app/assets/javascripts/notes/i18n.js +++ b/app/assets/javascripts/notes/i18n.js @@ -17,7 +17,7 @@ export const COMMENT_FORM = { bodyPlaceholderInternal: __('Write an internal note or drag your files here…'), internal: s__('Notes|Make this an internal note'), internalVisibility: s__( - 'Notes|Internal notes are only visible to members with the role of Reporter or higher', + 'Notes|Internal notes are only visible to members with the role of Planner or higher', ), discussionThatNeedsResolution: __( 'Discuss a specific suggestion or question that needs to be resolved.', diff --git a/app/controllers/groups_controller.rb b/app/controllers/groups_controller.rb index b056b94eb19..1d3ead25fee 100644 --- a/app/controllers/groups_controller.rb +++ b/app/controllers/groups_controller.rb @@ -94,9 +94,15 @@ class GroupsController < Groups::ApplicationController successful_creation_hooks notice = if @group.chat_team.present? - format(_("Group %{group_name} and its Mattermost team were successfully created."), group_name: @group.name) + format( + _("Group %{group_name} and its Mattermost team were successfully created."), + group_name: @group.name + ) else - format(_("Group %{group_name} was successfully created."), group_name: @group.name) + format( + _("Group %{group_name} was successfully created."), + group_name: @group.name + ) end redirect_to @group, notice: notice @@ -207,7 +213,8 @@ class GroupsController < Groups::ApplicationController ) if export_service.async_execute - redirect_to edit_group_path(@group), notice: _('Group export started. A download link will be sent by email and made available on this page.') + redirect_to edit_group_path(@group), + notice: _('Group export started. A download link will be sent by email and made available on this page.') else redirect_to edit_group_path(@group), alert: _('Group export could not be started.') end @@ -220,7 +227,9 @@ class GroupsController < Groups::ApplicationController send_upload(export_file, attachment: export_file.filename) else redirect_to edit_group_path(@group), - alert: _('The file containing the export is not available yet; it may still be transferring. Please try again later.') + alert: _( + 'The file containing the export is not available yet; it may still be transferring. Please try again later.' + ) end else redirect_to edit_group_path(@group), diff --git a/app/controllers/import/base_controller.rb b/app/controllers/import/base_controller.rb index 6880d59bf97..a52ed784c2b 100644 --- a/app/controllers/import/base_controller.rb +++ b/app/controllers/import/base_controller.rb @@ -3,7 +3,13 @@ class Import::BaseController < ApplicationController include ActionView::Helpers::SanitizeHelper - before_action -> { check_rate_limit!(:project_import, scope: [current_user, :project_import], redirect_back: true) }, only: [:create] + before_action -> { + check_rate_limit!( + :project_import, + scope: [current_user, :project_import], + redirect_back: true + ) + }, only: [:create] feature_category :importers urgency :low @@ -65,11 +71,23 @@ class Import::BaseController < ApplicationController end def serialized_provider_repos - Import::ProviderRepoSerializer.new(current_user: current_user).represent(importable_repos, provider: provider_name, provider_url: provider_url, **extra_representation_opts) + Import::ProviderRepoSerializer.new(current_user: current_user) + .represent( + importable_repos, + provider: provider_name, + provider_url: provider_url, + **extra_representation_opts + ) end def serialized_incompatible_repos - Import::ProviderRepoSerializer.new(current_user: current_user).represent(incompatible_repos, provider: provider_name, provider_url: provider_url, **extra_representation_opts) + Import::ProviderRepoSerializer.new(current_user: current_user) + .represent( + incompatible_repos, + provider: provider_name, + provider_url: provider_url, + **extra_representation_opts + ) end def serialized_imported_projects @@ -92,7 +110,11 @@ class Import::BaseController < ApplicationController return current_user.namespace if names == owner - group = Groups::NestedCreateService.new(current_user, organization_id: Current.organization_id, group_path: names).execute + group = Groups::NestedCreateService.new( + current_user, + organization_id: Current.organization_id, + group_path: names + ).execute group.errors.any? ? current_user.namespace : group rescue StandardError => e diff --git a/app/controllers/import/bitbucket_controller.rb b/app/controllers/import/bitbucket_controller.rb index c44417102a7..cf8b8f8c926 100644 --- a/app/controllers/import/bitbucket_controller.rb +++ b/app/controllers/import/bitbucket_controller.rb @@ -18,7 +18,10 @@ class Import::BitbucketController < Import::BaseController if auth_state.blank? || !ActiveSupport::SecurityUtils.secure_compare(auth_state, params[:state]) go_to_bitbucket_for_permissions else - response = oauth_client.auth_code.get_token(params[:code], redirect_uri: users_import_bitbucket_callback_url(namespace_id: params[:namespace_id])) + response = oauth_client.auth_code.get_token( + params[:code], + redirect_uri: users_import_bitbucket_callback_url(namespace_id: params[:namespace_id]) + ) session[:bitbucket_token] = response.token session[:bitbucket_expires_at] = response.expires_at @@ -62,7 +65,13 @@ class Import::BitbucketController < Import::BaseController # Bitbucket::Connection class refreshes it. session[:bitbucket_token] = bitbucket_client.connection.token - project = Gitlab::BitbucketImport::ProjectCreator.new(repo, project_name, target_namespace, current_user, credentials).execute + project = Gitlab::BitbucketImport::ProjectCreator.new( + repo, + project_name, + target_namespace, + current_user, + credentials + ).execute if project.persisted? render json: ProjectSerializer.new.represent(project, serializer: :import) @@ -70,7 +79,8 @@ class Import::BitbucketController < Import::BaseController render json: { errors: project_save_error(project) }, status: :unprocessable_entity end else - render json: { errors: s_('BitbucketImport|You are not allowed to import projects in this namespace.') }, status: :unprocessable_entity + render json: { errors: s_('BitbucketImport|You are not allowed to import projects in this namespace.') }, + status: :unprocessable_entity end end @@ -143,7 +153,10 @@ class Import::BitbucketController < Import::BaseController def go_to_bitbucket_for_permissions state = SecureRandom.base64(64) session[:bitbucket_auth_state] = state - redirect_to oauth_client.auth_code.authorize_url(redirect_uri: users_import_bitbucket_callback_url(namespace_id: params[:namespace_id]), state: state) + redirect_to oauth_client.auth_code.authorize_url( + redirect_uri: users_import_bitbucket_callback_url(namespace_id: params[:namespace_id]), + state: state + ) end def bitbucket_unauthorized(exception) diff --git a/app/controllers/import/bitbucket_server_controller.rb b/app/controllers/import/bitbucket_server_controller.rb index 8790f154257..872520f0e1e 100644 --- a/app/controllers/import/bitbucket_server_controller.rb +++ b/app/controllers/import/bitbucket_server_controller.rb @@ -4,6 +4,7 @@ class Import::BitbucketServerController < Import::BaseController extend ::Gitlab::Utils::Override include ActionView::Helpers::SanitizeHelper + include SafeFormatHelper before_action :verify_bitbucket_server_import_enabled before_action :bitbucket_auth, except: [:new, :configure] @@ -15,7 +16,8 @@ class Import::BitbucketServerController < Import::BaseController # As a basic sanity check to prevent URL injection, restrict project # repository input and repository slugs to allowed characters. For Bitbucket: # - # Project keys must start with a letter and may only consist of ASCII letters, numbers and underscores (A-Z, a-z, 0-9, _). + # Project keys must start with a letter and may only consist of ASCII letters, + # numbers and underscores (A-Z, a-z, 0-9, _). # # Repository names are limited to 128 characters. They must start with a # letter or number and may contain spaces, hyphens, underscores, and periods. @@ -31,10 +33,19 @@ class Import::BitbucketServerController < Import::BaseController repo = client.repo(@project_key, @repo_slug) unless repo - return render json: { errors: _("Project %{project_repo} could not be found") % { project_repo: "#{@project_key}/#{@repo_slug}" } }, status: :unprocessable_entity + return render json: { + errors: safe_format( + s_("Project %{project_repo} could not be found"), + project_repo: "#{@project_key}/#{@repo_slug}" + ) + }, status: :unprocessable_entity end - result = Import::BitbucketServerService.new(client, current_user, params.merge({ organization_id: Current.organization_id })).execute(credentials) + result = Import::BitbucketServerService.new( + client, + current_user, + params.merge({ organization_id: Current.organization_id }) + ).execute(credentials) if result[:status] == :success render json: ProjectSerializer.new.represent(result[:project], serializer: :import) @@ -87,7 +98,11 @@ class Import::BitbucketServerController < Import::BaseController end def bitbucket_repos - @bitbucket_repos ||= client.repos(page_offset: page_offset, limit: limit_per_page, filter: sanitized_filter_param).to_a + @bitbucket_repos ||= client.repos( + page_offset: page_offset, + limit: limit_per_page, + filter: sanitized_filter_param + ).to_a end def normalize_import_params diff --git a/app/controllers/import/bulk_imports_controller.rb b/app/controllers/import/bulk_imports_controller.rb index 2137c208aea..9bdf9bb020e 100644 --- a/app/controllers/import/bulk_imports_controller.rb +++ b/app/controllers/import/bulk_imports_controller.rb @@ -69,7 +69,9 @@ class Import::BulkImportsController < ApplicationController ::BulkImports::CreateService.new(current_user, entry, credentials).execute end - render json: responses.map { |response| { success: response.success?, id: response.payload[:id], message: response.message } } + render json: responses.map { |response| + { success: response.success?, id: response.payload[:id], message: response.message } + } end def realtime_changes @@ -177,7 +179,8 @@ class Import::BulkImportsController < ApplicationController rescue Gitlab::HTTP_V2::UrlBlocker::BlockedUrlError => e clear_session_data - redirect_to new_group_path(anchor: 'import-group-pane'), alert: _('Specified URL cannot be used: "%{reason}"') % { reason: e.message } + redirect_to new_group_path(anchor: 'import-group-pane'), + alert: _('Specified URL cannot be used: "%{reason}"') % { reason: e.message } end def allow_local_requests? diff --git a/app/controllers/import/fogbugz_controller.rb b/app/controllers/import/fogbugz_controller.rb index 7f2ae1a1163..ba923837ebb 100644 --- a/app/controllers/import/fogbugz_controller.rb +++ b/app/controllers/import/fogbugz_controller.rb @@ -18,7 +18,8 @@ class Import::FogbugzController < Import::BaseController res = Gitlab::FogbugzImport::Client.new(import_params.to_h.symbolize_keys) rescue StandardError # If the URI is invalid various errors can occur - return redirect_to new_import_fogbugz_path(namespace_id: params[:namespace_id]), alert: _('Could not connect to FogBugz, check your URL') + return redirect_to new_import_fogbugz_path(namespace_id: params[:namespace_id]), + alert: _('Could not connect to FogBugz, check your URL') end session[:fogbugz_token] = res.get_token.to_s session[:fogbugz_uri] = params[:uri] diff --git a/app/controllers/import/gitea_controller.rb b/app/controllers/import/gitea_controller.rb index 42270133042..4047332ddef 100644 --- a/app/controllers/import/gitea_controller.rb +++ b/app/controllers/import/gitea_controller.rb @@ -86,7 +86,11 @@ class Import::GiteaController < Import::GithubController def client_options verified_url, provider_hostname = verify_blocked_uri - { host: verified_url.scheme == 'https' ? provider_url : verified_url.to_s, api_version: 'v1', hostname: provider_hostname } + { + host: verified_url.scheme == 'https' ? provider_url : verified_url.to_s, + api_version: 'v1', + hostname: provider_hostname + } end def verify_blocked_uri diff --git a/app/controllers/import/gitlab_groups_controller.rb b/app/controllers/import/gitlab_groups_controller.rb index 2ac67e9e56d..92127510f02 100644 --- a/app/controllers/import/gitlab_groups_controller.rb +++ b/app/controllers/import/gitlab_groups_controller.rb @@ -10,7 +10,8 @@ class Import::GitlabGroupsController < ApplicationController def create unless file_is_valid?(group_params[:file]) - return redirect_to new_group_path(anchor: 'import-group-pane'), alert: s_('GroupImport|Unable to process group import file') + return redirect_to new_group_path(anchor: 'import-group-pane'), + alert: s_('GroupImport|Unable to process group import file') end group_data = group_params @@ -36,7 +37,9 @@ class Import::GitlabGroupsController < ApplicationController end else redirect_to new_group_path(anchor: 'import-group-pane'), - alert: s_("GroupImport|Group could not be imported: %{errors}") % { errors: group.errors.full_messages.to_sentence } + alert: s_("GroupImport|Group could not be imported: %{errors}") % { + errors: group.errors.full_messages.to_sentence + } end end diff --git a/app/controllers/import/gitlab_projects_controller.rb b/app/controllers/import/gitlab_projects_controller.rb index d1b182a57d8..0477bc25941 100644 --- a/app/controllers/import/gitlab_projects_controller.rb +++ b/app/controllers/import/gitlab_projects_controller.rb @@ -15,7 +15,11 @@ class Import::GitlabProjectsController < Import::BaseController def create unless file_is_valid?(project_params[:file]) - return redirect_back_or_default(options: { alert: _("You need to upload a GitLab project export archive (ending in .gz).") }) + return redirect_back_or_default( + options: { + alert: _("You need to upload a GitLab project export archive (ending in .gz).") + } + ) end @project = ::Projects::GitlabProjectsImportService.new(current_user, project_params).execute @@ -26,7 +30,11 @@ class Import::GitlabProjectsController < Import::BaseController notice: _("Project '%{project_name}' is being imported.") % { project_name: @project.name } ) else - redirect_back_or_default(options: { alert: "Project could not be imported: #{@project.errors.full_messages.join(', ')}" }) + redirect_back_or_default( + options: { + alert: "Project could not be imported: #{@project.errors.full_messages.join(', ')}" + } + ) end end diff --git a/app/controllers/invites_controller.rb b/app/controllers/invites_controller.rb index 16cd35c3643..5d9e35c4624 100644 --- a/app/controllers/invites_controller.rb +++ b/app/controllers/invites_controller.rb @@ -84,7 +84,8 @@ class InvitesController < ApplicationController if user_sign_up? set_session_invite_params - redirect_to new_user_registration_path(invite_email: member.invite_email), notice: _("To accept this invitation, create an account or sign in.") + redirect_to new_user_registration_path(invite_email: member.invite_email), + notice: _("To accept this invitation, create an account or sign in.") else redirect_to new_user_session_path(sign_in_redirect_params), notice: sign_in_notice end diff --git a/app/controllers/jira_connect/events_controller.rb b/app/controllers/jira_connect/events_controller.rb index 20494315eaf..daad2f5e2ab 100644 --- a/app/controllers/jira_connect/events_controller.rb +++ b/app/controllers/jira_connect/events_controller.rb @@ -17,7 +17,11 @@ class JiraConnect::EventsController < JiraConnect::ApplicationController end def uninstalled - if JiraConnectInstallations::DestroyService.execute(current_jira_installation, jira_connect_base_path, jira_connect_events_uninstalled_path) + if JiraConnectInstallations::DestroyService.execute( + current_jira_installation, + jira_connect_base_path, + jira_connect_events_uninstalled_path + ) head :ok else head :unprocessable_entity @@ -66,7 +70,11 @@ class JiraConnect::EventsController < JiraConnect::ApplicationController end def calculate_audiences - audiences = [Gitlab.config.jira_connect.enforce_jira_base_url_https ? jira_connect_base_url(protocol: 'https') : jira_connect_base_url] + audiences = if Gitlab.config.jira_connect.enforce_jira_base_url_https + [jira_connect_base_url(protocol: 'https')] + else + [jira_connect_base_url] + end if (additional_url = Gitlab::CurrentSettings.jira_connect_additional_audience_url).present? audiences << Gitlab::Utils.append_path(additional_url, "-/jira_connect") diff --git a/app/controllers/jira_connect/subscriptions_controller.rb b/app/controllers/jira_connect/subscriptions_controller.rb index 6885e5560a5..989794438c8 100644 --- a/app/controllers/jira_connect/subscriptions_controller.rb +++ b/app/controllers/jira_connect/subscriptions_controller.rb @@ -65,7 +65,12 @@ class JiraConnect::SubscriptionsController < JiraConnect::ApplicationController end def create_service - JiraConnectSubscriptions::CreateService.new(current_jira_installation, current_user, namespace_path: params['namespace_path'], jira_user: jira_user) + JiraConnectSubscriptions::CreateService.new( + current_jira_installation, + current_user, + namespace_path: params['namespace_path'], + jira_user: jira_user + ) end def destroy_service diff --git a/app/controllers/jwt_controller.rb b/app/controllers/jwt_controller.rb index f3af8d9ef19..c8ccdfc3136 100644 --- a/app/controllers/jwt_controller.rb +++ b/app/controllers/jwt_controller.rb @@ -34,7 +34,12 @@ class JwtController < ApplicationController private def authenticate_project_or_user - @authentication_result = Gitlab::Auth::Result.new(nil, nil, :none, Gitlab::Auth.read_only_authentication_abilities) + @authentication_result = Gitlab::Auth::Result.new( + nil, + nil, + :none, + Gitlab::Auth.read_only_authentication_abilities + ) authenticate_with_http_basic do |login, password| @authentication_result = Gitlab::Auth.find_for_git_client(login, password, project: nil, request: request) @@ -70,10 +75,15 @@ class JwtController < ApplicationController ) render( - json: { errors: [{ - code: 'UNAUTHORIZED', - message: format(_("HTTP Basic: Access denied. If a password was provided for Git authentication, the password was incorrect or you're required to use a token instead of a password. If a token was provided, it was either incorrect, expired, or improperly scoped. See %{help_page_url}"), help_page_url: help_page) - }] }, + json: { + errors: [{ + code: 'UNAUTHORIZED', + message: format(_("HTTP Basic: Access denied. If a password was provided for Git authentication, the " \ + "password was incorrect or you're required to use a token instead of a password. If a " \ + "token was provided, it was either incorrect, expired, or improperly scoped. See " \ + "%{help_page_url}"), help_page_url: help_page) + }] + }, status: :unauthorized ) end diff --git a/app/controllers/omniauth_callbacks_controller.rb b/app/controllers/omniauth_callbacks_controller.rb index 551134c9d5c..285c20237cf 100644 --- a/app/controllers/omniauth_callbacks_controller.rb +++ b/app/controllers/omniauth_callbacks_controller.rb @@ -182,7 +182,8 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController end def redirect_identity_link_failed(error_message) - redirect_to profile_account_path, notice: _("Authentication failed: %{error_message}") % { error_message: error_message } + redirect_to profile_account_path, + notice: _("Authentication failed: %{error_message}") % { error_message: error_message } end def redirect_identity_linked @@ -234,7 +235,8 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController else if @user.deactivated? @user.activate - flash[:notice] = _('Welcome back! Your account had been deactivated due to inactivity but is now reactivated.') + flash[:notice] = + _('Welcome back! Your account had been deactivated due to inactivity but is now reactivated.') end # session variable for storing bypass two-factor request from IDP @@ -262,12 +264,28 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController redirect_path = new_user_session_path label = Gitlab::Auth::OAuth::Provider.label_for(oauth['provider']) simple_url = Settings.gitlab.url.sub(%r{^https?://(www\.)?}i, '') - message = [_("Signing in using your %{label} account without a pre-existing account in %{simple_url} is not allowed.") % { label: label, simple_url: simple_url }] + message = [ + _('Signing in using your %{label} account without a pre-existing ' \ + 'account in %{simple_url} is not allowed.') % { + label: label, simple_url: simple_url + } + ] if Gitlab::CurrentSettings.allow_signup? redirect_path = new_user_registration_path - doc_pair = tag_pair(view_context.link_to('', help_page_path('user/profile/index.md', anchor: 'sign-in-services')), :doc_start, :doc_end) - message << safe_format(_("Create an account in %{simple_url} first, and then %{doc_start}connect it to your %{label} account%{doc_end}."), doc_pair, label: label, simple_url: simple_url) + doc_pair = tag_pair(view_context.link_to( + '', + help_page_path('user/profile/index.md', anchor: 'sign-in-services')), + :doc_start, + :doc_end + ) + message << safe_format( + _('Create an account in %{simple_url} first, and then %{doc_start}connect it to ' \ + 'your %{label} account%{doc_end}.'), + doc_pair, + label: label, + simple_url: simple_url + ) end flash[:alert] = message.join(' ').html_safe # rubocop:disable Rails/OutputSafety -- Generated message is safe @@ -308,7 +326,13 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController def handle_identity_with_untrusted_extern_uid label = Gitlab::Auth::OAuth::Provider.label_for(oauth['provider']) - flash[:alert] = format(_("Signing in using your %{label} account has been disabled for security reasons. Please sign in to your GitLab account using another authentication method and reconnect to your %{label} account."), label: label) + flash[:alert] = format( + _('Signing in using your %{label} account has been disabled for security reasons. ' \ + 'Please sign in to your GitLab account using another authentication method and ' \ + 'reconnect to your %{label} account.' + ), + label: label + ) redirect_to new_user_session_path end diff --git a/app/controllers/profiles/chat_names_controller.rb b/app/controllers/profiles/chat_names_controller.rb index c4384c962d2..7a2d4447a45 100644 --- a/app/controllers/profiles/chat_names_controller.rb +++ b/app/controllers/profiles/chat_names_controller.rb @@ -30,7 +30,8 @@ class Profiles::ChatNamesController < Profiles::ApplicationController def deny delete_chat_name_token - flash[:notice] = _("Denied authorization of chat nickname %{user_name}.") % { user_name: chat_name_params[:user_name] } + flash[:notice] = + _("Denied authorization of chat nickname %{user_name}.") % { user_name: chat_name_params[:user_name] } redirect_to profile_chat_names_path end diff --git a/app/graphql/types/ci/job_token_scope/allowlist_entry_type.rb b/app/graphql/types/ci/job_token_scope/allowlist_entry_type.rb index 77e795f5c74..3e976ef6919 100644 --- a/app/graphql/types/ci/job_token_scope/allowlist_entry_type.rb +++ b/app/graphql/types/ci/job_token_scope/allowlist_entry_type.rb @@ -66,7 +66,7 @@ module Types def job_token_policies return unless Feature.enabled?(:add_policies_to_ci_job_token, object.source_project) - object.job_token_policies + object.job_token_policies&.map(&:to_sym) end end # rubocop: enable Graphql/AuthorizeTypes diff --git a/app/graphql/types/ci/job_token_scope/job_token_policy_category_type.rb b/app/graphql/types/ci/job_token_scope/job_token_policy_category_type.rb new file mode 100644 index 00000000000..31a013f8888 --- /dev/null +++ b/app/graphql/types/ci/job_token_scope/job_token_policy_category_type.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +module Types + module Ci + module JobTokenScope + # rubocop: disable Graphql/AuthorizeTypes -- this is static data + class JobTokenPolicyCategoryType < BaseObject + graphql_name 'JobTokenPolicyCategory' + description 'Job token policy category type' + + field :description, GraphQL::Types::String, description: 'Description of the category.' + field :policies, [Types::Ci::JobTokenScope::JobTokenPolicyType], description: 'Policies of the category.' + field :text, GraphQL::Types::String, description: 'Display text of the category.' + field :value, Types::Ci::JobTokenScope::PolicyCategoriesEnum, description: 'Value of the category.' + end + # rubocop: enable Graphql/AuthorizeTypes + end + end +end diff --git a/app/graphql/types/ci/job_token_scope/job_token_policy_type.rb b/app/graphql/types/ci/job_token_scope/job_token_policy_type.rb new file mode 100644 index 00000000000..b31255550ff --- /dev/null +++ b/app/graphql/types/ci/job_token_scope/job_token_policy_type.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +module Types + module Ci + module JobTokenScope + # rubocop: disable Graphql/AuthorizeTypes -- this is static data + class JobTokenPolicyType < BaseObject + graphql_name 'JobTokenPolicy' + description 'Job token policy' + + field :description, GraphQL::Types::String, description: 'Description of the job token policy.' + field :text, GraphQL::Types::String, description: 'Display text of the job token policy.' + field :type, Types::Ci::JobTokenScope::PolicyTypesEnum, description: 'Job token policy type.' + field :value, Types::Ci::JobTokenScope::PoliciesEnum, description: 'Value of the job token policy.' + end + # rubocop: enable Graphql/AuthorizeTypes + end + end +end diff --git a/app/graphql/types/ci/job_token_scope/policies_enum.rb b/app/graphql/types/ci/job_token_scope/policies_enum.rb index 88ed8612f54..be4abc61d5a 100644 --- a/app/graphql/types/ci/job_token_scope/policies_enum.rb +++ b/app/graphql/types/ci/job_token_scope/policies_enum.rb @@ -7,8 +7,8 @@ module Types graphql_name 'CiJobTokenScopePolicies' description 'CI_JOB_TOKEN policy' - ::Ci::JobToken::Policies.all_values.each do |policy| - value policy.upcase, value: policy, description: policy.titleize + ::Ci::JobToken::Policies.all_policies.each do |policy| + value policy[:value].to_s.upcase, value: policy[:value], description: policy[:description] end end end diff --git a/app/graphql/types/ci/job_token_scope/policy_categories_enum.rb b/app/graphql/types/ci/job_token_scope/policy_categories_enum.rb new file mode 100644 index 00000000000..39683b3d6ca --- /dev/null +++ b/app/graphql/types/ci/job_token_scope/policy_categories_enum.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +module Types + module Ci + module JobTokenScope + class PolicyCategoriesEnum < BaseEnum + graphql_name 'CiJobTokenScopePolicyCategoriesTypes' + description 'CI_JOB_TOKEN policy category type' + + ::Ci::JobToken::Policies::POLICIES_BY_CATEGORY.each do |category| + value category[:value].to_s.upcase, value: category[:value], description: category[:description] + end + end + end + end +end diff --git a/app/graphql/types/ci/job_token_scope/policy_types_enum.rb b/app/graphql/types/ci/job_token_scope/policy_types_enum.rb new file mode 100644 index 00000000000..420dfb46d71 --- /dev/null +++ b/app/graphql/types/ci/job_token_scope/policy_types_enum.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +module Types + module Ci + module JobTokenScope + class PolicyTypesEnum < BaseEnum + graphql_name 'CiJobTokenScopePolicyTypes' + description 'CI_JOB_TOKEN policy type' + + value 'READ', value: :read, description: 'Read-only access to the resource.' + value 'ADMIN', value: :admin, description: 'Admin access to the resource.' + end + end + end +end diff --git a/app/graphql/types/query_type.rb b/app/graphql/types/query_type.rb index 781da877851..e7637e2c7e8 100644 --- a/app/graphql/types/query_type.rb +++ b/app/graphql/types/query_type.rb @@ -245,6 +245,10 @@ module Types description: 'Check if a feature flag is enabled', resolver: Resolvers::FeatureFlagResolver + field :job_token_policies_by_category, [::Types::Ci::JobTokenScope::JobTokenPolicyCategoryType], + description: 'List of job token policies for use with fine-grained permissions on CI/CD job allowlist.', + experiment: { milestone: '17.7' } + def design_management DesignManagementObject.new(nil) end @@ -298,6 +302,10 @@ module Types stage end + + def job_token_policies_by_category + ::Ci::JobToken::Policies::POLICIES_BY_CATEGORY + end end end diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb index 56ce32398f5..cba371d591f 100644 --- a/app/helpers/projects_helper.rb +++ b/app/helpers/projects_helper.rb @@ -439,6 +439,7 @@ module ProjectsHelper end def show_lfs_misconfiguration_banner?(project) + return false unless Feature.enabled?(:lfs_misconfiguration_banner) return false unless project.repository return false unless project.lfs_enabled? diff --git a/app/services/ci/cancel_pipeline_service.rb b/app/services/ci/cancel_pipeline_service.rb index 68e893c8a6d..a6a75b197d2 100644 --- a/app/services/ci/cancel_pipeline_service.rb +++ b/app/services/ci/cancel_pipeline_service.rb @@ -64,6 +64,7 @@ module Ci def log_pipeline_being_canceled Gitlab::AppJsonLogger.info( + class: self.class.to_s, event: 'pipeline_cancel_running', pipeline_id: pipeline.id, auto_canceled_by_pipeline_id: @auto_canceled_by_pipeline&.id, diff --git a/app/validators/json_schemas/ci_job_token_policies.json b/app/validators/json_schemas/ci_job_token_policies.json index 3da0d8b309a..b5d2d37aa26 100644 --- a/app/validators/json_schemas/ci_job_token_policies.json +++ b/app/validators/json_schemas/ci_job_token_policies.json @@ -5,41 +5,22 @@ "items": { "type": "string", "enum": [ - "admin_container_image", - "admin_secure_files", - "admin_terraform_state", - "build_create_container_image", - "build_destroy_container_image", - "build_download_code", - "build_push_code", - "build_read_container_image", - "create_deployment", - "create_environment", - "create_on_demand_dast_scan", - "create_package", - "create_release", - "destroy_container_image", - "destroy_deployment", - "destroy_environment", - "destroy_package", - "destroy_release", - "read_build", - "read_container_image", - "read_deployment", - "read_environment", - "read_group", - "read_job_artifacts", - "read_package", - "read_pipeline", - "read_project", - "read_release", + "read_containers", + "admin_containers", + "read_deployments", + "admin_deployments", + "read_environments", + "admin_environments", + "read_jobs", + "admin_jobs", + "read_packages", + "admin_packages", + "read_releases", + "admin_releases", "read_secure_files", + "admin_secure_files", "read_terraform_state", - "stop_environment", - "update_deployment", - "update_environment", - "update_pipeline", - "update_release" + "admin_terraform_state" ] }, "uniqueItems": true, diff --git a/config/feature_flags/gitlab_com_derisk/lfs_misconfiguration_banner.patch b/config/feature_flags/gitlab_com_derisk/lfs_misconfiguration_banner.patch new file mode 100644 index 00000000000..b3d92157b0b --- /dev/null +++ b/config/feature_flags/gitlab_com_derisk/lfs_misconfiguration_banner.patch @@ -0,0 +1,31 @@ +diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb +index 04591476b72d..aecb81bb664b 100644 +--- a/app/helpers/projects_helper.rb ++++ b/app/helpers/projects_helper.rb +@@ -404,7 +404,6 @@ def show_terraform_banner?(project) + end + + def show_lfs_misconfiguration_banner?(project) +- return false unless Feature.enabled?(:lfs_misconfiguration_banner) + return false unless project.repository + return false unless project.lfs_enabled? + +diff --git a/spec/helpers/projects_helper_spec.rb b/spec/helpers/projects_helper_spec.rb +index a6ea3ec16179..ea2fdf3f4ba7 100644 +--- a/spec/helpers/projects_helper_spec.rb ++++ b/spec/helpers/projects_helper_spec.rb +@@ -903,14 +903,6 @@ def license_name + + it { is_expected.to be_falsey } + end +- +- context 'when lfs_misconfiguration_banner feature flag is disabled' do +- before do +- stub_feature_flags(lfs_misconfiguration_banner: false) +- end +- +- it { is_expected.to be_falsey } +- end + end + + context 'when it does have a .gitattributes file' do diff --git a/config/feature_flags/gitlab_com_derisk/lfs_misconfiguration_banner.yml b/config/feature_flags/gitlab_com_derisk/lfs_misconfiguration_banner.yml new file mode 100644 index 00000000000..5c3f56e8757 --- /dev/null +++ b/config/feature_flags/gitlab_com_derisk/lfs_misconfiguration_banner.yml @@ -0,0 +1,9 @@ +--- +name: lfs_misconfiguration_banner +feature_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/429467 +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/162123 +rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/477892 +milestone: '17.4' +group: group::source code +type: gitlab_com_derisk +default_enabled: false diff --git a/config/helpers/vite_plugin_style.mjs b/config/helpers/vite_plugin_style.mjs index b8eb8946bba..189592670f4 100644 --- a/config/helpers/vite_plugin_style.mjs +++ b/config/helpers/vite_plugin_style.mjs @@ -1,13 +1,10 @@ import path from 'node:path'; -import { fileURLToPath } from 'node:url'; -/* eslint-disable import/extensions */ import { resolveCompilationTargetsForVite, resolveLoadPaths, } from '../../scripts/frontend/lib/compile_css.mjs'; -/* eslint-enable import/extensions */ -const ROOT_PATH = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../../'); +const ROOT_PATH = path.resolve(import.meta.dirname, '../../'); /** * This Plugin provides virtual entrypoints for our SCSS files diff --git a/config/initializers/puma_patch.rb b/config/initializers/puma_patch.rb deleted file mode 100644 index 9f8c690b9a0..00000000000 --- a/config/initializers/puma_patch.rb +++ /dev/null @@ -1,77 +0,0 @@ -# frozen_string_literal: true - -return unless Gitlab::Runtime.puma? - -require 'puma' -require 'puma/cluster' - -# Ruby 3.1 and 3.2 have bugs that prevents Puma from reaping child processes properly: -# https://bugs.ruby-lang.org/issues/20490 -# https://bugs.ruby-lang.org/issues/19837 -# -# https://github.com/puma/puma/pull/3314 fixes this in Puma, but a release -# has not been forthcoming. -if Gem::Version.new(Puma::Const::PUMA_VERSION) > Gem::Version.new('6.5') - raise 'This patch should not be needed after Puma 6.5.0.' -end - -# rubocop:disable Style/RedundantBegin -- These are upstream changes -# rubocop:disable Cop/LineBreakAfterGuardClauses -- These are upstream changes -# rubocop:disable Layout/EmptyLineAfterGuardClause -- These are upstream changes -module Puma - class Cluster < Runner - # loops thru @workers, removing workers that exited, and calling - # `#term` if needed - def wait_workers - # Reap all children, known workers or otherwise. - # If puma has PID 1, as it's common in containerized environments, - # then it's responsible for reaping orphaned processes, so we must reap - # all our dead children, regardless of whether they are workers we spawned - # or some reattached processes. - reaped_children = {} - loop do - begin - pid, status = Process.wait2(-1, Process::WNOHANG) - break unless pid - reaped_children[pid] = status - rescue Errno::ECHILD - break - end - end - - @workers.reject! do |w| - next false if w.pid.nil? - begin - # We may need to check the PID individually because: - # 1. From Ruby versions 2.6 to 3.2, `Process.detach` can prevent or delay - # `Process.wait2(-1)` from detecting a terminated process: https://bugs.ruby-lang.org/issues/19837. - # 2. When `fork_worker` is enabled, some worker may not be direct children, - # but grand children. Because of this they won't be reaped by `Process.wait2(-1)`. - if reaped_children.delete(w.pid) || Process.wait(w.pid, Process::WNOHANG) - true - else - w.term if w.term? - nil - end - rescue Errno::ECHILD - begin - Process.kill(0, w.pid) - # child still alive but has another parent (e.g., using fork_worker) - w.term if w.term? - false - rescue Errno::ESRCH, Errno::EPERM - true # child is already terminated - end - end - end - - # Log unknown children - reaped_children.each do |pid, status| - log "! reaped unknown child process pid=#{pid} status=#{status}" - end - end - end -end -# rubocop:enable Style/RedundantBegin -# rubocop:enable Cop/LineBreakAfterGuardClauses -# rubocop:enable Layout/EmptyLineAfterGuardClause diff --git a/db/docs/batched_background_migrations/backfill_group_wiki_repository_states_group_id.yml b/db/docs/batched_background_migrations/backfill_group_wiki_repository_states_group_id.yml new file mode 100644 index 00000000000..d35f0c8ad97 --- /dev/null +++ b/db/docs/batched_background_migrations/backfill_group_wiki_repository_states_group_id.yml @@ -0,0 +1,8 @@ +--- +migration_job_name: BackfillGroupWikiRepositoryStatesGroupId +description: Backfills sharding key `group_wiki_repository_states.group_id` from `group_wiki_repositories`. +feature_category: geo_replication +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/169242 +milestone: '17.7' +queued_migration_version: 20241125133627 +finalized_by: # version of the migration that finalized this BBM diff --git a/db/docs/group_wiki_repository_states.yml b/db/docs/group_wiki_repository_states.yml index 64e37995c66..1be22a53842 100644 --- a/db/docs/group_wiki_repository_states.yml +++ b/db/docs/group_wiki_repository_states.yml @@ -19,3 +19,4 @@ desired_sharding_key: sharding_key: group_id belongs_to: group_wiki_repository table_size: small +desired_sharding_key_migration_job_name: BackfillGroupWikiRepositoryStatesGroupId diff --git a/db/migrate/20241104130731_add_role_approvers_to_approval_merge_request_rules.rb b/db/migrate/20241104130731_add_role_approvers_to_approval_merge_request_rules.rb index f21794c1261..52058b74208 100644 --- a/db/migrate/20241104130731_add_role_approvers_to_approval_merge_request_rules.rb +++ b/db/migrate/20241104130731_add_role_approvers_to_approval_merge_request_rules.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true class AddRoleApproversToApprovalMergeRequestRules < Gitlab::Database::Migration[2.2] - milestone '17.6' + milestone '17.7' disable_ddl_transaction! CONSTRAINT_NAME = 'check_approval_m_r_rules_allowed_role_approvers_valid_entries' diff --git a/db/migrate/20241125133011_add_group_id_to_group_wiki_repository_states.rb b/db/migrate/20241125133011_add_group_id_to_group_wiki_repository_states.rb new file mode 100644 index 00000000000..0e54a9f1f7d --- /dev/null +++ b/db/migrate/20241125133011_add_group_id_to_group_wiki_repository_states.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +class AddGroupIdToGroupWikiRepositoryStates < Gitlab::Database::Migration[2.2] + milestone '17.7' + + def change + add_column :group_wiki_repository_states, :group_id, :bigint + end +end diff --git a/db/post_migrate/20241125133120_index_group_wiki_repository_states_on_group_id.rb b/db/post_migrate/20241125133120_index_group_wiki_repository_states_on_group_id.rb new file mode 100644 index 00000000000..46da1542956 --- /dev/null +++ b/db/post_migrate/20241125133120_index_group_wiki_repository_states_on_group_id.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +class IndexGroupWikiRepositoryStatesOnGroupId < Gitlab::Database::Migration[2.2] + milestone '17.7' + disable_ddl_transaction! + + INDEX_NAME = 'index_group_wiki_repository_states_on_group_id' + + def up + add_concurrent_index :group_wiki_repository_states, :group_id, name: INDEX_NAME + end + + def down + remove_concurrent_index_by_name :group_wiki_repository_states, INDEX_NAME + end +end diff --git a/db/post_migrate/20241125133216_add_group_wiki_repository_states_group_id_fk.rb b/db/post_migrate/20241125133216_add_group_wiki_repository_states_group_id_fk.rb new file mode 100644 index 00000000000..857dbea40fb --- /dev/null +++ b/db/post_migrate/20241125133216_add_group_wiki_repository_states_group_id_fk.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +class AddGroupWikiRepositoryStatesGroupIdFk < Gitlab::Database::Migration[2.2] + milestone '17.7' + disable_ddl_transaction! + + def up + add_concurrent_foreign_key :group_wiki_repository_states, :namespaces, column: :group_id, on_delete: :cascade + end + + def down + with_lock_retries do + remove_foreign_key :group_wiki_repository_states, column: :group_id + end + end +end diff --git a/db/post_migrate/20241125133312_add_group_wiki_repository_states_group_id_trigger.rb b/db/post_migrate/20241125133312_add_group_wiki_repository_states_group_id_trigger.rb new file mode 100644 index 00000000000..c9b0e53a776 --- /dev/null +++ b/db/post_migrate/20241125133312_add_group_wiki_repository_states_group_id_trigger.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +class AddGroupWikiRepositoryStatesGroupIdTrigger < Gitlab::Database::Migration[2.2] + milestone '17.7' + + def up + install_sharding_key_assignment_trigger( + table: :group_wiki_repository_states, + sharding_key: :group_id, + parent_table: :group_wiki_repositories, + parent_table_primary_key: :group_id, + parent_sharding_key: :group_id, + foreign_key: :group_wiki_repository_id + ) + end + + def down + remove_sharding_key_assignment_trigger( + table: :group_wiki_repository_states, + sharding_key: :group_id, + parent_table: :group_wiki_repositories, + parent_table_primary_key: :group_id, + parent_sharding_key: :group_id, + foreign_key: :group_wiki_repository_id + ) + end +end diff --git a/db/post_migrate/20241125133627_queue_backfill_group_wiki_repository_states_group_id.rb b/db/post_migrate/20241125133627_queue_backfill_group_wiki_repository_states_group_id.rb new file mode 100644 index 00000000000..f8bae7d0f90 --- /dev/null +++ b/db/post_migrate/20241125133627_queue_backfill_group_wiki_repository_states_group_id.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true + +class QueueBackfillGroupWikiRepositoryStatesGroupId < Gitlab::Database::Migration[2.2] + milestone '17.7' + restrict_gitlab_migration gitlab_schema: :gitlab_main_cell + + MIGRATION = "BackfillGroupWikiRepositoryStatesGroupId" + DELAY_INTERVAL = 2.minutes + BATCH_SIZE = 1000 + SUB_BATCH_SIZE = 100 + + def up + queue_batched_background_migration( + MIGRATION, + :group_wiki_repository_states, + :id, + :group_id, + :group_wiki_repositories, + :group_id, + :group_wiki_repository_id, + job_interval: DELAY_INTERVAL, + batch_size: BATCH_SIZE, + sub_batch_size: SUB_BATCH_SIZE + ) + end + + def down + delete_batched_background_migration( + MIGRATION, + :group_wiki_repository_states, + :id, + [ + :group_id, + :group_wiki_repositories, + :group_id, + :group_wiki_repository_id + ] + ) + end +end diff --git a/db/schema_migrations/20241125133011 b/db/schema_migrations/20241125133011 new file mode 100644 index 00000000000..09d09f84346 --- /dev/null +++ b/db/schema_migrations/20241125133011 @@ -0,0 +1 @@ +a343179b4ff10dc52c123c4c16eae512dac082f1e732905b7b9d1ed797cadd39 \ No newline at end of file diff --git a/db/schema_migrations/20241125133120 b/db/schema_migrations/20241125133120 new file mode 100644 index 00000000000..0c703a0a390 --- /dev/null +++ b/db/schema_migrations/20241125133120 @@ -0,0 +1 @@ +f3a17c383994b89d08effcf7858d5f62b34f00a3e88d0585b55ce1b2d2b98200 \ No newline at end of file diff --git a/db/schema_migrations/20241125133216 b/db/schema_migrations/20241125133216 new file mode 100644 index 00000000000..0fc41c617c5 --- /dev/null +++ b/db/schema_migrations/20241125133216 @@ -0,0 +1 @@ +5b2655c6752ea3d16426262d7ba7182c4ce54445bfad284e177f4f295b1879fa \ No newline at end of file diff --git a/db/schema_migrations/20241125133312 b/db/schema_migrations/20241125133312 new file mode 100644 index 00000000000..4d6b7474b0b --- /dev/null +++ b/db/schema_migrations/20241125133312 @@ -0,0 +1 @@ +10b4dbd09a1888c465a7899a6dcaf4875873980fbf93fd238b384136fd012b57 \ No newline at end of file diff --git a/db/schema_migrations/20241125133627 b/db/schema_migrations/20241125133627 new file mode 100644 index 00000000000..9527cacfc05 --- /dev/null +++ b/db/schema_migrations/20241125133627 @@ -0,0 +1 @@ +3cc2c84bc6f4ca87de823ad9ecaed8f4bc4699d65d272793fb9d5995a3c1e4ac \ No newline at end of file diff --git a/db/structure.sql b/db/structure.sql index 9a6db39e28e..d699725a769 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -2337,6 +2337,22 @@ RETURN NEW; END $$; +CREATE FUNCTION trigger_a22be47501db() RETURNS trigger + LANGUAGE plpgsql + AS $$ +BEGIN +IF NEW."group_id" IS NULL THEN + SELECT "group_id" + INTO NEW."group_id" + FROM "group_wiki_repositories" + WHERE "group_wiki_repositories"."group_id" = NEW."group_wiki_repository_id"; +END IF; + +RETURN NEW; + +END +$$; + CREATE FUNCTION trigger_a253cb3cacdf() RETURNS trigger LANGUAGE plpgsql AS $$ @@ -12763,6 +12779,7 @@ CREATE TABLE group_wiki_repository_states ( verification_retry_count smallint DEFAULT 0 NOT NULL, verification_checksum bytea, verification_failure text, + group_id bigint, CONSTRAINT check_14d288436d CHECK ((char_length(verification_failure) <= 255)) ); @@ -30320,6 +30337,8 @@ CREATE INDEX index_group_wiki_repository_states_failed_verification ON group_wik CREATE INDEX index_group_wiki_repository_states_needs_verification ON group_wiki_repository_states USING btree (verification_state) WHERE ((verification_state = 0) OR (verification_state = 3)); +CREATE INDEX index_group_wiki_repository_states_on_group_id ON group_wiki_repository_states USING btree (group_id); + CREATE UNIQUE INDEX index_group_wiki_repository_states_on_group_wiki_repository_id ON group_wiki_repository_states USING btree (group_wiki_repository_id); CREATE INDEX index_group_wiki_repository_states_on_verification_state ON group_wiki_repository_states USING btree (verification_state); @@ -35206,6 +35225,8 @@ CREATE TRIGGER trigger_9f3de326ea61 BEFORE INSERT OR UPDATE ON ci_pipeline_sched CREATE TRIGGER trigger_a1bc7c70cbdf BEFORE INSERT OR UPDATE ON vulnerability_user_mentions FOR EACH ROW EXECUTE FUNCTION trigger_a1bc7c70cbdf(); +CREATE TRIGGER trigger_a22be47501db BEFORE INSERT OR UPDATE ON group_wiki_repository_states FOR EACH ROW EXECUTE FUNCTION trigger_a22be47501db(); + CREATE TRIGGER trigger_a253cb3cacdf BEFORE INSERT OR UPDATE ON dora_daily_metrics FOR EACH ROW EXECUTE FUNCTION trigger_a253cb3cacdf(); CREATE TRIGGER trigger_a465de38164e BEFORE INSERT OR UPDATE ON ci_job_artifact_states FOR EACH ROW EXECUTE FUNCTION trigger_a465de38164e(); @@ -35934,6 +35955,9 @@ ALTER TABLE ONLY dast_profile_schedules ALTER TABLE ONLY events ADD CONSTRAINT fk_61fbf6ca48 FOREIGN KEY (group_id) REFERENCES namespaces(id) ON DELETE CASCADE; +ALTER TABLE ONLY group_wiki_repository_states + ADD CONSTRAINT fk_621768bf3d FOREIGN KEY (group_id) REFERENCES namespaces(id) ON DELETE CASCADE; + ALTER TABLE ONLY vulnerability_reads ADD CONSTRAINT fk_62736f638f FOREIGN KEY (vulnerability_id) REFERENCES vulnerabilities(id) ON DELETE CASCADE; diff --git a/doc/administration/geo/replication/troubleshooting/postgresql_replication.md b/doc/administration/geo/replication/troubleshooting/postgresql_replication.md index c535cf9bcdd..c962fb307f7 100644 --- a/doc/administration/geo/replication/troubleshooting/postgresql_replication.md +++ b/doc/administration/geo/replication/troubleshooting/postgresql_replication.md @@ -50,49 +50,6 @@ If the secondary site is not able to reconnect, use the following steps to remov 1. Follow either the steps [to remove that Geo site](../remove_geo_site.md) if it's no longer required, or [re-initiate the replication process](../../setup/database.md#step-3-initiate-the-replication-process), which recreates the replication slot correctly. -### Message: `"Error during verification","error":"File is not checksummable"` - -If you encounter these errors in your primary site `geo.log`, they're also reflected in the UI under **Admin > Geo > Sites**. To remove those errors, you can identify the particular blob that generates the message so that you can inspect it. - -1. In a Puma or Sidekiq node in the primary site, [open a Rails console](../../../../administration/operations/rails_console.md#starting-a-rails-console-session). -1. Run the following snippet to find the affected artifacts containing the `File is not checksummable` message: - -NOTE: -The example provided below uses `JobArtifact` blob type; however, the same solution applies to any blob type that Geo uses. - -```ruby - -artifacts = Ci::JobArtifact.verification_failed.where("verification_failure like '%File is not checksummable%'");1 -puts "Found #{artifacts.count} artifacts that failed verification with 'File is not checksummable'. The first one:" -pp artifacts.first -``` - -If you determine that the affected files need to be recovered then you can explore these options (non-exhaustive) to recover the missing files: - -- Check if the secondary site has the object and manually copy them to the primary. -- Look through old backups and manually copy the object back into the primary site. -- Spot check some to try to determine that it's probably fine to destroy the records, for example, if they are all very old artifacts, then maybe they are not critical data. - -Often, these kinds of errors happen when a file is checksummed by Geo, and then goes missing from the primary site. After you identify the affected files, you should check the projects that the files belong to from the UI to decide if it's acceptable to delete the file reference. If so, you can destroy the references with the following irreversible snippet: - -```ruby -def destroy_artifacts_not_checksummable - artifacts = Ci::JobArtifact.verification_failed.where("verification_failure like '%File is not checksummable%'");1 - puts "Found #{artifacts.count} artifacts that failed verification with 'File is not checksummable'." - puts "Enter 'y' to continue: " - prompt = STDIN.gets.chomp - if prompt != 'y' - puts "Exiting without action..." - return - end - - puts "Destroying all..." - artifacts.destroy_all -end - -destroy_artifacts_not_checksummable -``` - ## Message: `WARNING: oldest xmin is far in the past` and `pg_wal` size growing If a replication slot is inactive, diff --git a/doc/administration/geo/replication/troubleshooting/synchronization_verification.md b/doc/administration/geo/replication/troubleshooting/synchronization_verification.md index 46bfffc2947..a2ceed980f2 100644 --- a/doc/administration/geo/replication/troubleshooting/synchronization_verification.md +++ b/doc/administration/geo/replication/troubleshooting/synchronization_verification.md @@ -279,6 +279,49 @@ end p "#{uploads_deleted} remote objects were destroyed." ``` +### Message: `"Error during verification","error":"File is not checksummable"` + +If you encounter these errors in your primary site `geo.log`, they're also reflected in the UI under **Admin > Geo > Sites**. To remove those errors, you can identify the particular blob that generates the message so that you can inspect it. + +1. In a Puma or Sidekiq node in the primary site, [open a Rails console](../../../../administration/operations/rails_console.md#starting-a-rails-console-session). +1. Run the following snippet to find the affected artifacts containing the `File is not checksummable` message: + +NOTE: +The example provided below uses `JobArtifact` blob type; however, the same solution applies to any blob type that Geo uses. + +```ruby + +artifacts = Ci::JobArtifact.verification_failed.where("verification_failure like '%File is not checksummable%'");1 +puts "Found #{artifacts.count} artifacts that failed verification with 'File is not checksummable'. The first one:" +pp artifacts.first +``` + +If you determine that the affected files need to be recovered then you can explore these options (non-exhaustive) to recover the missing files: + +- Check if the secondary site has the object and manually copy them to the primary. +- Look through old backups and manually copy the object back into the primary site. +- Spot check some to try to determine that it's probably fine to destroy the records, for example, if they are all very old artifacts, then maybe they are not critical data. + +Often, these kinds of errors happen when a file is checksummed by Geo, and then goes missing from the primary site. After you identify the affected files, you should check the projects that the files belong to from the UI to decide if it's acceptable to delete the file reference. If so, you can destroy the references with the following irreversible snippet: + +```ruby +def destroy_artifacts_not_checksummable + artifacts = Ci::JobArtifact.verification_failed.where("verification_failure like '%File is not checksummable%'");1 + puts "Found #{artifacts.count} artifacts that failed verification with 'File is not checksummable'." + puts "Enter 'y' to continue: " + prompt = STDIN.gets.chomp + if prompt != 'y' + puts "Exiting without action..." + return + end + + puts "Destroying all..." + artifacts.destroy_all +end + +destroy_artifacts_not_checksummable +``` + ### Error: `Error syncing repository: 13:fatal: could not read Username` The `last_sync_failure` error diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md index 561d4fe691f..d2aec5128f5 100644 --- a/doc/api/graphql/reference/index.md +++ b/doc/api/graphql/reference/index.md @@ -725,6 +725,16 @@ Returns [`Iteration`](#iteration). | ---- | ---- | ----------- | | `id` | [`IterationID!`](#iterationid) | Find an iteration by its ID. | +### `Query.jobTokenPoliciesByCategory` + +List of job token policies for use with fine-grained permissions on CI/CD job allowlist. + +DETAILS: +**Introduced** in GitLab 17.7. +**Status**: Experiment. + +Returns [`[JobTokenPolicyCategory!]`](#jobtokenpolicycategory). + ### `Query.jobs` All jobs on this GitLab instance. Returns an empty result for users without administrator access. @@ -26868,6 +26878,32 @@ Represents the Geo replication and verification state of a job_artifact. | `readJobArtifacts` | [`Boolean!`](#boolean) | If `true`, the user can perform `read_job_artifacts` on this resource. | | `updateBuild` | [`Boolean!`](#boolean) | If `true`, the user can perform `update_build` on this resource. | +### `JobTokenPolicy` + +Job token policy. + +#### Fields + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `description` | [`String`](#string) | Description of the job token policy. | +| `text` | [`String`](#string) | Display text of the job token policy. | +| `type` | [`CiJobTokenScopePolicyTypes`](#cijobtokenscopepolicytypes) | Job token policy type. | +| `value` | [`CiJobTokenScopePolicies`](#cijobtokenscopepolicies) | Value of the job token policy. | + +### `JobTokenPolicyCategory` + +Job token policy category type. + +#### Fields + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `description` | [`String`](#string) | Description of the category. | +| `policies` | [`[JobTokenPolicy!]`](#jobtokenpolicy) | Policies of the category. | +| `text` | [`String`](#string) | Display text of the category. | +| `value` | [`CiJobTokenScopePolicyCategoriesTypes`](#cijobtokenscopepolicycategoriestypes) | Value of the category. | + ### `Kas` #### Fields @@ -36088,6 +36124,7 @@ Represents a vulnerability. | `primaryIdentifier` | [`VulnerabilityIdentifier`](#vulnerabilityidentifier) | Primary identifier of the vulnerability. | | `project` | [`Project`](#project) | Project on which the vulnerability was found. | | `reportType` | [`VulnerabilityReportType`](#vulnerabilityreporttype) | Type of the security report that found the vulnerability (SAST, DEPENDENCY_SCANNING, CONTAINER_SCANNING, DAST, SECRET_DETECTION, COVERAGE_FUZZING, API_FUZZING, CLUSTER_IMAGE_SCANNING, CONTAINER_SCANNING_FOR_REGISTRY, GENERIC). `Scan Type` in the UI. | +| `representationInformation` **{warning-solid}** | [`VulnerabilityRepresentationInformation`](#vulnerabilityrepresentationinformation) | **Introduced** in GitLab 17.7. **Status**: Experiment. Information about the representation of the vulnerability, such as resolved commit SHA. | | `resolvedAt` | [`Time`](#time) | Timestamp of when the vulnerability state was changed to resolved. | | `resolvedBy` | [`UserCore`](#usercore) | User that resolved the vulnerability. | | `resolvedOnDefaultBranch` | [`Boolean!`](#boolean) | Indicates whether the vulnerability is fixed on the default branch or not. | @@ -36631,6 +36668,16 @@ Represents a vulnerability remediation type. | `diff` | [`String`](#string) | Diff of the remediation. | | `summary` | [`String`](#string) | Summary of the remediation. | +### `VulnerabilityRepresentationInformation` + +Represents vulnerability information. + +#### Fields + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `resolvedInCommitSha` | [`String`](#string) | SHA of the commit where the vulnerability was resolved. | + ### `VulnerabilityRequest` Represents a Vulnerability Request. @@ -37999,41 +38046,46 @@ CI_JOB_TOKEN policy. | Value | Description | | ----- | ----------- | -| `ADMIN_CONTAINER_IMAGE` | Admin Container Image. | -| `ADMIN_SECURE_FILES` | Admin Secure Files. | -| `ADMIN_TERRAFORM_STATE` | Admin Terraform State. | -| `BUILD_CREATE_CONTAINER_IMAGE` | Build Create Container Image. | -| `BUILD_DESTROY_CONTAINER_IMAGE` | Build Destroy Container Image. | -| `BUILD_DOWNLOAD_CODE` | Build Download Code. | -| `BUILD_PUSH_CODE` | Build Push Code. | -| `BUILD_READ_CONTAINER_IMAGE` | Build Read Container Image. | -| `CREATE_DEPLOYMENT` | Create Deployment. | -| `CREATE_ENVIRONMENT` | Create Environment. | -| `CREATE_ON_DEMAND_DAST_SCAN` | Create On Demand Dast Scan. | -| `CREATE_PACKAGE` | Create Package. | -| `CREATE_RELEASE` | Create Release. | -| `DESTROY_CONTAINER_IMAGE` | Destroy Container Image. | -| `DESTROY_DEPLOYMENT` | Destroy Deployment. | -| `DESTROY_ENVIRONMENT` | Destroy Environment. | -| `DESTROY_PACKAGE` | Destroy Package. | -| `DESTROY_RELEASE` | Destroy Release. | -| `READ_BUILD` | Read Build. | -| `READ_CONTAINER_IMAGE` | Read Container Image. | -| `READ_DEPLOYMENT` | Read Deployment. | -| `READ_ENVIRONMENT` | Read Environment. | -| `READ_GROUP` | Read Group. | -| `READ_JOB_ARTIFACTS` | Read Job Artifacts. | -| `READ_PACKAGE` | Read Package. | -| `READ_PIPELINE` | Read Pipeline. | -| `READ_PROJECT` | Read Project. | -| `READ_RELEASE` | Read Release. | -| `READ_SECURE_FILES` | Read Secure Files. | -| `READ_TERRAFORM_STATE` | Read Terraform State. | -| `STOP_ENVIRONMENT` | Stop Environment. | -| `UPDATE_DEPLOYMENT` | Update Deployment. | -| `UPDATE_ENVIRONMENT` | Update Environment. | -| `UPDATE_PIPELINE` | Update Pipeline. | -| `UPDATE_RELEASE` | Update Release. | +| `ADMIN_CONTAINERS` | Admin container images in a project. | +| `ADMIN_DEPLOYMENTS` | Admin deployments in a project. | +| `ADMIN_ENVIRONMENTS` | Admin + Stop environments in a project. | +| `ADMIN_JOBS` | Read job metadata, upload artifacts and update the pipeline status. | +| `ADMIN_PACKAGES` | Admin packages. | +| `ADMIN_RELEASES` | Admin releases in a project. | +| `ADMIN_SECURE_FILES` | Admin secure files in a project. | +| `ADMIN_TERRAFORM_STATE` | Admin terraform state files/versions. | +| `READ_CONTAINERS` | Read container images in a project. | +| `READ_DEPLOYMENTS` | Read deployments in a project. | +| `READ_ENVIRONMENTS` | Read environments in a project. | +| `READ_JOBS` | Read job metadata and artifacts. | +| `READ_PACKAGES` | Read packages. | +| `READ_RELEASES` | Read releases in a project. | +| `READ_SECURE_FILES` | Read secure files in a project. | +| `READ_TERRAFORM_STATE` | Read terraform state files/version. | + +### `CiJobTokenScopePolicyCategoriesTypes` + +CI_JOB_TOKEN policy category type. + +| Value | Description | +| ----- | ----------- | +| `CONTAINERS` | Containers category. | +| `DEPLOYMENTS` | Deployments category. | +| `ENVIRONMENTS` | Environments category. | +| `JOBS` | Jobs category. | +| `PACKAGES` | Packages category. | +| `RELEASES` | Releases category. | +| `SECURE_FILES` | Secure files category. | +| `TERRAFORM_STATE` | Terraform state category. | + +### `CiJobTokenScopePolicyTypes` + +CI_JOB_TOKEN policy type. + +| Value | Description | +| ----- | ----------- | +| `ADMIN` | Admin access to the resource. | +| `READ` | Read-only access to the resource. | ### `CiRunnerAccessLevel` diff --git a/doc/api/packages/rubygems.md b/doc/api/packages/rubygems.md index ef38ef5dcb5..f05929f3193 100644 --- a/doc/api/packages/rubygems.md +++ b/doc/api/packages/rubygems.md @@ -94,7 +94,7 @@ curl --header "Authorization:" "https://gitlab.example.co This endpoint returns a marshalled array of hashes for all versions of the requested gems. Since the response is marshalled, you can store it in a file. If Ruby is installed, you can use the following Ruby command to read the response. For this to work, you must -[set your credentials in `~/.gem/credentials`](../../user/packages/rubygems_registry/index.md#authenticate-with-a-personal-access-token-or-deploy-token): +[set your credentials in `~/.gem/credentials`](../../user/packages/rubygems_registry/index.md#authenticate-to-the-package-registry): ```shell $ ruby -ropen-uri -rpp -e \ diff --git a/doc/ci/yaml/artifacts_reports.md b/doc/ci/yaml/artifacts_reports.md index dfd9d5fb54d..1ea7e4bb264 100644 --- a/doc/ci/yaml/artifacts_reports.md +++ b/doc/ci/yaml/artifacts_reports.md @@ -349,7 +349,9 @@ artifact and existing [requirements](../../user/project/requirements/index.md) a GitLab can display the results of one or more reports in the [project requirements](../../user/project/requirements/index.md#view-a-requirement). -## `artifacts:reports:repository_xray` + + +## `artifacts:reports:repository_xray` (deprecated) DETAILS: **Tier:** Premium, Ultimate @@ -358,6 +360,12 @@ DETAILS: The `repository_xray` report collects information about your repository for use by GitLab Duo Code Suggestions. +WARNING: +This feature was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/500146) in GitLab 17.6 +and is planned for removal in 18.0. Use [Enable Repository X-Ray](../../user/project/repository/code_suggestions/repository_xray.md#enable-repository-x-ray) instead. + + + ## `artifacts:reports:sast` The `sast` report collects [SAST vulnerabilities](../../user/application_security/sast/index.md). diff --git a/doc/user/group/settings/group_access_tokens.md b/doc/user/group/settings/group_access_tokens.md index cb004add130..1291089cfd2 100644 --- a/doc/user/group/settings/group_access_tokens.md +++ b/doc/user/group/settings/group_access_tokens.md @@ -123,6 +123,9 @@ If you are an administrator, you can create group access tokens in the Rails con > - Ability to view revoked tokens [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/462217) in GitLab 17.3 [with a flag](../../../administration/feature_flags.md) named `retain_resource_access_token_user_after_revoke`. Disabled by default. +FLAG: +The availability of being able to view revoked tokens is controlled by a feature flag. For more information, see the history. + In GitLab 17.3 and later, if you enable the `retain_resource_access_token_user_after_revoke` feature flag, you can view both active and inactive revoked group access tokens on the access tokens page. If you do not enable the feature flag, you can only view diff --git a/doc/user/packages/rubygems_registry/index.md b/doc/user/packages/rubygems_registry/index.md index e836e67c91a..7b83df1b2ff 100644 --- a/doc/user/packages/rubygems_registry/index.md +++ b/doc/user/packages/rubygems_registry/index.md @@ -11,50 +11,21 @@ DETAILS: **Offering:** GitLab.com, Self-managed, GitLab Dedicated **Status:** Experiment -WARNING: -The Ruby gems package registry for GitLab is under development and isn't ready for production use due to -limited functionality. This [epic](https://gitlab.com/groups/gitlab-org/-/epics/3200) details the remaining -work and timelines to make it production ready. +> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/52147) in GitLab 13.9 [with a flag](../../../administration/feature_flags.md) named `rubygem_packages`. Disabled by default. This feature is an [experiment](../../../policy/experiment-beta-support.md). -You can publish Ruby gems in your project's package registry, then install the packages when you -need to use them as a dependency. Although you can push gems to the registry, you cannot install -them from the registry. However, you can download `gem` files directly from the package registry's -UI, or by using the [API](../../../api/packages/rubygems.md#download-a-gem-file). +FLAG: +The availability of this feature is controlled by a feature flag. +For more information, see the history. +This feature is available for testing, but not ready for production use. -For documentation of the specific API endpoints that the Ruby gems and Bundler package manager -clients use, see the [Ruby gems API documentation](../../../api/packages/rubygems.md). +You can publish Ruby gems to your project's package registry. Then, you can download them from the UI or with the API. -## Enable the Ruby gems registry - -The Ruby gems registry for GitLab is behind a feature flag that is disabled by default. GitLab -administrators with access to the GitLab Rails console can enable this registry for your instance. - -To enable it: - -```ruby -Feature.enable(:rubygem_packages) -``` - -To disable it: - -```ruby -Feature.disable(:rubygem_packages) -``` - -To enable or disable it for specific projects: - -```ruby -Feature.enable(:rubygem_packages, Project.find(1)) -Feature.disable(:rubygem_packages, Project.find(2)) -``` - -## Create a Ruby gem - -If you need help creating a Ruby gem, see the [RubyGems documentation](https://guides.rubygems.org/make-your-own-gem/). +This feature is an [experiment](../../../policy/experiment-beta-support.md). +For more information about the development of this feature, see [epic 3200](https://gitlab.com/groups/gitlab-org/-/epics/3200). ## Authenticate to the package registry -Before you can push to the package registry, you must authenticate. +Before you can interact with the package registry, you must authenticate to it. To do this, you can use: @@ -62,89 +33,109 @@ To do this, you can use: with the scope set to `api`. - A [deploy token](../../project/deploy_tokens/index.md) with the scope set to `read_package_registry`, `write_package_registry`, or both. -- A [CI job token](#authenticate-with-a-ci-job-token). - -### Authenticate with a personal access token or deploy token - -To authenticate with a personal access token, create or edit the `~/.gem/credentials` file and add: - -```ini ---- -https://gitlab.example.com/api/v4/projects//packages/rubygems: '' -``` - -- `` must be the token value of either your personal access token or deploy token. -- Your project ID is displayed on the [project overview page](../../project/working_with_projects.md#access-a-project-by-using-the-project-id). - -### Authenticate with a CI job token - -To work with RubyGems commands within [GitLab CI/CD](../../../ci/index.md), -you can use the [`CI_JOB_TOKEN`](../../../ci/jobs/ci_job_token.md) predefined environment variable instead of a personal access token or deploy token. +- A [CI/CD job token](../../../ci/jobs/ci_job_token.md). For example: -```yaml -# assuming a my_gem.gemspec file is present in the repository with the version currently set to 0.0.1 -image: ruby +::Tabs -run: - before_script: - - mkdir ~/.gem - - echo "---" > ~/.gem/credentials - - | - echo "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/rubygems: '${CI_JOB_TOKEN}'" >> ~/.gem/credentials - - chmod 0600 ~/.gem/credentials # rubygems requires 0600 permissions on the credentials file - script: - - gem build my_gem - - gem push my_gem-0.0.1.gem --host ${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/rubygems -``` +:::TabTitle With an access token -You can also use `CI_JOB_TOKEN` in a `~/.gem/credentials` file that you check in to -GitLab: +To authenticate with an access token: -```ini ---- -https://gitlab.example.com/api/v4/projects/${env.CI_PROJECT_ID}/packages/rubygems: '${env.CI_JOB_TOKEN}' -``` +- Create or edit your `~/.gem/credentials` file, and add: + + ```ini + --- + https://gitlab.example.com/api/v4/projects//packages/rubygems: '' + ``` + +In this example: + +- `` must be the token value of either your personal access token or deploy token. +- `` is displayed on the [project overview page](../../project/working_with_projects.md#access-a-project-by-using-the-project-id). + +:::TabTitle With a CI/CD job token + +To authenticate with a CI/CD job token: + +- Create or edit your `.gitlab-ci.yml` file, and add: + + ```yaml + # assuming a my_gem.gemspec file is present in the repository with the version currently set to 0.0.1 + image: ruby + + run: + before_script: + - mkdir ~/.gem + - echo "---" > ~/.gem/credentials + - | + echo "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/rubygems: '${CI_JOB_TOKEN}'" >> ~/.gem/credentials + - chmod 0600 ~/.gem/credentials # rubygems requires 0600 permissions on the credentials file + script: + - gem build my_gem + - gem push my_gem-0.0.1.gem --host ${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/rubygems + ``` + + You can also use `CI_JOB_TOKEN` in a `~/.gem/credentials` file you check in to GitLab: + + ```ini + --- + https://gitlab.example.com/api/v4/projects/${env.CI_PROJECT_ID}/packages/rubygems: '${env.CI_JOB_TOKEN}' + ``` + +::EndTabs ## Push a Ruby gem Prerequisites: - You must [authenticate to the package registry](#authenticate-to-the-package-registry). -- The maximum allowed gem size is 3 GB. +- Your Ruby gem must be 3 GB or less. -To push your gem, run a command like this one: +To do this: -```shell -gem push my_gem-0.0.1.gem --host -``` +- Run a command like: -`` is the URL you used when setting up authentication. For example: + ```shell + gem push my_gem-0.0.1.gem --host + ``` -```shell -gem push my_gem-0.0.1.gem --host https://gitlab.example.com/api/v4/projects/1/packages/rubygems -``` + In this example, `` is the URL you used when setting up authentication. For example: -This message indicates that the gem uploaded successfully: + ```shell + gem push my_gem-0.0.1.gem --host https://gitlab.example.com/api/v4/projects/1/packages/rubygems + ``` + +When a gem is published successfully, a message like this is displayed: ```plaintext Pushing gem to https://gitlab.example.com/api/v4/projects/1/packages/rubygems... {"message":"201 Created"} ``` -To view the published gem, go to your project's **Packages and registries** page. Gems pushed to -GitLab aren't displayed in your project's Packages UI immediately. It can take up to 10 minutes to -process a gem. +The gem is published to your package registry, and is shown on the **Packages and registries** page. +It can take up to 10 minutes before GitLab processes and displays your gem. ### Pushing gems with the same name or version You can push a gem if a package of the same name and version already exists. -Both are visible and accessible in the UI. However, only the most recently -pushed gem is used for installs. +Both are visible and accessible in the UI. -## Install a Ruby gem +## Download gems -The Ruby gems registry for GitLab is under development, and isn't ready for production use. You -cannot install Gems from the registry. However, you can download `.gem` files directly from the UI -or by using the [API](../../../api/packages/rubygems.md#download-a-gem-file). +You can't install Ruby gems from the GitLab package registry. However, you can download gem files for local use. + +To do this: + +1. On the left sidebar, select **Search or go to** and find your project. +1. Select **Deploy > Package registry**. +1. Select the package name and version. +1. Under **Assets**, select the Ruby gem you want to download. + +To download Ruby gems, you can also [use the API](../../../api/packages/rubygems.md#download-a-gem-file). + +## Related topics + +- [Make your own gem](https://guides.rubygems.org/make-your-own-gem/) +- [Ruby gems API documentation](../../../api/packages/rubygems.md) diff --git a/doc/user/project/merge_requests/status_checks.md b/doc/user/project/merge_requests/status_checks.md index 011ae2a5207..ea70f090393 100644 --- a/doc/user/project/merge_requests/status_checks.md +++ b/doc/user/project/merge_requests/status_checks.md @@ -21,8 +21,8 @@ can then update the status of merge requests from outside of GitLab. With this integration, you can integrate with third-party workflow tools, like ServiceNow, or the custom tool of your choice. The third-party tool -respond with an associated status. This status is then displayed as a non-blocking -widget within the merge request to surface this status to the merge request author or reviewers +responds with an associated status. This status is then displayed as a non-blocking +widget within the merge request, which surfaces this status to the merge request author or reviewers at the merge request level itself. You can configure merge request status checks for each individual project. These are not shared between projects. diff --git a/doc/user/project/settings/project_access_tokens.md b/doc/user/project/settings/project_access_tokens.md index 4e12b16a658..beaf27cfc56 100644 --- a/doc/user/project/settings/project_access_tokens.md +++ b/doc/user/project/settings/project_access_tokens.md @@ -77,6 +77,9 @@ all projects that have visibility level set to [Internal](../../public_access.md > - Ability to view revoked tokens [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/462217) in GitLab 17.3 [with a flag](../../../administration/feature_flags.md) named `retain_resource_access_token_user_after_revoke`. Disabled by default. +FLAG: +The availability of being able to view revoked tokens is controlled by a feature flag. For more information, see the history. + To revoke a project access token: 1. On the left sidebar, select **Search or go to** and find your project. diff --git a/eslint.config.mjs b/eslint.config.mjs index 8b2a368cb68..feb73d8cee5 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -1,14 +1,12 @@ /* eslint-disable import/no-default-export */ import path from 'node:path'; -import { fileURLToPath } from 'node:url'; import { existsSync } from 'node:fs'; import localRules from 'eslint-plugin-local-rules'; import js from '@eslint/js'; import { FlatCompat } from '@eslint/eslintrc'; import * as graphqlEslint from '@graphql-eslint/eslint-plugin'; -const filename = fileURLToPath(import.meta.url); -const dirname = path.dirname(filename); +const { dirname } = import.meta; const compat = new FlatCompat({ baseDirectory: dirname, recommendedConfig: js.configs.recommended, @@ -545,6 +543,7 @@ export default [ rules: { '@gitlab/require-i18n-strings': 'off', + 'import/extensions': 'off', 'import/no-extraneous-dependencies': 'off', 'import/no-commonjs': 'off', 'import/no-nodejs-modules': 'off', diff --git a/lib/ci/job_token/policies.rb b/lib/ci/job_token/policies.rb index b48926cd755..c746e20fdd3 100644 --- a/lib/ci/job_token/policies.rb +++ b/lib/ci/job_token/policies.rb @@ -3,52 +3,124 @@ module Ci module JobToken module Policies - # policies that every CI job token needs - FIXED = [ - :build_create_container_image, - :build_destroy_container_image, - :build_download_code, - :build_push_code, - :build_read_container_image, - :read_project - ].freeze - - # policies that can be assigned to a CI job token - ALLOWED = [ - :admin_container_image, - :admin_secure_files, - :admin_terraform_state, - :create_deployment, - :create_environment, - :create_on_demand_dast_scan, - :create_package, - :create_release, - :destroy_container_image, - :destroy_deployment, - :destroy_environment, - :destroy_package, - :destroy_release, - :read_build, - :read_container_image, - :read_deployment, - :read_environment, - :read_group, - :read_job_artifacts, - :read_package, - :read_pipeline, - :read_release, - :read_secure_files, - :read_terraform_state, - :stop_environment, - :update_deployment, - :update_environment, - :update_pipeline, - :update_release + POLICIES_BY_CATEGORY = [ + { + value: :containers, + text: 'Containers', + description: 'Containers category', + policies: [ + { + value: :read_containers, + type: :read, + text: 'Read', + description: 'Read container images in a project' + }, + { + value: :admin_containers, + type: :admin, + text: 'Read and write', + description: 'Admin container images in a project' + } + ] + }, + { + value: :deployments, + text: 'Deployments', + description: 'Deployments category', + policies: [ + { value: :read_deployments, type: :read, text: 'Read', description: 'Read deployments in a project' }, + { + value: :admin_deployments, + type: :admin, + text: 'Read and write', + description: 'Admin deployments in a project' + } + ] + }, + { + value: :environments, + text: 'Environments', + description: 'Environments category', + policies: [ + { value: :read_environments, type: :read, text: 'Read', description: 'Read environments in a project' }, + { + value: :admin_environments, + type: :admin, + text: 'Read and write', + description: 'Admin + Stop environments in a project' + } + ] + }, + { + value: :jobs, + text: 'Jobs', + description: 'Jobs category', + policies: [ + { value: :read_jobs, type: :read, text: 'Read', description: 'Read job metadata and artifacts' }, + { + value: :admin_jobs, + type: :admin, + text: 'Read and write', + description: 'Read job metadata, upload artifacts and update the pipeline status' + } + ] + }, + { + value: :packages, + text: 'Packages', + description: 'Packages category', + policies: [ + { value: :read_packages, type: :read, text: 'Read', description: 'Read packages' }, + { value: :admin_packages, type: :admin, text: 'Read and write', description: 'Admin packages' } + ] + }, + { + value: :releases, + text: 'Releases', + description: 'Releases category', + policies: [ + { value: :read_releases, type: :read, text: 'Read', description: 'Read releases in a project' }, + { value: :admin_releases, type: :admin, text: 'Read and write', description: 'Admin releases in a project' } + ] + }, + { + value: :secure_files, + text: 'Secure files', + description: 'Secure files category', + policies: [ + { value: :read_secure_files, type: :read, text: 'Read', description: 'Read secure files in a project' }, + { + value: :admin_secure_files, + type: :admin, + text: 'Read and write', + description: 'Admin secure files in a project' + } + ] + }, + { + value: :terraform_state, + text: 'Terraform state', + description: 'Terraform state category', + policies: [ + { + value: :read_terraform_state, + type: :read, + text: 'Read', + description: 'Read terraform state files/version' + }, + { + value: :admin_terraform_state, + type: :admin, + text: 'Read and write', + description: 'Admin terraform state files/versions' + } + ] + } ].freeze class << self - def all_values - (FIXED + ALLOWED).map(&:to_s) + def all_policies + POLICIES_BY_CATEGORY.flat_map { |category| category[:policies] } end end end diff --git a/lib/gitlab/background_migration/backfill_group_wiki_repository_states_group_id.rb b/lib/gitlab/background_migration/backfill_group_wiki_repository_states_group_id.rb new file mode 100644 index 00000000000..44ddc366304 --- /dev/null +++ b/lib/gitlab/background_migration/backfill_group_wiki_repository_states_group_id.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +module Gitlab + module BackgroundMigration + class BackfillGroupWikiRepositoryStatesGroupId < BackfillDesiredShardingKeyJob + operation_name :backfill_group_wiki_repository_states_group_id + feature_category :geo_replication + + # override as parent table primary key is group_id + def backfill_via_table_primary_key + 'group_id' + end + end + end +end diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 25367034103..d5247be4e3a 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -36782,9 +36782,6 @@ msgstr "" msgid "Notes|Internal notes are only visible to members with the role of Planner or higher" msgstr "" -msgid "Notes|Internal notes are only visible to members with the role of Reporter or higher" -msgstr "" - msgid "Notes|Last reply by %{name}" msgstr "" diff --git a/qa/qa/specs/features/browser_ui/5_package/package_registry/maven/maven_group_level_spec.rb b/qa/qa/specs/features/browser_ui/5_package/package_registry/maven/maven_group_level_spec.rb index cf5d5eedcf0..ad49758f62d 100644 --- a/qa/qa/specs/features/browser_ui/5_package/package_registry/maven/maven_group_level_spec.rb +++ b/qa/qa/specs/features/browser_ui/5_package/package_registry/maven/maven_group_level_spec.rb @@ -129,7 +129,7 @@ module QA Page::Group::Settings::PackageRegistries.perform(&:set_allow_duplicates_disabled) end - it 'prevents users from publishing duplicates', + it 'prevents users from publishing duplicates', :blocking, testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/377491' do create_package(package_project) package_project.visit_job('deploy') diff --git a/scripts/frontend/build_css.mjs b/scripts/frontend/build_css.mjs index bc07362c3f9..9e786146f2c 100755 --- a/scripts/frontend/build_css.mjs +++ b/scripts/frontend/build_css.mjs @@ -1,9 +1,7 @@ #!/usr/bin/env node import process from 'node:process'; -/* eslint-disable import/extensions */ import { compileAllStyles } from './lib/compile_css.mjs'; -/* eslint-enable import/extensions */ const fileWatcher = await compileAllStyles({ shouldWatch: process.argv?.includes('--watch') }); diff --git a/scripts/frontend/find_frontend_files.mjs b/scripts/frontend/find_frontend_files.mjs index e469076e499..dc45930437c 100755 --- a/scripts/frontend/find_frontend_files.mjs +++ b/scripts/frontend/find_frontend_files.mjs @@ -1,13 +1,12 @@ #!/usr/bin/env node -import { relative, dirname, resolve } from 'node:path'; -import { fileURLToPath } from 'node:url'; +import { relative, resolve } from 'node:path'; import Runtime from 'jest-runtime'; import { readConfig } from 'jest-config'; -import createJestConfig from '../../jest.config.base'; +import createJestConfig from '../../jest.config.base.js'; -const ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '../../'); +const ROOT = resolve(import.meta.dirname, '../../'); function resolveDependenciesRecursively(context, target, seen) { const dependencies = context.hasteFS.getDependencies(target); diff --git a/scripts/frontend/lib/compile_css.mjs b/scripts/frontend/lib/compile_css.mjs index 092bd2a3ba6..cccd77be07f 100644 --- a/scripts/frontend/lib/compile_css.mjs +++ b/scripts/frontend/lib/compile_css.mjs @@ -7,16 +7,13 @@ import postcssCustomProperties from 'postcss-custom-properties'; import postcssGlobalData from '@csstools/postcss-global-data'; import { compile, Logger } from 'sass'; import glob from 'glob'; -/* eslint-disable import/extensions */ import tailwindcss from 'tailwindcss/lib/plugin.js'; import tailwindConfig from '../../../config/tailwind.config.js'; import IS_EE from '../../../config/helpers/is_ee_env.js'; import IS_JH from '../../../config/helpers/is_jh_env.js'; import { postCssColorToHex } from './postcss_color_to_hex.js'; -/* eslint-enable import/extensions */ -// Note, in node > 21.2 we could replace the below with import.meta.dirname -const ROOT_PATH = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../../../'); +const ROOT_PATH = path.resolve(import.meta.dirname, '../../../'); const OUTPUT_PATH = path.join(ROOT_PATH, 'app/assets/builds/'); const BASE_PATH = 'app/assets/stylesheets'; diff --git a/scripts/frontend/preinstall.mjs b/scripts/frontend/preinstall.mjs index 80e85bf226a..e86525cd20d 100644 --- a/scripts/frontend/preinstall.mjs +++ b/scripts/frontend/preinstall.mjs @@ -1,8 +1,7 @@ -import { dirname, join } from 'node:path'; -import { fileURLToPath } from 'node:url'; +import { join } from 'node:path'; import { readFile, rm } from 'node:fs/promises'; -const ROOT_PATH = join(dirname(fileURLToPath(import.meta.url)), '..', '..'); +const ROOT_PATH = join(import.meta.dirname, '..', '..'); const NODE_MODULES = join(ROOT_PATH, 'node_modules'); const INTEGRITY_FILE = join(NODE_MODULES, '.yarn-integrity'); const PACKAGE_JSON = join(ROOT_PATH, 'package.json'); diff --git a/scripts/frontend/tailwindcss.mjs b/scripts/frontend/tailwindcss.mjs index 2ce7e43d5ff..1c4486343d0 100644 --- a/scripts/frontend/tailwindcss.mjs +++ b/scripts/frontend/tailwindcss.mjs @@ -1,10 +1,7 @@ -/* eslint-disable import/extensions */ import path from 'node:path'; -import { fileURLToPath } from 'node:url'; import { createProcessor } from 'tailwindcss/lib/cli/build/plugin.js'; -// Note, in node > 21.2 we could replace the below with import.meta.dirname -const ROOT_PATH = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../../'); +const ROOT_PATH = path.resolve(import.meta.dirname, '../../'); export async function build({ shouldWatch = false, content = false } = {}) { const processorOptions = { @@ -38,7 +35,7 @@ export async function build({ shouldWatch = false, content = false } = {}) { } function wasScriptCalledDirectly() { - return process.argv[1] === fileURLToPath(import.meta.url); + return process.argv[1] === import.meta.filename; } export function viteTailwindCompilerPlugin({ shouldWatch = true }) { diff --git a/scripts/frontend/webpack_dev_server.js b/scripts/frontend/webpack_dev_server.js index fffae83b308..d94de795caa 100755 --- a/scripts/frontend/webpack_dev_server.js +++ b/scripts/frontend/webpack_dev_server.js @@ -58,7 +58,7 @@ nodemon console.log('The JavaScript assets are recompiled only if they change'); console.log('If you change them often, you might want to unset DEV_SERVER_STATIC'); } - /* eslint-disable import/extensions, promise/catch-or-return */ + /* eslint-disable promise/catch-or-return */ import('./lib/compile_css.mjs').then(({ simplePluginForNodemon }) => { plugin = simplePluginForNodemon({ shouldWatch: !STATIC_MODE }); return plugin?.start(); @@ -67,7 +67,7 @@ nodemon plugin = webpackTailwindCompilerPlugin({ shouldWatch: !STATIC_MODE }); return plugin?.start(); }); - /* eslint-enable import/extensions, promise/catch-or-return */ + /* eslint-enable promise/catch-or-return */ }) .on('quit', () => { console.log('Shutting down CSS compilation process'); diff --git a/scripts/rspec_helpers.sh b/scripts/rspec_helpers.sh index 0181a9df7f3..4ba2379c42a 100644 --- a/scripts/rspec_helpers.sh +++ b/scripts/rspec_helpers.sh @@ -158,31 +158,31 @@ function debug_rspec_variables() { function handle_retry_rspec_in_new_process() { local rspec_run_status="${1}" local rspec_retry_status=0 - local auto_retry_status=1 + local known_flaky_tests_exit_code=1 if [[ $rspec_run_status -eq 3 ]]; then echoerr "Not retrying failing examples since we failed early on purpose!" - auto_retry_exit_code_if_known_flaky_tests || auto_retry_status=$? - exit "${auto_retry_status}" + change_exit_code_if_known_flaky_tests || known_flaky_tests_exit_code=$? + exit "${known_flaky_tests_exit_code}" fi if [[ $rspec_run_status -eq 2 ]]; then echoerr "Not retrying failing examples since there were errors happening outside of the RSpec examples!" - auto_retry_exit_code_if_known_flaky_tests || auto_retry_status=$? - exit "${auto_retry_status}" + change_exit_code_if_known_flaky_tests || known_flaky_tests_exit_code=$? + exit "${known_flaky_tests_exit_code}" fi if [[ $rspec_run_status -eq 1 ]]; then if is_rspec_last_run_results_file_missing; then - auto_retry_exit_code_if_known_flaky_tests || auto_retry_status=$? - exit "${auto_retry_status}" + change_exit_code_if_known_flaky_tests || known_flaky_tests_exit_code=$? + exit "${known_flaky_tests_exit_code}" fi local failed_examples_count=$(grep -c " failed" "${RSPEC_LAST_RUN_RESULTS_FILE}") if [[ "${failed_examples_count}" -eq "${RSPEC_FAIL_FAST_THRESHOLD}" ]]; then echoerr "Not retrying failing examples since we reached the maximum number of allowed test failures!" - auto_retry_exit_code_if_known_flaky_tests || auto_retry_status=$? - exit "${auto_retry_status}" + change_exit_code_if_known_flaky_tests || known_flaky_tests_exit_code=$? + exit "${known_flaky_tests_exit_code}" fi retry_failed_rspec_examples || rspec_retry_status=$? @@ -198,22 +198,17 @@ function handle_retry_rspec_in_new_process() { # At this stage, we know the CI/CD job will fail. # - # We'll change the exit code to auto-retry the CI job if the failure was due to a known flaky test. - auto_retry_exit_code_if_known_flaky_tests || auto_retry_status=$? - exit "${auto_retry_status}" + # We'll change the exit code of the CI job if the failure was due to a known flaky test. + change_exit_code_if_known_flaky_tests || known_flaky_tests_exit_code=$? + exit "${known_flaky_tests_exit_code}" } -function auto_retry_exit_code_if_known_flaky_tests() { +function change_exit_code_if_known_flaky_tests() { # Default exit status - rspec_retry_status=1 - - if [[ "${CI_AUTO_RETRY_JOBS_WITH_FLAKY_TESTS_ENABLED}" != "true" ]]; then - echoinfo "INFO: auto-retry of CI/CD job that failed due to a known flaky test is disabled because CI_AUTO_RETRY_JOBS_WITH_FLAKY_TESTS_ENABLED=${CI_AUTO_RETRY_JOBS_WITH_FLAKY_TESTS_ENABLED}." - return "${rspec_retry_status}" - fi + new_exit_code=1 echo "*******************************************************" - echo "Retry CI job if known flaky tests failed the job" + echo "Checking whether known flaky tests failed the job" echo "*******************************************************" found_known_flaky_tests_status=0 @@ -222,34 +217,15 @@ function auto_retry_exit_code_if_known_flaky_tests() { echo "${found_known_flaky_tests_output}" if [[ $found_known_flaky_tests_status -eq 0 ]]; then echo - echo "We'll ensure this CI/CD job is auto-retried (i.e. setting exit code: 112)." + echo "Changing the CI/CD job exit code to 112." - if [[ "${CI_AUTO_RETRY_JOBS_WITH_FLAKY_TESTS_NOTIFICATIONS_ENABLED}" == "true" ]]; then - comment=$(cat <<-EOF -Job ${CI_JOB_NAME} (${CI_JOB_URL}, ${CI_PIPELINE_URL}) failed because of a flaky test, and was auto-retried. - -${found_known_flaky_tests_output} -EOF - ) - - echo - echo "Reporting to https://gitlab.com/gitlab-org/quality/engineering-productivity/team/-/issues/573 (project id: 34408484)" - new_comment_in_issue \ - "34408484" \ - "573" \ - "${comment}" || true - fi - - # Exit code for auto-retrying a job that had known flaky tests in it - # - # See .gitlab/ci/global.gitlab-ci.yml for the list of custom exit codes we use to auto-retry jobs - rspec_retry_status=112 + new_exit_code=112 else echo echo "Not changing the CI/CD job exit code." fi - return "${rspec_retry_status}" + return "${new_exit_code}" } function found_known_flaky_tests() { @@ -265,18 +241,6 @@ function found_known_flaky_tests() { --health-problem-type failures; } -function new_comment_in_issue() { - local project_id="${1}" - local issue_id="${2}" - local body="${3}" - - curl --silent -o /dev/null --request POST \ - --header "PRIVATE-TOKEN: ${TEST_FAILURES_PROJECT_TOKEN}" \ - --header "Content-Type: application/x-www-form-urlencoded" \ - --data "body=${body}" \ - "${CI_API_V4_URL}/projects/${project_id}/issues/${issue_id}/notes" || true -} - function rspec_parallelized_job() { echo "[$(date '+%H:%M:%S')] Starting rspec_parallelized_job" diff --git a/spec/frontend/notes/components/comment_form_spec.js b/spec/frontend/notes/components/comment_form_spec.js index 4207ec50e48..71037750bce 100644 --- a/spec/frontend/notes/components/comment_form_spec.js +++ b/spec/frontend/notes/components/comment_form_spec.js @@ -53,6 +53,7 @@ describe('issue_comment_form component', () => { const findAddToReviewButton = () => findAddToReviewDropdown().find('button'); const findAddCommentNowButton = () => wrapper.findByTestId('add-comment-now-button'); const findConfidentialNoteCheckbox = () => wrapper.findByTestId('internal-note-checkbox'); + const findInternalNoteTooltipIcon = () => wrapper.findByTestId('question-o-icon'); const findCommentTypeDropdown = () => wrapper.findByTestId('comment-button'); const findCommentButton = () => findCommentTypeDropdown().find('button'); const findErrorAlerts = () => wrapper.findAllComponents(GlAlert).wrappers; @@ -716,7 +717,7 @@ describe('issue_comment_form component', () => { expect(findConfidentialNoteCheckbox().exists()).toBe(true); }); - it('should not render checkbox if user is not at least a reporter', () => { + it('should not render checkbox if user is not at least a planner', () => { mountComponent({ mountFunction: mountExtended, initialData: { note: 'confidential note' }, @@ -727,6 +728,18 @@ describe('issue_comment_form component', () => { expect(checkbox.exists()).toBe(false); }); + it('should have the tooltip explaining the internal note capabilities', () => { + mountComponent({ + mountFunction: mountExtended, + initialData: { note: 'confidential note' }, + noteableData: { ...notableDataMockCanUpdateIssuable }, + }); + + const tooltip = findInternalNoteTooltipIcon(); + expect(tooltip.exists()).toBe(true); + expect(tooltip.attributes('title')).toBe(COMMENT_FORM.internalVisibility); + }); + it.each` noteableType | rendered | message ${'Issue'} | ${true} | ${'render'} diff --git a/spec/graphql/mutations/ci/job_token_scope/add_group_or_project_spec.rb b/spec/graphql/mutations/ci/job_token_scope/add_group_or_project_spec.rb index fa2a14f3008..86385bfcd0c 100644 --- a/spec/graphql/mutations/ci/job_token_scope/add_group_or_project_spec.rb +++ b/spec/graphql/mutations/ci/job_token_scope/add_group_or_project_spec.rb @@ -36,7 +36,7 @@ RSpec.describe Mutations::Ci::JobTokenScope::AddGroupOrProject, feature_category let_it_be(:target_project) { create(:project) } let_it_be(:target_project_path) { target_project.full_path } - let(:policies) { %w[read_project read_package] } + let(:policies) { %w[read_containers read_packages] } let(:mutation_args) do { project_path: project.full_path, target_path: target_project_path, job_token_policies: policies } @@ -96,7 +96,7 @@ RSpec.describe Mutations::Ci::JobTokenScope::AddGroupOrProject, feature_category let_it_be(:target_group) { create(:group, :private) } let_it_be(:target_group_path) { target_group.full_path } - let(:policies) { %w[read_project read_package] } + let(:policies) { %w[read_containers read_packages] } let(:mutation_args) do { project_path: project.full_path, target_path: target_group_path, job_token_policies: policies } diff --git a/spec/graphql/types/ci/job_token_scope/job_token_policy_category_type_spec.rb b/spec/graphql/types/ci/job_token_scope/job_token_policy_category_type_spec.rb new file mode 100644 index 00000000000..80be69d715b --- /dev/null +++ b/spec/graphql/types/ci/job_token_scope/job_token_policy_category_type_spec.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe ::Types::Ci::JobTokenScope::JobTokenPolicyCategoryType, feature_category: :secrets_management do + specify { expect(described_class.graphql_name).to eq('JobTokenPolicyCategory') } + specify { expect(described_class).to have_graphql_fields(%i[text value description policies]) } +end diff --git a/spec/graphql/types/ci/job_token_scope/job_token_policy_type_spec.rb b/spec/graphql/types/ci/job_token_scope/job_token_policy_type_spec.rb new file mode 100644 index 00000000000..717ea0753b2 --- /dev/null +++ b/spec/graphql/types/ci/job_token_scope/job_token_policy_type_spec.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe ::Types::Ci::JobTokenScope::JobTokenPolicyType, feature_category: :secrets_management do + specify { expect(described_class.graphql_name).to eq('JobTokenPolicy') } + specify { expect(described_class).to have_graphql_fields(%i[text value type description]) } +end diff --git a/spec/graphql/types/ci/job_token_scope/policies_enum_spec.rb b/spec/graphql/types/ci/job_token_scope/policies_enum_spec.rb index 17e56e7f5d2..1dd215a1807 100644 --- a/spec/graphql/types/ci/job_token_scope/policies_enum_spec.rb +++ b/spec/graphql/types/ci/job_token_scope/policies_enum_spec.rb @@ -2,44 +2,25 @@ require 'spec_helper' -RSpec.describe GitlabSchema.types['CiJobTokenScopePolicies'], feature_category: :secrets_management do +RSpec.describe ::Types::Ci::JobTokenScope::PoliciesEnum, feature_category: :secrets_management do it 'exposes all policies' do - expect(described_class.values.keys).to contain_exactly(*%w[ - ADMIN_CONTAINER_IMAGE - ADMIN_SECURE_FILES - ADMIN_TERRAFORM_STATE - BUILD_CREATE_CONTAINER_IMAGE - BUILD_DESTROY_CONTAINER_IMAGE - BUILD_DOWNLOAD_CODE - BUILD_PUSH_CODE - BUILD_READ_CONTAINER_IMAGE - CREATE_DEPLOYMENT - CREATE_ENVIRONMENT - CREATE_ON_DEMAND_DAST_SCAN - CREATE_PACKAGE - CREATE_RELEASE - DESTROY_CONTAINER_IMAGE - DESTROY_DEPLOYMENT - DESTROY_ENVIRONMENT - DESTROY_PACKAGE - DESTROY_RELEASE - READ_BUILD - READ_CONTAINER_IMAGE - READ_DEPLOYMENT - READ_ENVIRONMENT - READ_GROUP - READ_JOB_ARTIFACTS - READ_PACKAGE - READ_PIPELINE - READ_PROJECT - READ_RELEASE + expect(described_class.values.keys).to match_array(%w[ + READ_CONTAINERS + ADMIN_CONTAINERS + READ_DEPLOYMENTS + ADMIN_DEPLOYMENTS + READ_ENVIRONMENTS + ADMIN_ENVIRONMENTS + READ_JOBS + ADMIN_JOBS + READ_PACKAGES + ADMIN_PACKAGES + READ_RELEASES + ADMIN_RELEASES READ_SECURE_FILES + ADMIN_SECURE_FILES READ_TERRAFORM_STATE - STOP_ENVIRONMENT - UPDATE_DEPLOYMENT - UPDATE_ENVIRONMENT - UPDATE_PIPELINE - UPDATE_RELEASE + ADMIN_TERRAFORM_STATE ]) end end diff --git a/spec/graphql/types/ci/job_token_scope/policy_categories_enum_spec.rb b/spec/graphql/types/ci/job_token_scope/policy_categories_enum_spec.rb new file mode 100644 index 00000000000..41662543111 --- /dev/null +++ b/spec/graphql/types/ci/job_token_scope/policy_categories_enum_spec.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe ::Types::Ci::JobTokenScope::PolicyCategoriesEnum, feature_category: :secrets_management do + it 'exposes all categories' do + expect(described_class.values.keys).to match_array(%w[ + CONTAINERS + DEPLOYMENTS + ENVIRONMENTS + JOBS + PACKAGES + RELEASES + SECURE_FILES + TERRAFORM_STATE + ]) + end +end diff --git a/spec/graphql/types/ci/job_token_scope/policy_types_enum_spec.rb b/spec/graphql/types/ci/job_token_scope/policy_types_enum_spec.rb new file mode 100644 index 00000000000..171d7ddac6e --- /dev/null +++ b/spec/graphql/types/ci/job_token_scope/policy_types_enum_spec.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe ::Types::Ci::JobTokenScope::PolicyTypesEnum, feature_category: :secrets_management do + it 'the correct enum members' do + expect(described_class.values).to match( + 'READ' => have_attributes(value: :read, description: 'Read-only access to the resource.'), + 'ADMIN' => have_attributes(value: :admin, description: 'Admin access to the resource.') + ) + end +end diff --git a/spec/graphql/types/query_type_spec.rb b/spec/graphql/types/query_type_spec.rb index 74e9522c16c..3d4ea44fa3d 100644 --- a/spec/graphql/types/query_type_spec.rb +++ b/spec/graphql/types/query_type_spec.rb @@ -177,4 +177,48 @@ RSpec.describe GitlabSchema.types['Query'], feature_category: :shared do is_expected.to have_graphql_resolver(Resolvers::FeatureFlagResolver) end end + + describe 'jobTokenPoliciesByCategory field' do + subject { described_class.fields['jobTokenPoliciesByCategory'] } + + it 'returns job token policies', :aggregate_failures do + is_expected.to have_graphql_type(::Types::Ci::JobTokenScope::JobTokenPolicyCategoryType) + + query = <<~GRAPHQL + query { + jobTokenPoliciesByCategory { + text + value + description + policies { + text + value + description + type + } + } + } + GRAPHQL + + expected_result = ::Ci::JobToken::Policies::POLICIES_BY_CATEGORY.map do |category| + { + 'text' => category[:text], + 'value' => category[:value].upcase, + 'description' => category[:description], + 'policies' => category[:policies].map do |policy| + { + 'text' => policy[:text], + 'value' => policy[:value].upcase, + 'description' => policy[:description], + 'type' => policy[:type].upcase + } + end + } + end + + result = GitlabSchema.execute(query).as_json.dig('data', 'jobTokenPoliciesByCategory') + + expect(result).to eq(expected_result.as_json) + end + end end diff --git a/spec/helpers/projects_helper_spec.rb b/spec/helpers/projects_helper_spec.rb index 1b5ae6eddc6..ebdc8a987d7 100644 --- a/spec/helpers/projects_helper_spec.rb +++ b/spec/helpers/projects_helper_spec.rb @@ -903,6 +903,14 @@ RSpec.describe ProjectsHelper, feature_category: :source_code_management do it { is_expected.to be_falsey } end + + context 'when lfs_misconfiguration_banner feature flag is disabled' do + before do + stub_feature_flags(lfs_misconfiguration_banner: false) + end + + it { is_expected.to be_falsey } + end end context 'when it does have a .gitattributes file' do diff --git a/spec/lib/gitlab/background_migration/backfill_group_wiki_repository_states_group_id_spec.rb b/spec/lib/gitlab/background_migration/backfill_group_wiki_repository_states_group_id_spec.rb new file mode 100644 index 00000000000..80e58434ad5 --- /dev/null +++ b/spec/lib/gitlab/background_migration/backfill_group_wiki_repository_states_group_id_spec.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Gitlab::BackgroundMigration::BackfillGroupWikiRepositoryStatesGroupId, + feature_category: :geo_replication, + schema: 20241125133011 do + include_examples 'desired sharding key backfill job' do + let(:batch_table) { :group_wiki_repository_states } + let(:backfill_column) { :group_id } + let(:backfill_via_table) { :group_wiki_repositories } + let(:backfill_via_column) { :group_id } + let(:backfill_via_foreign_key) { :group_wiki_repository_id } + end +end diff --git a/spec/migrations/20241125133627_queue_backfill_group_wiki_repository_states_group_id_spec.rb b/spec/migrations/20241125133627_queue_backfill_group_wiki_repository_states_group_id_spec.rb new file mode 100644 index 00000000000..067755bd33a --- /dev/null +++ b/spec/migrations/20241125133627_queue_backfill_group_wiki_repository_states_group_id_spec.rb @@ -0,0 +1,33 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe QueueBackfillGroupWikiRepositoryStatesGroupId, feature_category: :geo_replication do + let!(:batched_migration) { described_class::MIGRATION } + + it 'schedules a new batched migration' do + reversible_migration do |migration| + migration.before -> { + expect(batched_migration).not_to have_scheduled_batched_migration + } + + migration.after -> { + expect(batched_migration).to have_scheduled_batched_migration( + table_name: :group_wiki_repository_states, + column_name: :id, + interval: described_class::DELAY_INTERVAL, + batch_size: described_class::BATCH_SIZE, + sub_batch_size: described_class::SUB_BATCH_SIZE, + gitlab_schema: :gitlab_main_cell, + job_arguments: [ + :group_id, + :group_wiki_repositories, + :group_id, + :group_wiki_repository_id + ] + ) + } + end + end +end diff --git a/spec/models/ci/job_token/allowlist_spec.rb b/spec/models/ci/job_token/allowlist_spec.rb index babefc7c96e..dfab57ff806 100644 --- a/spec/models/ci/job_token/allowlist_spec.rb +++ b/spec/models/ci/job_token/allowlist_spec.rb @@ -67,7 +67,7 @@ RSpec.describe Ci::JobToken::Allowlist, feature_category: :continuous_integratio describe 'add!' do let_it_be(:added_project) { create(:project) } let_it_be(:user) { create(:user) } - let_it_be(:policies) { %w[read_package read_project] } + let_it_be(:policies) { %w[read_containers read_packages] } subject(:add_project) { allowlist.add!(added_project, policies: policies, user: user) } @@ -107,7 +107,7 @@ RSpec.describe Ci::JobToken::Allowlist, feature_category: :continuous_integratio describe 'add_group!' do let_it_be(:added_group) { create(:group) } let_it_be(:user) { create(:user) } - let_it_be(:policies) { %w[read_package read_project] } + let_it_be(:policies) { %w[read_containers read_packages] } subject(:add_group) { allowlist.add_group!(added_group, policies: policies, user: user) } diff --git a/spec/models/ci/job_token/group_scope_link_spec.rb b/spec/models/ci/job_token/group_scope_link_spec.rb index c087e636921..1e5770fb9c5 100644 --- a/spec/models/ci/job_token/group_scope_link_spec.rb +++ b/spec/models/ci/job_token/group_scope_link_spec.rb @@ -74,12 +74,12 @@ RSpec.describe Ci::JobToken::GroupScopeLink, feature_category: :continuous_integ using RSpec::Parameterized::TableSyntax where(:value, :valid) do - nil | true - [] | true - %w[read_build] | true - %w[read_build read_project] | true - %w[read_issue] | false - { project: %w[read_build] } | false + nil | true + [] | true + %w[read_containers] | true + %w[read_containers read_packages] | true + %w[read_issue] | false + { project: %w[read_build] } | false end with_them do diff --git a/spec/models/ci/job_token/project_scope_link_spec.rb b/spec/models/ci/job_token/project_scope_link_spec.rb index 87b77761ef2..155da77a32c 100644 --- a/spec/models/ci/job_token/project_scope_link_spec.rb +++ b/spec/models/ci/job_token/project_scope_link_spec.rb @@ -78,12 +78,12 @@ RSpec.describe Ci::JobToken::ProjectScopeLink, feature_category: :continuous_int using RSpec::Parameterized::TableSyntax where(:value, :valid) do - nil | true - [] | true - %w[read_build] | true - %w[read_build read_project] | true - %w[read_issue] | false - { project: %w[read_build] } | false + nil | true + [] | true + %w[read_containers] | true + %w[read_containers read_packages] | true + %w[read_issue] | false + { project: %w[read_build] } | false end with_them do diff --git a/spec/requests/api/graphql/ci/job_token_scope/allowlist_query_spec.rb b/spec/requests/api/graphql/ci/job_token_scope/allowlist_query_spec.rb index d4c314d8559..3778d47c06a 100644 --- a/spec/requests/api/graphql/ci/job_token_scope/allowlist_query_spec.rb +++ b/spec/requests/api/graphql/ci/job_token_scope/allowlist_query_spec.rb @@ -70,7 +70,7 @@ RSpec.describe 'Querying CI_JOB_TOKEN allowlist for a project', feature_category { 'addedBy' => { 'username' => current_user.username }, 'direction' => 'inbound', - 'jobTokenPolicies' => ['READ_GROUP'], + 'jobTokenPolicies' => ['READ_CONTAINERS'], 'sourceProject' => { 'fullPath' => project.full_path }, 'target' => { 'fullPath' => target_group_1.full_path } } @@ -85,14 +85,14 @@ RSpec.describe 'Querying CI_JOB_TOKEN allowlist for a project', feature_category { 'addedBy' => { 'username' => current_user.username }, 'direction' => 'outbound', - 'jobTokenPolicies' => ['READ_PROJECT'], + 'jobTokenPolicies' => ['READ_CONTAINERS'], 'sourceProject' => { 'fullPath' => project.full_path }, 'target' => { 'fullPath' => target_project_2.full_path } }, { 'addedBy' => { 'username' => current_user.username }, 'direction' => 'inbound', - 'jobTokenPolicies' => ['READ_PROJECT'], + 'jobTokenPolicies' => ['READ_CONTAINERS'], 'sourceProject' => { 'fullPath' => project.full_path }, 'target' => { 'fullPath' => target_project_1.full_path } } @@ -138,7 +138,7 @@ RSpec.describe 'Querying CI_JOB_TOKEN allowlist for a project', feature_category :ci_job_token_project_scope_link, source_project: project, target_project: target_project_1, - job_token_policies: %w[read_project], + job_token_policies: %w[read_containers], added_by: current_user, direction: :inbound ) @@ -147,7 +147,7 @@ RSpec.describe 'Querying CI_JOB_TOKEN allowlist for a project', feature_category :ci_job_token_project_scope_link, source_project: project, target_project: target_project_2, - job_token_policies: %w[read_project], + job_token_policies: %w[read_containers], added_by: current_user, direction: :outbound ) @@ -157,7 +157,7 @@ RSpec.describe 'Querying CI_JOB_TOKEN allowlist for a project', feature_category source_project: project, target_group: target_group_1, added_by: current_user, - job_token_policies: %w[read_group] + job_token_policies: %w[read_containers] ) end diff --git a/spec/requests/api/graphql/mutations/ci/job_token_scope/add_group_or_project_spec.rb b/spec/requests/api/graphql/mutations/ci/job_token_scope/add_group_or_project_spec.rb index 0a10852c9fc..cbf9f4a1883 100644 --- a/spec/requests/api/graphql/mutations/ci/job_token_scope/add_group_or_project_spec.rb +++ b/spec/requests/api/graphql/mutations/ci/job_token_scope/add_group_or_project_spec.rb @@ -7,7 +7,7 @@ RSpec.describe 'CiJobTokenScopeAddGroupOrProject', feature_category: :continuous let_it_be(:project) { create(:project, ci_inbound_job_token_scope_enabled: true) } - let(:policies) { %w[READ_PROJECT] } + let(:policies) { %w[READ_CONTAINERS] } let(:mutation_response) { graphql_mutation_response(:ci_job_token_scope_add_group_or_project) } diff --git a/spec/requests/api/graphql/mutations/ci/job_token_scope/update_job_token_policies_spec.rb b/spec/requests/api/graphql/mutations/ci/job_token_scope/update_job_token_policies_spec.rb index 10ef438148b..acecd77b244 100644 --- a/spec/requests/api/graphql/mutations/ci/job_token_scope/update_job_token_policies_spec.rb +++ b/spec/requests/api/graphql/mutations/ci/job_token_scope/update_job_token_policies_spec.rb @@ -45,7 +45,7 @@ RSpec.describe 'CiJobTokenScopeUpdatePolicies', feature_category: :continuous_in let_it_be(:target_project) { create(:project, :private) } let_it_be(:target_path) { target_project.full_path } - let(:policies) { %w[READ_PROJECT READ_PACKAGE] } + let(:policies) { %w[READ_CONTAINERS READ_PACKAGES] } context 'when user does not have permissions to admin project' do let_it_be(:current_user) { create(:user, guest_of: target_project) } @@ -74,7 +74,7 @@ RSpec.describe 'CiJobTokenScopeUpdatePolicies', feature_category: :continuous_in :ci_job_token_project_scope_link, source_project: project, target_project: target_project, - job_token_policies: %w[read_project], + job_token_policies: %w[read_containers], direction: :inbound ) end @@ -123,7 +123,7 @@ RSpec.describe 'CiJobTokenScopeUpdatePolicies', feature_category: :continuous_in let_it_be(:target_group) { create(:group, :private) } let_it_be(:target_path) { target_group.full_path } - let(:policies) { %w[READ_GROUP READ_PACKAGE] } + let(:policies) { %w[READ_CONTAINERS READ_PACKAGES] } context 'when user does not have permissions to admin project' do let_it_be(:current_user) { create(:user, guest_of: target_group) } @@ -152,7 +152,7 @@ RSpec.describe 'CiJobTokenScopeUpdatePolicies', feature_category: :continuous_in :ci_job_token_group_scope_link, source_project: project, target_group: target_group, - job_token_policies: %w[read_group] + job_token_policies: %w[read_containers] ) end diff --git a/spec/services/ci/cancel_pipeline_service_spec.rb b/spec/services/ci/cancel_pipeline_service_spec.rb index d6312aa7d2f..c33150aebcf 100644 --- a/spec/services/ci/cancel_pipeline_service_spec.rb +++ b/spec/services/ci/cancel_pipeline_service_spec.rb @@ -51,6 +51,7 @@ RSpec.describe Ci::CancelPipelineService, :aggregate_failures, feature_category: .to have_received(:info) .with( a_hash_including( + class: described_class.to_s, event: 'pipeline_cancel_running', pipeline_id: pipeline.id, auto_canceled_by_pipeline_id: nil, diff --git a/spec/services/ci/job_token_scope/add_group_or_project_service_spec.rb b/spec/services/ci/job_token_scope/add_group_or_project_service_spec.rb index 3d8d7f68e62..8fbc181dfee 100644 --- a/spec/services/ci/job_token_scope/add_group_or_project_service_spec.rb +++ b/spec/services/ci/job_token_scope/add_group_or_project_service_spec.rb @@ -7,7 +7,7 @@ RSpec.describe Ci::JobTokenScope::AddGroupOrProjectService, feature_category: :c let_it_be(:target_project) { create(:project) } let_it_be(:target_group) { create(:group) } let_it_be(:current_user) { create(:user) } - let_it_be(:policies) { %w[read_project read_package] } + let_it_be(:policies) { %w[read_containers read_packages] } let(:response_success) { ServiceResponse.success } @@ -36,7 +36,7 @@ RSpec.describe Ci::JobTokenScope::AddGroupOrProjectService, feature_category: :c context 'when project is a target to add' do let(:target) { target_project } let(:add_project_service_double) { instance_double(::Ci::JobTokenScope::AddProjectService) } - let(:policies) { %w[read_project] } + let(:policies) { %w[read_containers] } before do allow(::Ci::JobTokenScope::AddProjectService).to receive(:new) diff --git a/spec/services/ci/job_token_scope/add_group_service_spec.rb b/spec/services/ci/job_token_scope/add_group_service_spec.rb index 8556dbc2d94..b6e087a25d2 100644 --- a/spec/services/ci/job_token_scope/add_group_service_spec.rb +++ b/spec/services/ci/job_token_scope/add_group_service_spec.rb @@ -6,7 +6,7 @@ RSpec.describe Ci::JobTokenScope::AddGroupService, feature_category: :continuous let_it_be(:project) { create(:project, ci_outbound_job_token_scope_enabled: true).tap(&:save!) } let_it_be(:target_group) { create(:group, :private) } let_it_be(:current_user) { create(:user) } - let_it_be(:policies) { %w[read_project read_package] } + let_it_be(:policies) { %w[read_containers read_packages] } let(:service) { described_class.new(project, current_user) } diff --git a/spec/services/ci/job_token_scope/add_project_service_spec.rb b/spec/services/ci/job_token_scope/add_project_service_spec.rb index d61518d91c6..55815e2852a 100644 --- a/spec/services/ci/job_token_scope/add_project_service_spec.rb +++ b/spec/services/ci/job_token_scope/add_project_service_spec.rb @@ -7,7 +7,7 @@ RSpec.describe Ci::JobTokenScope::AddProjectService, feature_category: :continuo let_it_be(:project) { create(:project, ci_outbound_job_token_scope_enabled: true).tap(&:save!) } let_it_be(:target_project) { create(:project) } let_it_be(:current_user) { create(:user) } - let_it_be(:policies) { %w[read_project read_package] } + let_it_be(:policies) { %w[read_containers read_packages] } shared_examples 'adds project' do |context| it 'adds the project to the scope', :aggregate_failures do diff --git a/spec/services/ci/job_token_scope/update_policies_service_spec.rb b/spec/services/ci/job_token_scope/update_policies_service_spec.rb index fed5d5e4c79..cbcbba5f1e0 100644 --- a/spec/services/ci/job_token_scope/update_policies_service_spec.rb +++ b/spec/services/ci/job_token_scope/update_policies_service_spec.rb @@ -78,12 +78,12 @@ RSpec.describe Ci::JobTokenScope::UpdatePoliciesService, feature_category: :cont :ci_job_token_project_scope_link, source_project: project, target_project: target_project, - job_token_policies: %w[read_project], + job_token_policies: %w[read_containers], direction: :inbound ) end - let(:policies) { %w[read_project read_package] } + let(:policies) { %w[read_containers read_packages] } it_behaves_like 'when user is not logged in' @@ -106,7 +106,7 @@ RSpec.describe Ci::JobTokenScope::UpdatePoliciesService, feature_category: :cont expect(project_link.source_project).to eq(project) expect(project_link.target_project).to eq(target_project) - expect(project_link.job_token_policies).to eq(%w[read_project read_package]) + expect(project_link.job_token_policies).to eq(%w[read_containers read_packages]) end context 'when feature-flag `add_policies_to_ci_job_token` is disabled' do @@ -117,7 +117,7 @@ RSpec.describe Ci::JobTokenScope::UpdatePoliciesService, feature_category: :cont it 'does not update the policies' do project_link = Ci::JobToken::ProjectScopeLink.last - expect(project_link.job_token_policies).to eq(%w[read_project]) + expect(project_link.job_token_policies).to eq(%w[read_containers]) end end end @@ -132,11 +132,11 @@ RSpec.describe Ci::JobTokenScope::UpdatePoliciesService, feature_category: :cont :ci_job_token_group_scope_link, source_project: project, target_group: target_group, - job_token_policies: %w[read_group] + job_token_policies: %w[read_containers] ) end - let(:policies) { %w[read_group read_package] } + let(:policies) { %w[read_containers read_packages] } it_behaves_like 'when user is not logged in' @@ -159,7 +159,7 @@ RSpec.describe Ci::JobTokenScope::UpdatePoliciesService, feature_category: :cont expect(group_link.source_project).to eq(project) expect(group_link.target_group).to eq(target_group) - expect(group_link.job_token_policies).to eq(%w[read_group read_package]) + expect(group_link.job_token_policies).to eq(%w[read_containers read_packages]) end context 'when feature-flag `add_policies_to_ci_job_token` is disabled' do @@ -170,7 +170,7 @@ RSpec.describe Ci::JobTokenScope::UpdatePoliciesService, feature_category: :cont it 'does not update the policies' do group_link = Ci::JobToken::GroupScopeLink.last - expect(group_link.job_token_policies).to eq(%w[read_group]) + expect(group_link.job_token_policies).to eq(%w[read_containers]) end end end diff --git a/spec/support/shared_contexts/graphql/types/query_type_shared_context.rb b/spec/support/shared_contexts/graphql/types/query_type_shared_context.rb index 8585ddd7f8c..997988e3636 100644 --- a/spec/support/shared_contexts/graphql/types/query_type_shared_context.rb +++ b/spec/support/shared_contexts/graphql/types/query_type_shared_context.rb @@ -51,7 +51,8 @@ RSpec.shared_context 'with FOSS query type fields' do :audit_event_definitions, :abuse_report, :abuse_report_labels, - :feature_flag_enabled + :feature_flag_enabled, + :job_token_policies_by_category ] end end diff --git a/vite.config.js b/vite.config.js index ceb475eccc3..4ec0bcf09e7 100644 --- a/vite.config.js +++ b/vite.config.js @@ -20,7 +20,6 @@ import { PDF_JS_CMAPS_V4_PUBLIC_PATH, } from './config/pdfjs.constants'; -/* eslint-disable import/extensions */ import { viteTailwindCompilerPlugin } from './scripts/frontend/tailwindcss.mjs'; import { CopyPlugin } from './config/helpers/vite_plugin_copy.mjs'; import { AutoStopPlugin } from './config/helpers/vite_plugin_auto_stop.mjs'; @@ -29,7 +28,6 @@ import { FixedRubyPlugin } from './config/helpers/vite_plugin_ruby_fixed.mjs'; import { StylePlugin } from './config/helpers/vite_plugin_style.mjs'; import { IconsPlugin } from './config/helpers/vite_plugin_icons.mjs'; import { ImagesPlugin } from './config/helpers/vite_plugin_images.mjs'; -/* eslint-enable import/extensions */ let viteGDKConfig; try {