diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2022-06-02 21:09:25 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2022-06-02 21:09:25 +0000 |
commit | 6ddc820225c148a923a154ab6d6f0a8c791a089d (patch) | |
tree | 23a648fd2a83f54d5535dda197ed1ac6e5315493 | |
parent | 9b40f0e0d63ff2a8ed1686f8713701688600a998 (diff) | |
download | gitlab-ce-6ddc820225c148a923a154ab6d6f0a8c791a089d.tar.gz |
Add latest changes from gitlab-org/gitlab@master
104 files changed, 709 insertions, 183 deletions
diff --git a/.rubocop_todo/gitlab/namespaced_class.yml b/.rubocop_todo/gitlab/namespaced_class.yml index eb333cbf058..36348324bd0 100644 --- a/.rubocop_todo/gitlab/namespaced_class.yml +++ b/.rubocop_todo/gitlab/namespaced_class.yml @@ -820,7 +820,6 @@ Gitlab/NamespacedClass: - 'app/workers/project_daily_statistics_worker.rb' - 'app/workers/project_destroy_worker.rb' - 'app/workers/project_export_worker.rb' - - 'app/workers/project_service_worker.rb' - 'app/workers/propagate_integration_group_worker.rb' - 'app/workers/propagate_integration_inherit_descendant_worker.rb' - 'app/workers/propagate_integration_inherit_worker.rb' diff --git a/.rubocop_todo/layout/line_length.yml b/.rubocop_todo/layout/line_length.yml index e98fd267831..a8fd3dee6be 100644 --- a/.rubocop_todo/layout/line_length.yml +++ b/.rubocop_todo/layout/line_length.yml @@ -6216,7 +6216,6 @@ Layout/LineLength: - 'spec/support/helpers/global_id_deprecation_helpers.rb' - 'spec/support/helpers/graphql_helpers.rb' - 'spec/support/helpers/javascript_fixtures_helpers.rb' - - 'spec/support/helpers/jira_service_helper.rb' - 'spec/support/helpers/kubernetes_helpers.rb' - 'spec/support/helpers/lets_encrypt_helpers.rb' - 'spec/support/helpers/live_debugger.rb' diff --git a/.rubocop_todo/naming/rescued_exceptions_variable_name.yml b/.rubocop_todo/naming/rescued_exceptions_variable_name.yml index 8d4d2da29ac..0e753a53dc3 100644 --- a/.rubocop_todo/naming/rescued_exceptions_variable_name.yml +++ b/.rubocop_todo/naming/rescued_exceptions_variable_name.yml @@ -86,7 +86,6 @@ Naming/RescuedExceptionsVariableName: - 'app/workers/namespaces/schedule_aggregation_worker.rb' - 'app/workers/packages/go/sync_packages_worker.rb' - 'app/workers/project_destroy_worker.rb' - - 'app/workers/project_service_worker.rb' - 'app/workers/projects/git_garbage_collect_worker.rb' - 'app/workers/remove_expired_members_worker.rb' - 'app/workers/users/create_statistics_worker.rb' diff --git a/.rubocop_todo/style/string_concatenation.yml b/.rubocop_todo/style/string_concatenation.yml index 23a16f928f5..e21fecfb5e3 100644 --- a/.rubocop_todo/style/string_concatenation.yml +++ b/.rubocop_todo/style/string_concatenation.yml @@ -317,7 +317,6 @@ Style/StringConcatenation: - 'spec/support/helpers/git_helpers.rb' - 'spec/support/helpers/gitaly_setup.rb' - 'spec/support/helpers/javascript_fixtures_helpers.rb' - - 'spec/support/helpers/jira_service_helper.rb' - 'spec/support/helpers/kubernetes_helpers.rb' - 'spec/support/helpers/stub_configuration.rb' - 'spec/support/helpers/workhorse_helpers.rb' diff --git a/app/assets/javascripts/editor/schema/ci.json b/app/assets/javascripts/editor/schema/ci.json index 7ea1db0b5ad..8262dae2b89 100644 --- a/app/assets/javascripts/editor/schema/ci.json +++ b/app/assets/javascripts/editor/schema/ci.json @@ -63,7 +63,10 @@ "rules": { "type": "array", "items": { - "type": "object", + "anyOf": [ + {"type": "object"}, + {"type": "array", "minLength": 1, "items": { "type": "string" }} + ], "properties": { "if": { "$ref": "#/definitions/if" }, "changes": { "$ref": "#/definitions/changes" }, diff --git a/app/assets/javascripts/pipelines/components/graph/linked_pipeline.vue b/app/assets/javascripts/pipelines/components/graph/linked_pipeline.vue index e46578acc18..119dc645f6d 100644 --- a/app/assets/javascripts/pipelines/components/graph/linked_pipeline.vue +++ b/app/assets/javascripts/pipelines/components/graph/linked_pipeline.vue @@ -107,6 +107,9 @@ export default { } return this.expanded ? 'angle-left' : 'angle-right'; }, + expandBtnText() { + return this.expanded ? __('Collapse jobs') : __('Expand jobs'); + }, childPipeline() { return this.isDownstream && this.isSameProject; }, @@ -161,7 +164,7 @@ export default { return Boolean(this.action?.method && this.action?.icon && this.action?.ariaLabel); }, showCardTooltip() { - return !this.hasActionTooltip; + return !this.hasActionTooltip && !this.isExpandBtnFocus; }, sourceJobName() { return this.pipeline.sourceJob?.name ?? ''; @@ -284,10 +287,12 @@ export default { <div class="gl-display-flex"> <gl-button :id="buttonId" + v-gl-tooltip + :title="expandBtnText" class="gl-border! gl-rounded-lg!" :class="[`js-pipeline-expand-${pipeline.id}`, buttonBorderClasses, buttonShadowClass]" :icon="expandedIcon" - :aria-label="__('Expand pipeline')" + :aria-label="expandBtnText" data-testid="expand-pipeline-button" data-qa-selector="expand_linked_pipeline_button" @mouseover="setExpandBtnActiveState(true)" diff --git a/app/assets/javascripts/repository/components/blob_viewers/sketch_viewer.vue b/app/assets/javascripts/repository/components/blob_viewers/sketch_viewer.vue index 32e24a9cc07..b48af02e541 100644 --- a/app/assets/javascripts/repository/components/blob_viewers/sketch_viewer.vue +++ b/app/assets/javascripts/repository/components/blob_viewers/sketch_viewer.vue @@ -26,6 +26,6 @@ export default { <template> <div ref="viewer" class="file-content" :data-endpoint="url" data-testid="sketch"> - <gl-loading-icon class="my-4 js-loading-icon" size="md" /> + <gl-loading-icon class="my-4 js-loading-icon" size="lg" /> </div> </template> diff --git a/app/assets/javascripts/vue_shared/components/notes/skeleton_note.vue b/app/assets/javascripts/vue_shared/components/notes/skeleton_note.vue index 3aca068c074..2206ae98c73 100644 --- a/app/assets/javascripts/vue_shared/components/notes/skeleton_note.vue +++ b/app/assets/javascripts/vue_shared/components/notes/skeleton_note.vue @@ -1,11 +1,11 @@ <script> -import { GlDeprecatedSkeletonLoading as GlSkeletonLoading } from '@gitlab/ui'; +import { GlSkeletonLoader } from '@gitlab/ui'; import TimelineEntryItem from '~/vue_shared/components/notes/timeline_entry_item.vue'; export default { name: 'SkeletonNote', components: { - GlSkeletonLoading, + GlSkeletonLoader, TimelineEntryItem, }, }; @@ -16,7 +16,7 @@ export default { <div class="timeline-icon"></div> <div class="timeline-content"> <div class="note-header"></div> - <div class="note-body"><gl-skeleton-loading /></div> + <div class="note-body"><gl-skeleton-loader /></div> </div> </timeline-entry-item> </template> diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb index 6b11b8eda5c..874eb8985fb 100644 --- a/app/controllers/admin/users_controller.rb +++ b/app/controllers/admin/users_controller.rb @@ -9,7 +9,7 @@ class Admin::UsersController < Admin::ApplicationController before_action :ensure_destroy_prerequisites_met, only: [:destroy] before_action :check_ban_user_feature_flag, only: [:ban] - feature_category :users + feature_category :user_management PAGINATION_WITH_COUNT_LIMIT = 1000 diff --git a/app/controllers/confirmations_controller.rb b/app/controllers/confirmations_controller.rb index dd30d688fa8..704453fbf44 100644 --- a/app/controllers/confirmations_controller.rb +++ b/app/controllers/confirmations_controller.rb @@ -8,7 +8,7 @@ class ConfirmationsController < Devise::ConfirmationsController prepend_before_action :check_recaptcha, only: :create before_action :load_recaptcha, only: :new - feature_category :users + feature_category :authentication_and_authorization def almost_there flash[:notice] = nil diff --git a/app/controllers/profiles/accounts_controller.rb b/app/controllers/profiles/accounts_controller.rb index 83eabbb736e..cb8b2783000 100644 --- a/app/controllers/profiles/accounts_controller.rb +++ b/app/controllers/profiles/accounts_controller.rb @@ -3,7 +3,7 @@ class Profiles::AccountsController < Profiles::ApplicationController include AuthHelper - feature_category :users + feature_category :authentication_and_authorization urgency :low, [:show] def show diff --git a/app/controllers/profiles/active_sessions_controller.rb b/app/controllers/profiles/active_sessions_controller.rb index aafd7c2b65b..2607ba7d404 100644 --- a/app/controllers/profiles/active_sessions_controller.rb +++ b/app/controllers/profiles/active_sessions_controller.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true class Profiles::ActiveSessionsController < Profiles::ApplicationController - feature_category :users + feature_category :authentication_and_authorization def index @sessions = ActiveSession.list(current_user).reject(&:is_impersonated) diff --git a/app/controllers/profiles_controller.rb b/app/controllers/profiles_controller.rb index d5e7195a157..dd1ac526b89 100644 --- a/app/controllers/profiles_controller.rb +++ b/app/controllers/profiles_controller.rb @@ -14,7 +14,10 @@ class ProfilesController < Profiles::ApplicationController push_frontend_feature_flag(:webauthn) end - feature_category :users + feature_category :users, [:show, :update, :reset_incoming_email_token, :reset_feed_token, + :reset_static_object_token, :update_username] + + feature_category :authentication_and_authorization, [:audit_log] urgency :low, [:show, :update] def show diff --git a/app/controllers/users/terms_controller.rb b/app/controllers/users/terms_controller.rb index f0d95b56d33..f7eb2aad9dc 100644 --- a/app/controllers/users/terms_controller.rb +++ b/app/controllers/users/terms_controller.rb @@ -15,7 +15,7 @@ module Users layout 'terms' - feature_category :users + feature_category :user_management def index @redirect = redirect_path diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 37c4ffe2a5e..2799479d922 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -29,9 +29,10 @@ class UsersController < ApplicationController feature_category :users, [:show, :activity, :groups, :projects, :contributed, :starred, :followers, :following, :calendar, :calendar_activities, - :exists, :activity, :follow, :unfollow, :ssh_keys, :gpg_keys] + :exists, :activity, :follow, :unfollow, :ssh_keys] feature_category :snippets, [:snippets] + feature_category :source_code_management, [:gpg_keys] # TODO: Set higher urgency after resolving https://gitlab.com/gitlab-org/gitlab/-/issues/357914 urgency :low, [:show, :calendar_activities, :contributed, :activity, :projects, :groups, :calendar] diff --git a/app/models/application_setting_implementation.rb b/app/models/application_setting_implementation.rb index 8ccd27f468b..a89ea05fb62 100644 --- a/app/models/application_setting_implementation.rb +++ b/app/models/application_setting_implementation.rb @@ -510,8 +510,35 @@ module ApplicationSettingImplementation 'https://sandbox-prod.gitlab-static.net' end + def ensure_key_restrictions! + return if Gitlab::Database.read_only? + return unless Gitlab::FIPS.enabled? + + Gitlab::SSHPublicKey.supported_types.each do |key_type| + set_max_key_restriction!(key_type) + end + end + private + def set_max_key_restriction!(key_type) + attr_name = "#{key_type}_key_restriction" + current = self.attributes[attr_name].to_i + + return if current == KeyRestrictionValidator::FORBIDDEN + + min_size = self.class.default_min_key_size(key_type) + + new_value = + if min_size == KeyRestrictionValidator::FORBIDDEN + min_size + else + [min_size, current].max + end + + self.assign_attributes({ attr_name => new_value }) + end + def separate_allowlists(string_array) string_array.reduce([[], []]) do |(ip_allowlist, domain_allowlist), string| address, port = parse_addr_and_port(string) diff --git a/app/models/concerns/cache_markdown_field.rb b/app/models/concerns/cache_markdown_field.rb index 9414d16beef..99dbe464a7c 100644 --- a/app/models/concerns/cache_markdown_field.rb +++ b/app/models/concerns/cache_markdown_field.rb @@ -24,6 +24,9 @@ module CacheMarkdownField true end + attr_accessor :skip_markdown_cache_validation + alias_method :skip_markdown_cache_validation?, :skip_markdown_cache_validation + # Returns the default Banzai render context for the cached markdown field. def banzai_render_context(field) raise ArgumentError, "Unknown field: #{field.inspect}" unless @@ -91,7 +94,7 @@ module CacheMarkdownField end def invalidated_markdown_cache? - cached_markdown_fields.html_fields.any? {|html_field| attribute_invalidated?(html_field) } + cached_markdown_fields.html_fields.any? { |html_field| attribute_invalidated?(html_field) } end def attribute_invalidated?(attr) @@ -218,6 +221,8 @@ module CacheMarkdownField # The HTML becomes invalid if any dependent fields change. For now, assume # author and project invalidate the cache in all circumstances. define_method(invalidation_method) do + return false if skip_markdown_cache_validation? + changed_fields = changed_attributes.keys invalidations = changed_fields & [markdown_field.to_s, *INVALIDATED_BY] !invalidations.empty? || !cached_html_up_to_date?(markdown_field) diff --git a/app/models/integration.rb b/app/models/integration.rb index a16e8dc960a..316f2877059 100644 --- a/app/models/integration.rb +++ b/app/models/integration.rb @@ -576,7 +576,11 @@ class Integration < ApplicationRecord def async_execute(data) return unless supported_events.include?(data[:object_kind]) - ProjectServiceWorker.perform_async(id, data) + if Feature.enabled?(:rename_integrations_workers) + Integrations::ExecuteWorker.perform_async(id, data) + else + ProjectServiceWorker.perform_async(id, data) + end end # override if needed diff --git a/app/services/issuable/clone/base_service.rb b/app/services/issuable/clone/base_service.rb index 1d2c5c06d1b..ce9918a4b56 100644 --- a/app/services/issuable/clone/base_service.rb +++ b/app/services/issuable/clone/base_service.rb @@ -41,14 +41,15 @@ module Issuable end def update_new_entity_description - rewritten_description = MarkdownContentRewriterService.new( + update_description_params = MarkdownContentRewriterService.new( current_user, - original_entity.description, + original_entity, + :description, original_entity.project, new_parent ).execute - new_entity.update!(description: rewritten_description) + new_entity.update!(update_description_params) end def update_new_entity_attributes diff --git a/app/services/markdown_content_rewriter_service.rb b/app/services/markdown_content_rewriter_service.rb index bc6fd592eaa..4d8f523fa77 100644 --- a/app/services/markdown_content_rewriter_service.rb +++ b/app/services/markdown_content_rewriter_service.rb @@ -4,29 +4,69 @@ # which rewrite references to GitLab objects and uploads within the content # based on their visibility by the `target_parent`. class MarkdownContentRewriterService - REWRITERS = [Gitlab::Gfm::ReferenceRewriter, Gitlab::Gfm::UploadsRewriter].freeze + include Gitlab::Utils::StrongMemoize - def initialize(current_user, content, source_parent, target_parent) - # See https://gitlab.com/gitlab-org/gitlab/-/merge_requests/39654#note_399095117 - raise ArgumentError, 'The rewriter classes require that `source_parent` is a `Project`' \ - unless source_parent.is_a?(Project) + REWRITERS = [Gitlab::Gfm::ReferenceRewriter, Gitlab::Gfm::UploadsRewriter].freeze + def initialize(current_user, object, field, source_parent, target_parent) @current_user = current_user - @content = content.presence @source_parent = source_parent @target_parent = target_parent + @object = object + @field = field + + validate_parameters! + + @content = object[field].dup.presence + @html_field = object.cached_markdown_fields.html_field(field) + @content_html = object.cached_html_for(field) + + @rewriters = + REWRITERS.map do |rewriter_class| + rewriter_class.new(@content, content_html, source_parent, current_user) + end + + @result = { + field => nil, + html_field => nil + }.with_indifferent_access end def execute - return unless content + return result unless content - REWRITERS.inject(content) do |text, klass| - rewriter = klass.new(text, source_parent, current_user) - rewriter.rewrite(target_parent) + unless safe_to_copy_markdown? + rewriters.each do |rewriter| + rewriter.rewrite(target_parent) + end + end + + result[field] = content + result[html_field] = content_html if safe_to_copy_markdown? + result[:skip_markdown_cache_validation] = safe_to_copy_markdown? + + result + end + + def safe_to_copy_markdown? + strong_memoize(:safe_to_copy_markdown) do + rewriters.none?(&:needs_rewrite?) end end private - attr_reader :current_user, :content, :source_parent, :target_parent + def validate_parameters! + # See https://gitlab.com/gitlab-org/gitlab/-/merge_requests/39654#note_399095117 + raise ArgumentError, 'The rewriter classes require that `source_parent` is a `Project`' \ + unless source_parent.is_a?(Project) + + if object.cached_markdown_fields[field].nil? + raise ArgumentError, 'The `field` attribute does not contain cached markdown' + end + end + + attr_reader :current_user, :content, :source_parent, + :target_parent, :rewriters, :content_html, + :field, :html_field, :object, :result end diff --git a/app/services/members/approve_access_request_service.rb b/app/services/members/approve_access_request_service.rb index 919c22894c1..5337279f702 100644 --- a/app/services/members/approve_access_request_service.rb +++ b/app/services/members/approve_access_request_service.rb @@ -3,7 +3,7 @@ module Members class ApproveAccessRequestService < Members::BaseService def execute(access_requester, skip_authorization: false, skip_log_audit_event: false) - raise Gitlab::Access::AccessDeniedError unless skip_authorization || can_update_access_requester?(access_requester) + validate_access!(access_requester) unless skip_authorization access_requester.access_level = params[:access_level] if params[:access_level] access_requester.accept_request @@ -15,9 +15,24 @@ module Members private + def validate_access!(access_requester) + raise Gitlab::Access::AccessDeniedError unless can_update_access_requester?(access_requester) + + if approving_member_with_owner_access_level?(access_requester) && + cannot_assign_owner_responsibilities_to_member_in_project?(access_requester) + raise Gitlab::Access::AccessDeniedError + end + end + def can_update_access_requester?(access_requester) can?(current_user, update_member_permission(access_requester), access_requester) end + + def approving_member_with_owner_access_level?(access_requester) + access_level_value = params[:access_level] || access_requester.access_level + + access_level_value == Gitlab::Access::OWNER + end end end diff --git a/app/services/notes/copy_service.rb b/app/services/notes/copy_service.rb index 6e5b4596602..e7182350837 100644 --- a/app/services/notes/copy_service.rb +++ b/app/services/notes/copy_service.rb @@ -38,17 +38,16 @@ module Notes def params_from_note(note, new_note) new_discussion_ids[note.discussion_id] ||= Discussion.discussion_id(new_note) - rewritten_note = MarkdownContentRewriterService.new(current_user, note.note, from_project, to_noteable.resource_parent).execute - new_params = { + new_params = sanitized_note_params(note) + + new_params.merge!( project: to_noteable.project, noteable: to_noteable, discussion_id: new_discussion_ids[note.discussion_id], - note: rewritten_note, - note_html: nil, created_at: note.created_at, updated_at: note.updated_at - } + ) if note.system_note_metadata new_params[:system_note_metadata] = note.system_note_metadata.dup @@ -61,6 +60,14 @@ module Notes new_params end + # Skip copying cached markdown HTML if text + # does not contain references or uploads. + def sanitized_note_params(note) + MarkdownContentRewriterService + .new(current_user, note, :note, from_project, to_noteable.resource_parent) + .execute + end + def copy_award_emoji(from_note, to_note) AwardEmojis::CopyService.new(from_note, to_note).execute end diff --git a/app/workers/all_queues.yml b/app/workers/all_queues.yml index 87a621980c7..fe321c598aa 100644 --- a/app/workers/all_queues.yml +++ b/app/workers/all_queues.yml @@ -2371,6 +2371,15 @@ :weight: 1 :idempotent: true :tags: [] +- :name: integrations_execute + :worker_name: Integrations::ExecuteWorker + :feature_category: :integrations + :has_external_dependencies: true + :urgency: :low + :resource_boundary: :unknown + :weight: 1 + :idempotent: + :tags: [] - :name: invalid_gpg_signature_update :worker_name: InvalidGpgSignatureUpdateWorker :feature_category: :source_code_management diff --git a/app/workers/integrations/execute_worker.rb b/app/workers/integrations/execute_worker.rb new file mode 100644 index 00000000000..443f1d9fe8e --- /dev/null +++ b/app/workers/integrations/execute_worker.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +module Integrations + class ExecuteWorker # rubocop:disable Scalability/IdempotentWorker + include ApplicationWorker + + data_consistency :always + sidekiq_options retry: 3 + sidekiq_options dead: false + feature_category :integrations + urgency :low + + worker_has_external_dependencies! + + def perform(hook_id, data) + data = data.with_indifferent_access + integration = Integration.find_by_id(hook_id) + return unless integration + + begin + integration.execute(data) + rescue StandardError => e + integration.log_exception(e) + end + end + end +end diff --git a/app/workers/project_service_worker.rb b/app/workers/project_service_worker.rb index f73958a6ef9..f45eec0bcd9 100644 --- a/app/workers/project_service_worker.rb +++ b/app/workers/project_service_worker.rb @@ -1,8 +1,11 @@ # frozen_string_literal: true -class ProjectServiceWorker # rubocop:disable Scalability/IdempotentWorker - include ApplicationWorker - +# This worker was renamed in 15.1, we can delete it in 15.2. +# See: https://gitlab.com/gitlab-org/gitlab/-/issues/364107 +# +# rubocop: disable Gitlab/NamespacedClass +# rubocop: disable Scalability/IdempotentWorker +class ProjectServiceWorker < Integrations::ExecuteWorker data_consistency :always sidekiq_options retry: 3 sidekiq_options dead: false @@ -10,16 +13,4 @@ class ProjectServiceWorker # rubocop:disable Scalability/IdempotentWorker urgency :low worker_has_external_dependencies! - - def perform(hook_id, data) - data = data.with_indifferent_access - integration = Integration.find_by_id(hook_id) - return unless integration - - begin - integration.execute(data) - rescue StandardError => error - integration.log_exception(error) - end - end end diff --git a/config/feature_flags/development/rename_integrations_workers.yml b/config/feature_flags/development/rename_integrations_workers.yml new file mode 100644 index 00000000000..91f8f7f7166 --- /dev/null +++ b/config/feature_flags/development/rename_integrations_workers.yml @@ -0,0 +1,8 @@ +--- +name: rename_integrations_workers +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/88558 +rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/364112 +milestone: '15.1' +type: development +group: group::integrations +default_enabled: false diff --git a/config/routes.rb b/config/routes.rb index 2eb7ece9a95..44e89f0d387 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -109,6 +109,7 @@ Rails.application.routes.draw do get '/autocomplete/project_groups' => 'autocomplete#project_groups' get '/autocomplete/project_routes' => 'autocomplete#project_routes' get '/autocomplete/namespace_routes' => 'autocomplete#namespace_routes' + get '/autocomplete/group_subgroups' => 'autocomplete#group_subgroups' end # sandbox diff --git a/config/sidekiq_queues.yml b/config/sidekiq_queues.yml index 9f2eede1c47..1ffc9d97a0e 100644 --- a/config/sidekiq_queues.yml +++ b/config/sidekiq_queues.yml @@ -223,6 +223,8 @@ - 1 - - integrations_create_external_cross_reference - 1 +- - integrations_execute + - 1 - - invalid_gpg_signature_update - 2 - - irker diff --git a/data/deprecations/14-10-dependency-scanning-default-java-version.yml b/data/deprecations/14-10-dependency-scanning-default-java-version.yml index c589f2bb3ac..1717c452891 100644 --- a/data/deprecations/14-10-dependency-scanning-default-java-version.yml +++ b/data/deprecations/14-10-dependency-scanning-default-java-version.yml @@ -2,7 +2,7 @@ announcement_milestone: "14.10" announcement_date: "2022-04-22" removal_milestone: "15.0" - removal_date: "2021-05-22" + removal_date: "2022-05-22" breaking_change: true reporter: NicoleSchwartz body: | diff --git a/data/deprecations/14-10-old-search-migration-removal.yml b/data/deprecations/14-10-old-search-migration-removal.yml index d7036150059..a0074c53ffb 100644 --- a/data/deprecations/14-10-old-search-migration-removal.yml +++ b/data/deprecations/14-10-old-search-migration-removal.yml @@ -2,7 +2,7 @@ announcement_milestone: "14.10" announcement_date: "2021-04-22" removal_milestone: "15.0" - removal_date: "2021-05-22" + removal_date: "2022-05-22" breaking_change: true body: | As Advanced Search migrations usually require support multiple code paths for a long period of time, it’s important to clean those up when we safely can. We use GitLab major version upgrades as a safe time to remove backward compatibility for indices that have not been fully migrated. See the [upgrade documentation](https://docs.gitlab.com/ee/update/index.html#upgrading-to-a-new-major-version) for details. diff --git a/data/deprecations/14-8-ci-build-variables.yml b/data/deprecations/14-8-ci-build-variables.yml index a87c6a2fa17..dba841841f2 100644 --- a/data/deprecations/14-8-ci-build-variables.yml +++ b/data/deprecations/14-8-ci-build-variables.yml @@ -1,6 +1,6 @@ - name: "`CI_BUILD_*` predefined variables" announcement_milestone: "14.8" - announcement_date: "2021-02-22" + announcement_date: "2022-02-22" removal_milestone: "16.0" removal_date: "2023-04-22" breaking_change: true diff --git a/data/deprecations/14-8-compliance-required-pipeline-configuration-premium.yml b/data/deprecations/14-8-compliance-required-pipeline-configuration-premium.yml index 104dbc5f72d..aabd330d567 100644 --- a/data/deprecations/14-8-compliance-required-pipeline-configuration-premium.yml +++ b/data/deprecations/14-8-compliance-required-pipeline-configuration-premium.yml @@ -1,6 +1,6 @@ - name: "Required pipeline configurations in Premium tier" announcement_milestone: "14.8" - announcement_date: "2021-02-22" + announcement_date: "2022-02-22" removal_milestone: "15.0" removal_date: "2022-05-22" breaking_change: true diff --git a/data/deprecations/14-8-compliance-status-check-api-field.yml b/data/deprecations/14-8-compliance-status-check-api-field.yml index b98dab9e905..ba8c84343bd 100644 --- a/data/deprecations/14-8-compliance-status-check-api-field.yml +++ b/data/deprecations/14-8-compliance-status-check-api-field.yml @@ -1,6 +1,6 @@ - name: "External status check API breaking changes" announcement_milestone: "14.8" - announcement_date: "2021-02-22" + announcement_date: "2022-02-22" removal_milestone: "15.0" removal_date: "2022-05-22" breaking_change: true diff --git a/data/deprecations/14-8-request-profiling.yml b/data/deprecations/14-8-request-profiling.yml index 82d2aadd149..ea3833d98ef 100644 --- a/data/deprecations/14-8-request-profiling.yml +++ b/data/deprecations/14-8-request-profiling.yml @@ -1,6 +1,6 @@ - name: "Request profiling" announcement_milestone: "14.8" - announcement_date: "2021-02-22" + announcement_date: "2022-02-22" removal_milestone: "15.0" removal_date: "2022-05-22" breaking_change: true diff --git a/data/deprecations/14-8-secure-ca-python-deprecation.yml b/data/deprecations/14-8-secure-ca-python-deprecation.yml index c97271e4db2..21b3b01a590 100644 --- a/data/deprecations/14-8-secure-ca-python-deprecation.yml +++ b/data/deprecations/14-8-secure-ca-python-deprecation.yml @@ -2,7 +2,7 @@ announcement_milestone: "14.8" # The milestone when this feature was first announced as deprecated. announcement_date: "2021-02-22" # The date of the milestone release when this feature was first announced as deprecated. This should almost always be the 22nd of a month (YYYY-MM-22), unless you did an out of band blog post. removal_milestone: "15.0" # The milestone when this feature is planned to be removed - removal_date: "2021-05-22" # The date of the milestone release when this feature was first announced as deprecated. This should almost always be the 22nd of a month (YYYY-MM-22), unless you did an out of band blog post. + removal_date: "2022-05-22" # The date of the milestone release when this feature was first announced as deprecated. This should almost always be the 22nd of a month (YYYY-MM-22), unless you did an out of band blog post. breaking_change: true # If this deprecation is a breaking change, set this value to true body: | # Do not modify this line, instead modify the lines below. For those using Dependency Scanning for Python projects, we are deprecating the default `gemnasium-python:2` image which uses Python 3.6 as well as the custom `gemnasium-python:2-python-3.9` image which uses Python 3.9. The new default image as of GitLab 15.0 will be for Python 3.9 as it is a [supported version](https://endoflife.date/python) and 3.6 [is no longer supported](https://endoflife.date/python). diff --git a/data/deprecations/distribution_deprecations_14-4.yml b/data/deprecations/distribution_deprecations_14-4.yml index 5b7163d5b4d..e54108d2947 100644 --- a/data/deprecations/distribution_deprecations_14-4.yml +++ b/data/deprecations/distribution_deprecations_14-4.yml @@ -1,6 +1,6 @@ - name: "Move `custom_hooks_dir` setting from GitLab Shell to Gitaly" # The name of the feature to be deprecated announcement_milestone: "14.9" # The milestone when this feature was first announced as deprecated. - announcement_date: "2021-10-22" + announcement_date: "2022-03-22" removal_milestone: "15.0" # the milestone when this feature is planned to be removed removal_date: "2022-05-22" body: | # Do not modify this line, instead modify the lines below. diff --git a/db/migrate/20220525123825_add_raw_to_ci_pipeline_variables.rb b/db/migrate/20220525123825_add_raw_to_ci_pipeline_variables.rb new file mode 100644 index 00000000000..258b4631643 --- /dev/null +++ b/db/migrate/20220525123825_add_raw_to_ci_pipeline_variables.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +class AddRawToCiPipelineVariables < Gitlab::Database::Migration[2.0] + enable_lock_retries! + + def change + add_column :ci_pipeline_variables, :raw, :boolean, null: false, default: true + end +end diff --git a/db/migrate/20220525123851_add_raw_to_ci_group_variables.rb b/db/migrate/20220525123851_add_raw_to_ci_group_variables.rb new file mode 100644 index 00000000000..9eae210d8c3 --- /dev/null +++ b/db/migrate/20220525123851_add_raw_to_ci_group_variables.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +class AddRawToCiGroupVariables < Gitlab::Database::Migration[2.0] + enable_lock_retries! + + def change + add_column :ci_group_variables, :raw, :boolean, null: false, default: true + end +end diff --git a/db/migrate/20220525123914_add_raw_to_ci_instance_variables.rb b/db/migrate/20220525123914_add_raw_to_ci_instance_variables.rb new file mode 100644 index 00000000000..71674b48e39 --- /dev/null +++ b/db/migrate/20220525123914_add_raw_to_ci_instance_variables.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +class AddRawToCiInstanceVariables < Gitlab::Database::Migration[2.0] + enable_lock_retries! + + def change + add_column :ci_instance_variables, :raw, :boolean, null: false, default: true + end +end diff --git a/db/migrate/20220525123940_add_raw_to_ci_job_variables.rb b/db/migrate/20220525123940_add_raw_to_ci_job_variables.rb new file mode 100644 index 00000000000..abd1f1eb211 --- /dev/null +++ b/db/migrate/20220525123940_add_raw_to_ci_job_variables.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +class AddRawToCiJobVariables < Gitlab::Database::Migration[2.0] + enable_lock_retries! + + def change + add_column :ci_job_variables, :raw, :boolean, null: false, default: true + end +end diff --git a/db/migrate/20220525124104_add_raw_to_ci_pipeline_schedule_variables.rb b/db/migrate/20220525124104_add_raw_to_ci_pipeline_schedule_variables.rb new file mode 100644 index 00000000000..c7a3b832552 --- /dev/null +++ b/db/migrate/20220525124104_add_raw_to_ci_pipeline_schedule_variables.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +class AddRawToCiPipelineScheduleVariables < Gitlab::Database::Migration[2.0] + enable_lock_retries! + + def change + add_column :ci_pipeline_schedule_variables, :raw, :boolean, null: false, default: true + end +end diff --git a/db/migrate/20220525124125_add_raw_to_ci_variables.rb b/db/migrate/20220525124125_add_raw_to_ci_variables.rb new file mode 100644 index 00000000000..168cd107d1c --- /dev/null +++ b/db/migrate/20220525124125_add_raw_to_ci_variables.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +class AddRawToCiVariables < Gitlab::Database::Migration[2.0] + enable_lock_retries! + + def change + add_column :ci_variables, :raw, :boolean, null: false, default: true + end +end diff --git a/db/post_migrate/20220418180958_remove_integrations_properties.rb b/db/post_migrate/20220418180958_remove_integrations_properties.rb new file mode 100644 index 00000000000..781b8c8ac72 --- /dev/null +++ b/db/post_migrate/20220418180958_remove_integrations_properties.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +class RemoveIntegrationsProperties < Gitlab::Database::Migration[2.0] + disable_ddl_transaction! + + def change + remove_column :integrations, :properties, :text + end +end diff --git a/db/post_migrate/20220525141540_migrate_project_service_worker_queue.rb b/db/post_migrate/20220525141540_migrate_project_service_worker_queue.rb new file mode 100644 index 00000000000..acfb8b227fe --- /dev/null +++ b/db/post_migrate/20220525141540_migrate_project_service_worker_queue.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +class MigrateProjectServiceWorkerQueue < Gitlab::Database::Migration[2.0] + def up + sidekiq_queue_migrate 'project_service', to: 'integrations_execute' + end + + def down + sidekiq_queue_migrate 'integrations_execute', to: 'project_service' + end +end diff --git a/db/post_migrate/20220530170915_add_index_for_vulnerability_state_transition.rb b/db/post_migrate/20220530170915_add_index_for_vulnerability_state_transition.rb new file mode 100644 index 00000000000..46ff79c2441 --- /dev/null +++ b/db/post_migrate/20220530170915_add_index_for_vulnerability_state_transition.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +class AddIndexForVulnerabilityStateTransition < Gitlab::Database::Migration[2.0] + disable_ddl_transaction! + NEW_INDEX_NAME = 'index_vulnerability_state_transitions_id_and_vulnerability_id' + OLD_INDEX_NAME = 'index_vulnerability_state_transitions_on_vulnerability_id' + + def up + add_concurrent_index(:vulnerability_state_transitions, [:vulnerability_id, :id], name: NEW_INDEX_NAME) + + remove_concurrent_index_by_name(:vulnerability_state_transitions, OLD_INDEX_NAME) + end + + def down + remove_concurrent_index_by_name(:vulnerability_state_transitions, NEW_INDEX_NAME) + + add_concurrent_index(:vulnerability_state_transitions, [:vulnerability_id], name: OLD_INDEX_NAME) + end +end diff --git a/db/post_migrate/20220601040233_finalize_backfill_issue_search_data.rb b/db/post_migrate/20220601040233_finalize_backfill_issue_search_data.rb new file mode 100644 index 00000000000..7b5cd405fa8 --- /dev/null +++ b/db/post_migrate/20220601040233_finalize_backfill_issue_search_data.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +class FinalizeBackfillIssueSearchData < Gitlab::Database::Migration[2.0] + MIGRATION = 'BackfillIssueSearchData' + disable_ddl_transaction! + + restrict_gitlab_migration gitlab_schema: :gitlab_main + + def up + ensure_batched_background_migration_is_finished( + job_class_name: MIGRATION, + table_name: :issues, + column_name: :id, + job_arguments: [], + finalize: true + ) + end + + def down + # no-op + end +end diff --git a/db/schema_migrations/20220418180958 b/db/schema_migrations/20220418180958 new file mode 100644 index 00000000000..74aaa9c2f46 --- /dev/null +++ b/db/schema_migrations/20220418180958 @@ -0,0 +1 @@ +0108fa3b92704107f712552b51eb3addd53f1482db4866a3b8ccaba2a52239ba
\ No newline at end of file diff --git a/db/schema_migrations/20220525123825 b/db/schema_migrations/20220525123825 new file mode 100644 index 00000000000..47d4bc2c8a3 --- /dev/null +++ b/db/schema_migrations/20220525123825 @@ -0,0 +1 @@ +8a30ec71e2c28929e0a7ebf744941246e460c37745e60dcd9f13a94b7d005772
\ No newline at end of file diff --git a/db/schema_migrations/20220525123851 b/db/schema_migrations/20220525123851 new file mode 100644 index 00000000000..fd16775f784 --- /dev/null +++ b/db/schema_migrations/20220525123851 @@ -0,0 +1 @@ +f6fcea6f6beef6c2d4848bd4bc11f0854acc9e19771438778f763171e0eaa3c7
\ No newline at end of file diff --git a/db/schema_migrations/20220525123914 b/db/schema_migrations/20220525123914 new file mode 100644 index 00000000000..564ceb0dbe2 --- /dev/null +++ b/db/schema_migrations/20220525123914 @@ -0,0 +1 @@ +504e43ab17c644707c65e396b8aa88a11472372a9c3b8d2b9ef88b9de978b0c3
\ No newline at end of file diff --git a/db/schema_migrations/20220525123940 b/db/schema_migrations/20220525123940 new file mode 100644 index 00000000000..7bb5b598247 --- /dev/null +++ b/db/schema_migrations/20220525123940 @@ -0,0 +1 @@ +7ddd1f03efe86f45b6105c6b0816e28e318e9de219dcd38801a11451745ae5f9
\ No newline at end of file diff --git a/db/schema_migrations/20220525124104 b/db/schema_migrations/20220525124104 new file mode 100644 index 00000000000..229fb6ae2a6 --- /dev/null +++ b/db/schema_migrations/20220525124104 @@ -0,0 +1 @@ +8c1ccabb6d2b3054398a015836bb9fe06f28936625f7a8220b4c58000a891b8a
\ No newline at end of file diff --git a/db/schema_migrations/20220525124125 b/db/schema_migrations/20220525124125 new file mode 100644 index 00000000000..8ccc434a7ac --- /dev/null +++ b/db/schema_migrations/20220525124125 @@ -0,0 +1 @@ +5e9f67479903590d5118e04811bc3c4aacf92fd11b90efa011975d4292dd0207
\ No newline at end of file diff --git a/db/schema_migrations/20220525141540 b/db/schema_migrations/20220525141540 new file mode 100644 index 00000000000..5d44edb76dd --- /dev/null +++ b/db/schema_migrations/20220525141540 @@ -0,0 +1 @@ +ecb575072a1176378b180e95090915b191792ce350df84c6a0c198dfb816df96
\ No newline at end of file diff --git a/db/schema_migrations/20220530170915 b/db/schema_migrations/20220530170915 new file mode 100644 index 00000000000..9fa7d0128a2 --- /dev/null +++ b/db/schema_migrations/20220530170915 @@ -0,0 +1 @@ +6182d4a468348076aab761714990dd55f69f44a5fafcf566fd11b73486c7d656
\ No newline at end of file diff --git a/db/schema_migrations/20220601040233 b/db/schema_migrations/20220601040233 new file mode 100644 index 00000000000..5acfd2851ca --- /dev/null +++ b/db/schema_migrations/20220601040233 @@ -0,0 +1 @@ +d7e3650b7f83a324c6c7f8da0ec37096c0e538072ab8fd0ac00672fa02e92c77
\ No newline at end of file diff --git a/db/structure.sql b/db/structure.sql index 5f7a15891d9..8dce81b5e1c 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -12534,6 +12534,7 @@ CREATE TABLE ci_group_variables ( masked boolean DEFAULT false NOT NULL, variable_type smallint DEFAULT 1 NOT NULL, environment_scope text DEFAULT '*'::text NOT NULL, + raw boolean DEFAULT true NOT NULL, CONSTRAINT check_dfe009485a CHECK ((char_length(environment_scope) <= 255)) ); @@ -12554,6 +12555,7 @@ CREATE TABLE ci_instance_variables ( key text NOT NULL, encrypted_value text, encrypted_value_iv text, + raw boolean DEFAULT true NOT NULL, CONSTRAINT check_07a45a5bcb CHECK ((char_length(encrypted_value_iv) <= 255)), CONSTRAINT check_5aede12208 CHECK ((char_length(key) <= 255)), CONSTRAINT check_956afd70f1 CHECK ((char_length(encrypted_value) <= 13579)) @@ -12642,7 +12644,8 @@ CREATE TABLE ci_job_variables ( encrypted_value_iv character varying, job_id bigint NOT NULL, variable_type smallint DEFAULT 1 NOT NULL, - source smallint DEFAULT 0 NOT NULL + source smallint DEFAULT 0 NOT NULL, + raw boolean DEFAULT true NOT NULL ); CREATE SEQUENCE ci_job_variables_id_seq @@ -12808,7 +12811,8 @@ CREATE TABLE ci_pipeline_schedule_variables ( pipeline_schedule_id integer NOT NULL, created_at timestamp with time zone, updated_at timestamp with time zone, - variable_type smallint DEFAULT 1 NOT NULL + variable_type smallint DEFAULT 1 NOT NULL, + raw boolean DEFAULT true NOT NULL ); CREATE SEQUENCE ci_pipeline_schedule_variables_id_seq @@ -12851,7 +12855,8 @@ CREATE TABLE ci_pipeline_variables ( encrypted_value_salt character varying, encrypted_value_iv character varying, pipeline_id integer NOT NULL, - variable_type smallint DEFAULT 1 NOT NULL + variable_type smallint DEFAULT 1 NOT NULL, + raw boolean DEFAULT true NOT NULL ); CREATE SEQUENCE ci_pipeline_variables_id_seq @@ -13292,7 +13297,8 @@ CREATE TABLE ci_variables ( protected boolean DEFAULT false NOT NULL, environment_scope character varying DEFAULT '*'::character varying NOT NULL, masked boolean DEFAULT false NOT NULL, - variable_type smallint DEFAULT 1 NOT NULL + variable_type smallint DEFAULT 1 NOT NULL, + raw boolean DEFAULT true NOT NULL ); CREATE SEQUENCE ci_variables_id_seq @@ -16195,7 +16201,6 @@ CREATE TABLE integrations ( created_at timestamp without time zone, updated_at timestamp without time zone, active boolean DEFAULT false NOT NULL, - properties text, push_events boolean DEFAULT true, issues_events boolean DEFAULT true, merge_requests_events boolean DEFAULT true, @@ -29819,7 +29824,7 @@ CREATE UNIQUE INDEX index_vulnerability_remediations_on_project_id_and_checksum CREATE UNIQUE INDEX index_vulnerability_scanners_on_project_id_and_external_id ON vulnerability_scanners USING btree (project_id, external_id); -CREATE INDEX index_vulnerability_state_transitions_on_vulnerability_id ON vulnerability_state_transitions USING btree (vulnerability_id); +CREATE INDEX index_vulnerability_state_transitions_id_and_vulnerability_id ON vulnerability_state_transitions USING btree (vulnerability_id, id); CREATE INDEX index_vulnerability_statistics_on_latest_pipeline_id ON vulnerability_statistics USING btree (latest_pipeline_id); diff --git a/doc/update/deprecations.md b/doc/update/deprecations.md index 73f1d3752fe..3f90f540c7a 100644 --- a/doc/update/deprecations.md +++ b/doc/update/deprecations.md @@ -158,7 +158,7 @@ GitLab 15.2 to simplify the codebase and prevent any unwanted performance degrad ### Dependency Scanning default Java version changed to 17 -Planned removal: GitLab <span class="removal-milestone">15.0</span> (2021-05-22) +Planned removal: GitLab <span class="removal-milestone">15.0</span> (2022-05-22) WARNING: This is a [breaking change](https://docs.gitlab.com/ee/development/contributing/#breaking-changes). @@ -204,7 +204,7 @@ For more information about iteration cadences, you can refer to ### Outdated indices of Advanced Search migrations -Planned removal: GitLab <span class="removal-milestone">15.0</span> (2021-05-22) +Planned removal: GitLab <span class="removal-milestone">15.0</span> (2022-05-22) WARNING: This is a [breaking change](https://docs.gitlab.com/ee/development/contributing/#breaking-changes). @@ -412,7 +412,7 @@ For additional context, or to provide feedback regarding this change, please ref ### Dependency Scanning Python 3.9 and 3.6 image deprecation -Planned removal: GitLab <span class="removal-milestone">15.0</span> (2021-05-22) +Planned removal: GitLab <span class="removal-milestone">15.0</span> (2022-05-22) WARNING: This is a [breaking change](https://docs.gitlab.com/ee/development/contributing/#breaking-changes). diff --git a/doc/user/permissions.md b/doc/user/permissions.md index b4822f48be0..dc8796ffe4d 100644 --- a/doc/user/permissions.md +++ b/doc/user/permissions.md @@ -158,7 +158,7 @@ The following table lists project permissions available for each role: | [Projects](project/index.md):<br>Edit project badges | | | | ✓ | ✓ | | [Projects](project/index.md):<br>Edit project settings | | | | ✓ | ✓ | | [Projects](project/index.md):<br>Export project | | | | ✓ | ✓ | -| [Projects](project/index.md):<br>Manage [project access tokens](project/settings/project_access_tokens.md) (*11*) | | | | ✓ | ✓ | +| [Projects](project/index.md):<br>Manage [project access tokens](project/settings/project_access_tokens.md) (*11*) | | | | ✓ (*21*) | ✓ | | [Projects](project/index.md):<br>Manage [Project Operations](../operations/index.md) | | | | ✓ | ✓ | | [Projects](project/index.md):<br>Rename project | | | | ✓ | ✓ | | [Projects](project/index.md):<br>Share (invite) projects with groups | | | | ✓ (*7*) | ✓ (*7*) | @@ -238,7 +238,7 @@ The following table lists project permissions available for each role: 18. Authors and assignees of issues can modify the title and description even if they don't have the Reporter role. 19. Authors and assignees can close and reopen issues even if they don't have the Reporter role. 20. The ability to view the Container Registry and pull images is controlled by the [Container Registry's visibility permissions](packages/container_registry/index.md#container-registry-visibility-permissions). -21. Maintainers cannot create, demote, or remove Owners, and they cannot promote users to the Owner role. +21. Maintainers cannot create, demote, or remove Owners, and they cannot promote users to the Owner role. They also cannot approve Owner role access requests. <!-- markdownlint-enable MD029 --> diff --git a/doc/user/project/integrations/slack.md b/doc/user/project/integrations/slack.md index 870554100b7..bd93fbcbcbc 100644 --- a/doc/user/project/integrations/slack.md +++ b/doc/user/project/integrations/slack.md @@ -91,7 +91,7 @@ the error message and keep troubleshooting from there. You might see an entry like the following in your Sidekiq log: ```plaintext -2019-01-10_13:22:08.42572 2019-01-10T13:22:08.425Z 6877 TID-abcdefg ProjectServiceWorker JID-3bade5fb3dd47a85db6d78c5 ERROR: {:class=>"ProjectServiceWorker", :service_class=>"SlackService", :message=>"SSL_connect returned=1 errno=0 state=error: certificate verify failed"} +2019-01-10_13:22:08.42572 2019-01-10T13:22:08.425Z 6877 TID-abcdefg Integrations::ExecuteWorker JID-3bade5fb3dd47a85db6d78c5 ERROR: {:class=>"Integrations::ExecuteWorker :service_class=>"SlackService", :message=>"SSL_connect returned=1 errno=0 state=error: certificate verify failed"} ``` This issue occurs when there is a problem with GitLab communicating with Slack, diff --git a/doc/user/project/members/index.md b/doc/user/project/members/index.md index 28bd353d8cc..7bea57d180b 100644 --- a/doc/user/project/members/index.md +++ b/doc/user/project/members/index.md @@ -225,9 +225,10 @@ GitLab users can request to become a member of a project. An email is sent to the most recently active project maintainers. Up to ten project maintainers are notified. -Any project maintainer can approve or decline the request. +Any project owner or maintainer can approve or decline the request. +Project maintainers cannot approve Owner role access requests. -If a project does not have any maintainers, the notification is sent to the +If a project does not have any direct owners or maintainers, the notification is sent to the most recently active owners of the project's group. If you change your mind before your request is approved, select diff --git a/lib/gitlab/gfm/reference_rewriter.rb b/lib/gitlab/gfm/reference_rewriter.rb index 5d0a638f97a..40dcac5f46f 100644 --- a/lib/gitlab/gfm/reference_rewriter.rb +++ b/lib/gitlab/gfm/reference_rewriter.rb @@ -31,30 +31,41 @@ module Gitlab # http://gitlab.com/some/link/#1234, and code `puts #1234`' # class ReferenceRewriter + include Gitlab::Utils::StrongMemoize + RewriteError = Class.new(StandardError) - def initialize(text, source_parent, current_user) + def initialize(text, text_html, source_parent, current_user) @text = text + + # If for some reason cached html is not present it gets rendered here + @text_html = text_html || original_html + @source_parent = source_parent @current_user = current_user - @original_html = markdown(text) @pattern = Gitlab::ReferenceExtractor.references_pattern end def rewrite(target_parent) return @text unless needs_rewrite? - @text.gsub(@pattern) do |reference| + @text.gsub!(@pattern) do |reference| unfold_reference(reference, Regexp.last_match, target_parent) end end def needs_rewrite? - @text =~ @pattern + strong_memoize(:needs_rewrite) { @text_html.include?('data-reference-type=') } end private + def original_html + strong_memoize(:original_html) do + markdown(@text) + end + end + def unfold_reference(reference, match, target_parent) before = @text[0...match.begin(0)] after = @text[match.end(0)..] @@ -89,7 +100,7 @@ module Gitlab end def substitution_valid?(substituted) - @original_html == markdown(substituted) + original_html == markdown(substituted) end def markdown(text) diff --git a/lib/gitlab/gfm/uploads_rewriter.rb b/lib/gitlab/gfm/uploads_rewriter.rb index 82ef7eed56a..b0bf68f4204 100644 --- a/lib/gitlab/gfm/uploads_rewriter.rb +++ b/lib/gitlab/gfm/uploads_rewriter.rb @@ -12,7 +12,9 @@ module Gitlab # # class UploadsRewriter - def initialize(text, source_project, _current_user) + include Gitlab::Utils::StrongMemoize + + def initialize(text, _text_html, source_project, _current_user) @text = text @source_project = source_project @pattern = FileUploader::MARKDOWN_PATTERN @@ -21,7 +23,7 @@ module Gitlab def rewrite(target_parent) return @text unless needs_rewrite? - @text.gsub(@pattern) do |markdown| + @text.gsub!(@pattern) do |markdown| file = find_file($~[:secret], $~[:file]) # No file will be returned for a path traversal next if file.nil? @@ -43,15 +45,9 @@ module Gitlab end def needs_rewrite? - files.any? - end - - def files - referenced_files = @text.scan(@pattern).map do - find_file($~[:secret], $~[:file]) + strong_memoize(:needs_rewrite) do + FileUploader::MARKDOWN_PATTERN.match?(@text) end - - referenced_files.compact.select(&:exists?) end def was_embedded?(markdown) diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 1b4368c7e8f..55cc184d89e 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -8978,6 +8978,9 @@ msgstr "" msgid "Collapse issues" msgstr "" +msgid "Collapse jobs" +msgstr "" + msgid "Collapse milestones" msgstr "" @@ -15193,13 +15196,13 @@ msgstr "" msgid "Expand issues" msgstr "" -msgid "Expand milestones" +msgid "Expand jobs" msgstr "" -msgid "Expand panel" +msgid "Expand milestones" msgstr "" -msgid "Expand pipeline" +msgid "Expand panel" msgstr "" msgid "Expand settings section" diff --git a/spec/controllers/admin/integrations_controller_spec.rb b/spec/controllers/admin/integrations_controller_spec.rb index 410bc0ddc1d..0e456858b49 100644 --- a/spec/controllers/admin/integrations_controller_spec.rb +++ b/spec/controllers/admin/integrations_controller_spec.rb @@ -43,7 +43,7 @@ RSpec.describe Admin::IntegrationsController do end describe '#update' do - include JiraServiceHelper + include JiraIntegrationHelpers let(:integration) { create(:jira_integration, :instance) } diff --git a/spec/controllers/groups/settings/integrations_controller_spec.rb b/spec/controllers/groups/settings/integrations_controller_spec.rb index c070094babd..377c38ce087 100644 --- a/spec/controllers/groups/settings/integrations_controller_spec.rb +++ b/spec/controllers/groups/settings/integrations_controller_spec.rb @@ -76,7 +76,7 @@ RSpec.describe Groups::Settings::IntegrationsController do end describe '#update' do - include JiraServiceHelper + include JiraIntegrationHelpers let(:integration) { create(:jira_integration, :group, group: group) } diff --git a/spec/controllers/projects/import/jira_controller_spec.rb b/spec/controllers/projects/import/jira_controller_spec.rb index 5288c0fcf21..3f149afbb02 100644 --- a/spec/controllers/projects/import/jira_controller_spec.rb +++ b/spec/controllers/projects/import/jira_controller_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' RSpec.describe Projects::Import::JiraController do - include JiraServiceHelper + include JiraIntegrationHelpers let_it_be(:user) { create(:user) } let_it_be(:project) { create(:project) } diff --git a/spec/controllers/projects/settings/integrations_controller_spec.rb b/spec/controllers/projects/settings/integrations_controller_spec.rb index 16f32ee83b4..e6ca088a533 100644 --- a/spec/controllers/projects/settings/integrations_controller_spec.rb +++ b/spec/controllers/projects/settings/integrations_controller_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' RSpec.describe Projects::Settings::IntegrationsController do - include JiraServiceHelper + include JiraIntegrationHelpers include AfterNextHelpers let_it_be(:project) { create(:project, :repository) } diff --git a/spec/factories/application_settings.rb b/spec/factories/application_settings.rb index c28d3c20a86..844e21df60c 100644 --- a/spec/factories/application_settings.rb +++ b/spec/factories/application_settings.rb @@ -5,5 +5,9 @@ FactoryBot.define do default_projects_limit { 42 } import_sources { [] } restricted_visibility_levels { [] } + + after(:build) do |settings| + settings.ensure_key_restrictions! + end end end diff --git a/spec/features/projects/integrations/user_activates_jira_spec.rb b/spec/features/projects/integrations/user_activates_jira_spec.rb index b63c7a115bc..dad201ffbb6 100644 --- a/spec/features/projects/integrations/user_activates_jira_spec.rb +++ b/spec/features/projects/integrations/user_activates_jira_spec.rb @@ -61,7 +61,7 @@ RSpec.describe 'User activates Jira', :js do end describe 'user disables the Jira integration' do - include JiraServiceHelper + include JiraIntegrationHelpers before do stub_jira_integration_test diff --git a/spec/features/projects/integrations/user_uses_inherited_settings_spec.rb b/spec/features/projects/integrations/user_uses_inherited_settings_spec.rb index fcb04c338a9..8a2881c95dc 100644 --- a/spec/features/projects/integrations/user_uses_inherited_settings_spec.rb +++ b/spec/features/projects/integrations/user_uses_inherited_settings_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' RSpec.describe 'User uses inherited settings', :js do - include JiraServiceHelper + include JiraIntegrationHelpers include_context 'project integration activation' diff --git a/spec/frontend/notes/components/notes_app_spec.js b/spec/frontend/notes/components/notes_app_spec.js index e018523472b..f4eb69e0d49 100644 --- a/spec/frontend/notes/components/notes_app_spec.js +++ b/spec/frontend/notes/components/notes_app_spec.js @@ -222,7 +222,7 @@ describe('note_app', () => { }); it('renders skeleton notes', () => { - expect(wrapper.find('.animation-container').exists()).toBe(true); + expect(wrapper.find('.gl-skeleton-loader-default-container').exists()).toBe(true); }); it('should render form', () => { diff --git a/spec/frontend/pipelines/graph/linked_pipeline_spec.js b/spec/frontend/pipelines/graph/linked_pipeline_spec.js index 1a66320dd29..1e693184d73 100644 --- a/spec/frontend/pipelines/graph/linked_pipeline_spec.js +++ b/spec/frontend/pipelines/graph/linked_pipeline_spec.js @@ -200,10 +200,14 @@ describe('Linked pipeline', () => { expect(findRetryButton().exists()).toBe(true); }); - it('hides the card tooltip when the action button tooltip is hovered', async () => { + it.each` + findElement | name + ${findRetryButton} | ${'retry button'} + ${findExpandButton} | ${'expand button'} + `('hides the card tooltip when $name is hovered', async ({ findElement }) => { expect(findCardTooltip().exists()).toBe(true); - await findRetryButton().trigger('mouseover'); + await findElement().trigger('mouseover'); expect(findCardTooltip().exists()).toBe(false); }); @@ -262,10 +266,14 @@ describe('Linked pipeline', () => { expect(findRetryButton().exists()).toBe(false); }); - it('hides the card tooltip when the action button tooltip is hovered', async () => { + it.each` + findElement | name + ${findCancelButton} | ${'cancel button'} + ${findExpandButton} | ${'expand button'} + `('hides the card tooltip when $name is hovered', async ({ findElement }) => { expect(findCardTooltip().exists()).toBe(true); - await findCancelButton().trigger('mouseover'); + await findElement().trigger('mouseover'); expect(findCardTooltip().exists()).toBe(false); }); diff --git a/spec/lib/gitlab/background_migration/encrypt_integration_properties_spec.rb b/spec/lib/gitlab/background_migration/encrypt_integration_properties_spec.rb index 7334867e8fb..38e8b159e63 100644 --- a/spec/lib/gitlab/background_migration/encrypt_integration_properties_spec.rb +++ b/spec/lib/gitlab/background_migration/encrypt_integration_properties_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require 'spec_helper' -RSpec.describe Gitlab::BackgroundMigration::EncryptIntegrationProperties do +RSpec.describe Gitlab::BackgroundMigration::EncryptIntegrationProperties, schema: 20220415124804 do let(:integrations) do table(:integrations) do |integrations| integrations.send :attr_encrypted, :encrypted_properties_tmp, diff --git a/spec/lib/gitlab/gfm/reference_rewriter_spec.rb b/spec/lib/gitlab/gfm/reference_rewriter_spec.rb index 7d4a3655be6..8bb649e78e0 100644 --- a/spec/lib/gitlab/gfm/reference_rewriter_spec.rb +++ b/spec/lib/gitlab/gfm/reference_rewriter_spec.rb @@ -10,6 +10,7 @@ RSpec.describe Gitlab::Gfm::ReferenceRewriter do let(:old_project) { create(:project, name: 'old-project', group: group) } let(:old_project_ref) { old_project.to_reference_base(new_project) } let(:text) { 'some text' } + let(:note) { create(:note, note: text, project: old_project) } before do old_project.add_reporter(user) @@ -17,7 +18,7 @@ RSpec.describe Gitlab::Gfm::ReferenceRewriter do describe '#rewrite' do subject do - described_class.new(text, old_project, user).rewrite(new_project) + described_class.new(note.note, note.note_html, old_project, user).rewrite(new_project) end context 'multiple issues and merge requests referenced' do diff --git a/spec/lib/gitlab/gfm/uploads_rewriter_spec.rb b/spec/lib/gitlab/gfm/uploads_rewriter_spec.rb index f878f02f410..763e6f1b5f4 100644 --- a/spec/lib/gitlab/gfm/uploads_rewriter_spec.rb +++ b/spec/lib/gitlab/gfm/uploads_rewriter_spec.rb @@ -6,7 +6,7 @@ RSpec.describe Gitlab::Gfm::UploadsRewriter do let(:user) { create(:user) } let(:old_project) { create(:project) } let(:new_project) { create(:project) } - let(:rewriter) { described_class.new(text, old_project, user) } + let(:rewriter) { described_class.new(+text, nil, old_project, user) } context 'text contains links to uploads' do let(:image_uploader) do @@ -22,13 +22,21 @@ RSpec.describe Gitlab::Gfm::UploadsRewriter do "Text and #{image_uploader.markdown_link} and #{zip_uploader.markdown_link}" end + def referenced_files(text, project) + referenced_files = text.scan(FileUploader::MARKDOWN_PATTERN).map do + UploaderFinder.new(project, $~[:secret], $~[:file]).execute + end + + referenced_files.compact.select(&:exists?) + end + shared_examples "files are accessible" do describe '#rewrite' do let!(:new_text) { rewriter.rewrite(new_project) } let(:old_files) { [image_uploader, zip_uploader] } let(:new_files) do - described_class.new(new_text, new_project, user).files + referenced_files(new_text, new_project) end let(:old_paths) { old_files.map(&:path) } @@ -68,9 +76,9 @@ RSpec.describe Gitlab::Gfm::UploadsRewriter do it 'does not rewrite plain links as embedded' do embedded_link = image_uploader.markdown_link plain_image_link = embedded_link.delete_prefix('!') - text = "#{plain_image_link} and #{embedded_link}" + text = +"#{plain_image_link} and #{embedded_link}" - moved_text = described_class.new(text, old_project, user).rewrite(new_project) + moved_text = described_class.new(text, nil, old_project, user).rewrite(new_project) expect(moved_text.scan(/!\[.*?\]/).count).to eq(1) expect(moved_text.scan(/\A\[.*?\]/).count).to eq(1) @@ -97,11 +105,5 @@ RSpec.describe Gitlab::Gfm::UploadsRewriter do it { is_expected.to eq true } end - - describe '#files' do - subject { rewriter.files } - - it { is_expected.to be_an(Array) } - end end end diff --git a/spec/lib/gitlab/jira_import/base_importer_spec.rb b/spec/lib/gitlab/jira_import/base_importer_spec.rb index 479551095de..70a594b09af 100644 --- a/spec/lib/gitlab/jira_import/base_importer_spec.rb +++ b/spec/lib/gitlab/jira_import/base_importer_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' RSpec.describe Gitlab::JiraImport::BaseImporter do - include JiraServiceHelper + include JiraIntegrationHelpers let(:project) { create(:project) } diff --git a/spec/lib/gitlab/jira_import/issues_importer_spec.rb b/spec/lib/gitlab/jira_import/issues_importer_spec.rb index aead5405bd1..565a9ad17e1 100644 --- a/spec/lib/gitlab/jira_import/issues_importer_spec.rb +++ b/spec/lib/gitlab/jira_import/issues_importer_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' RSpec.describe Gitlab::JiraImport::IssuesImporter do - include JiraServiceHelper + include JiraIntegrationHelpers let_it_be(:user) { create(:user) } let_it_be(:current_user) { create(:user) } diff --git a/spec/lib/gitlab/jira_import/labels_importer_spec.rb b/spec/lib/gitlab/jira_import/labels_importer_spec.rb index 71440590815..4fb5e363475 100644 --- a/spec/lib/gitlab/jira_import/labels_importer_spec.rb +++ b/spec/lib/gitlab/jira_import/labels_importer_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' RSpec.describe Gitlab::JiraImport::LabelsImporter do - include JiraServiceHelper + include JiraIntegrationHelpers let_it_be(:user) { create(:user) } let_it_be(:group) { create(:group) } diff --git a/spec/lib/gitlab/jira_import_spec.rb b/spec/lib/gitlab/jira_import_spec.rb index a7c73e79641..972b0ab6ed1 100644 --- a/spec/lib/gitlab/jira_import_spec.rb +++ b/spec/lib/gitlab/jira_import_spec.rb @@ -6,7 +6,7 @@ RSpec.describe Gitlab::JiraImport do let(:project_id) { 321 } describe '.validate_project_settings!' do - include JiraServiceHelper + include JiraIntegrationHelpers let_it_be(:project, reload: true) { create(:project) } diff --git a/spec/models/application_setting_spec.rb b/spec/models/application_setting_spec.rb index 644fee97613..61f008416ea 100644 --- a/spec/models/application_setting_spec.rb +++ b/spec/models/application_setting_spec.rb @@ -554,11 +554,45 @@ RSpec.describe ApplicationSetting do it { is_expected.to allow_value(*KeyRestrictionValidator.supported_key_restrictions(type)).for(field) } it { is_expected.not_to allow_value(128).for(field) } end + end + end - it_behaves_like 'key validations' + describe '#ensure_key_restrictions!' do + context 'with non-compliant FIPS settings' do + before do + setting.update_columns( + rsa_key_restriction: 1024, + dsa_key_restriction: 0, + ecdsa_key_restriction: 521, + ed25519_key_restriction: -1, + ecdsa_sk_key_restriction: 0, + ed25519_sk_key_restriction: 0 + ) + end - context 'FIPS mode', :fips_mode do - it_behaves_like 'key validations' + context 'in non-FIPS mode', fips_mode: false do + it 'keeps existing key restrictions' do + expect { setting.ensure_key_restrictions! }.not_to change { setting.valid? } + expect(setting).to be_valid + expect(setting.rsa_key_restriction).to eq(1024) + expect(setting.dsa_key_restriction).to eq(0) + expect(setting.ecdsa_key_restriction).to eq(521) + expect(setting.ed25519_key_restriction).to eq(-1) + expect(setting.ecdsa_sk_key_restriction).to eq(0) + expect(setting.ed25519_sk_key_restriction).to eq(0) + end + end + + context 'in FIPS mode', :fips_mode do + it 'updates key restrictions to meet FIPS compliance' do + expect { setting.ensure_key_restrictions! }.to change { setting.valid? }.from(false).to(true) + expect(setting.rsa_key_restriction).to eq(3072) + expect(setting.dsa_key_restriction).to eq(-1) + expect(setting.ecdsa_key_restriction).to eq(521) + expect(setting.ed25519_key_restriction).to eq(-1) + expect(setting.ecdsa_sk_key_restriction).to eq(256) + expect(setting.ed25519_sk_key_restriction).to eq(256) + end end end end diff --git a/spec/models/concerns/cache_markdown_field_spec.rb b/spec/models/concerns/cache_markdown_field_spec.rb index d46f22b2216..a00129b3fdf 100644 --- a/spec/models/concerns/cache_markdown_field_spec.rb +++ b/spec/models/concerns/cache_markdown_field_spec.rb @@ -404,6 +404,16 @@ RSpec.describe CacheMarkdownField, :clean_gitlab_redis_cache do it 'returns false when there are no changes' do expect(thing.attribute_invalidated?(:description_html)).to eq(false) end + + it 'returns false if skip_markdown_cache_validation is true' do + # invalidates the attribute + thing.cached_markdown_version += 1 + thing.description = updated_markdown + + thing.skip_markdown_cache_validation = true + + expect(thing.attribute_invalidated?(:description_html)).to eq(false) + end end context 'when cache version is updated' do diff --git a/spec/models/integration_spec.rb b/spec/models/integration_spec.rb index 0d38e10c5e6..c4175518295 100644 --- a/spec/models/integration_spec.rb +++ b/spec/models/integration_spec.rb @@ -1205,4 +1205,46 @@ RSpec.describe Integration do end end end + + describe '#async_execute' do + let(:integration) { described_class.new(id: 123) } + let(:data) { { object_kind: 'push' } } + let(:supported_events) { %w[push] } + + subject(:async_execute) { integration.async_execute(data) } + + before do + allow(integration).to receive(:supported_events).and_return(supported_events) + end + + it 'queues a Integrations::ExecuteWorker' do + expect(Integrations::ExecuteWorker).to receive(:perform_async).with(integration.id, data) + expect(ProjectServiceWorker).not_to receive(:perform_async) + + async_execute + end + + context 'when the event is not supported' do + let(:supported_events) { %w[issue] } + + it 'does not queue a worker' do + expect(Integrations::ExecuteWorker).not_to receive(:perform_async) + + async_execute + end + end + + context 'when the FF :rename_integration_workers is disabled' do + before do + stub_feature_flags(rename_integrations_workers: false) + end + + it 'queues a ProjectServiceWorker' do + expect(ProjectServiceWorker).to receive(:perform_async).with(integration.id, data) + expect(Integrations::ExecuteWorker).not_to receive(:perform_async) + + async_execute + end + end + end end diff --git a/spec/requests/api/graphql/mutations/jira_import/import_users_spec.rb b/spec/requests/api/graphql/mutations/jira_import/import_users_spec.rb index 45cc70f09fd..b438e1ba881 100644 --- a/spec/requests/api/graphql/mutations/jira_import/import_users_spec.rb +++ b/spec/requests/api/graphql/mutations/jira_import/import_users_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' RSpec.describe 'Importing Jira Users' do - include JiraServiceHelper + include JiraIntegrationHelpers include GraphqlHelpers let_it_be(:user) { create(:user) } diff --git a/spec/requests/api/graphql/mutations/jira_import/start_spec.rb b/spec/requests/api/graphql/mutations/jira_import/start_spec.rb index b14305281af..1508ba31e37 100644 --- a/spec/requests/api/graphql/mutations/jira_import/start_spec.rb +++ b/spec/requests/api/graphql/mutations/jira_import/start_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' RSpec.describe 'Starting a Jira Import' do - include JiraServiceHelper + include JiraIntegrationHelpers include GraphqlHelpers let_it_be(:user) { create(:user) } diff --git a/spec/services/bulk_create_integration_service_spec.rb b/spec/services/bulk_create_integration_service_spec.rb index ddc95ff92d5..22bb1736f9f 100644 --- a/spec/services/bulk_create_integration_service_spec.rb +++ b/spec/services/bulk_create_integration_service_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' RSpec.describe BulkCreateIntegrationService do - include JiraServiceHelper + include JiraIntegrationHelpers before_all do stub_jira_integration_test diff --git a/spec/services/bulk_update_integration_service_spec.rb b/spec/services/bulk_update_integration_service_spec.rb index 23e2a0ef0ff..e3e38aacaa2 100644 --- a/spec/services/bulk_update_integration_service_spec.rb +++ b/spec/services/bulk_update_integration_service_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' RSpec.describe BulkUpdateIntegrationService do - include JiraServiceHelper + include JiraIntegrationHelpers before_all do stub_jira_integration_test diff --git a/spec/services/git/branch_push_service_spec.rb b/spec/services/git/branch_push_service_spec.rb index 57c130f76a4..befa9598964 100644 --- a/spec/services/git/branch_push_service_spec.rb +++ b/spec/services/git/branch_push_service_spec.rb @@ -410,7 +410,7 @@ RSpec.describe Git::BranchPushService, services: true do end context "for jira issue tracker" do - include JiraServiceHelper + include JiraIntegrationHelpers let(:jira_tracker) { project.create_jira_integration if project.jira_integration.nil? } diff --git a/spec/services/integrations/propagate_service_spec.rb b/spec/services/integrations/propagate_service_spec.rb index 7ae843f6aeb..c971c4a0ad0 100644 --- a/spec/services/integrations/propagate_service_spec.rb +++ b/spec/services/integrations/propagate_service_spec.rb @@ -4,7 +4,7 @@ require 'spec_helper' RSpec.describe Integrations::PropagateService do describe '.propagate' do - include JiraServiceHelper + include JiraIntegrationHelpers before do stub_jira_integration_test diff --git a/spec/services/jira_import/start_import_service_spec.rb b/spec/services/jira_import/start_import_service_spec.rb index e04e3314158..510f58f0e75 100644 --- a/spec/services/jira_import/start_import_service_spec.rb +++ b/spec/services/jira_import/start_import_service_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' RSpec.describe JiraImport::StartImportService do - include JiraServiceHelper + include JiraIntegrationHelpers let_it_be(:user) { create(:user) } let_it_be(:project, reload: true) { create(:project) } diff --git a/spec/services/jira_import/users_importer_spec.rb b/spec/services/jira_import/users_importer_spec.rb index af408847260..ace9e0d5779 100644 --- a/spec/services/jira_import/users_importer_spec.rb +++ b/spec/services/jira_import/users_importer_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' RSpec.describe JiraImport::UsersImporter do - include JiraServiceHelper + include JiraIntegrationHelpers let_it_be(:user) { create(:user) } let_it_be(:group) { create(:group) } diff --git a/spec/services/markdown_content_rewriter_service_spec.rb b/spec/services/markdown_content_rewriter_service_spec.rb index 37c8a210ba5..91a117536ca 100644 --- a/spec/services/markdown_content_rewriter_service_spec.rb +++ b/spec/services/markdown_content_rewriter_service_spec.rb @@ -8,38 +8,63 @@ RSpec.describe MarkdownContentRewriterService do let_it_be(:target_parent) { create(:project, :public) } let(:content) { 'My content' } + let(:issue) { create(:issue, project: source_parent, description: content)} describe '#initialize' do it 'raises an error if source_parent is not a Project' do expect do - described_class.new(user, content, create(:group), target_parent) + described_class.new(user, issue, :description, create(:group), target_parent) end.to raise_error(ArgumentError, 'The rewriter classes require that `source_parent` is a `Project`') end + + it 'raises an error if field does not have cached markdown' do + expect do + described_class.new(user, issue, :author, source_parent, target_parent) + end.to raise_error(ArgumentError, 'The `field` attribute does not contain cached markdown') + end end describe '#execute' do - subject { described_class.new(user, content, source_parent, target_parent).execute } + subject { described_class.new(user, issue, :description, source_parent, target_parent).execute } - it 'calls the rewriter classes successfully', :aggregate_failures do - [Gitlab::Gfm::ReferenceRewriter, Gitlab::Gfm::UploadsRewriter].each do |rewriter_class| - service = double - - expect(service).to receive(:rewrite).with(target_parent) - expect(rewriter_class).to receive(:new).and_return(service) + context 'when content does not need a rewrite' do + it 'returns original content and cached html' do + expect(subject).to eq({ + 'description' => issue.description, + 'description_html' => issue.description_html, + 'skip_markdown_cache_validation' => true + }) end + end + + context 'when content needs a rewrite' do + it 'calls the rewriter classes successfully', :aggregate_failures do + described_class::REWRITERS.each do |rewriter_class| + service = double - subject + allow(service).to receive(:needs_rewrite?).and_return(true) + + expect(service).to receive(:rewrite).with(target_parent) + expect(rewriter_class).to receive(:new).and_return(service) + end + + subject + end end # Perform simple integration-style tests for each rewriter class. # to prove they run correctly. - context 'when content contains a reference' do - let_it_be(:issue) { create(:issue, project: source_parent) } + context 'when content has references' do + let_it_be(:issue_to_reference) { create(:issue, project: source_parent) } - let(:content) { "See ##{issue.iid}" } + let(:content) { "See ##{issue_to_reference.iid}" } it 'rewrites content' do - expect(subject).to eq("See #{source_parent.full_path}##{issue.iid}") + expect(subject).to eq({ + 'description' => "See #{source_parent.full_path}##{issue_to_reference.iid}", + 'description_html' => nil, + 'skip_markdown_cache_validation' => false + }) end end @@ -50,9 +75,37 @@ RSpec.describe MarkdownContentRewriterService do it 'rewrites content' do new_content = subject - expect(new_content).not_to eq(content) - expect(new_content.length).to eq(content.length) + expect(new_content[:description]).not_to eq(content) + expect(new_content[:description].length).to eq(content.length) + expect(new_content[1]).to eq(nil) end end end + + describe '#safe_to_copy_markdown?' do + subject do + rewriter = described_class.new(user, issue, :description, source_parent, target_parent) + rewriter.safe_to_copy_markdown? + end + + context 'when content has references' do + let(:milestone) { create(:milestone, project: source_parent) } + let(:content) { "Description that references #{milestone.to_reference}" } + + it { is_expected.to eq(false) } + end + + context 'when content has uploaded file references' do + let(:image_uploader) { build(:file_uploader, project: source_parent) } + let(:content) { "Text and #{image_uploader.markdown_link}" } + + it { is_expected.to eq(false) } + end + + context 'when content does not have references or uploads' do + let(:content) { "simples text with ```code```" } + + it { is_expected.to eq(true) } + end + end end diff --git a/spec/services/members/approve_access_request_service_spec.rb b/spec/services/members/approve_access_request_service_spec.rb index f7fbac612ee..d26bab7bb0a 100644 --- a/spec/services/members/approve_access_request_service_spec.rb +++ b/spec/services/members/approve_access_request_service_spec.rb @@ -9,36 +9,34 @@ RSpec.describe Members::ApproveAccessRequestService do let(:access_requester_user) { create(:user) } let(:access_requester) { source.requesters.find_by!(user_id: access_requester_user.id) } let(:opts) { {} } - - shared_examples 'a service raising ActiveRecord::RecordNotFound' do - it 'raises ActiveRecord::RecordNotFound' do - expect { described_class.new(current_user).execute(access_requester, **opts) }.to raise_error(ActiveRecord::RecordNotFound) - end - end + let(:params) { {} } + let(:custom_access_level) { Gitlab::Access::MAINTAINER } shared_examples 'a service raising Gitlab::Access::AccessDeniedError' do it 'raises Gitlab::Access::AccessDeniedError' do - expect { described_class.new(current_user).execute(access_requester, **opts) }.to raise_error(Gitlab::Access::AccessDeniedError) + expect { described_class.new(current_user, params).execute(access_requester, **opts) }.to raise_error(Gitlab::Access::AccessDeniedError) end end shared_examples 'a service approving an access request' do it 'succeeds' do - expect { described_class.new(current_user).execute(access_requester, **opts) }.to change { source.requesters.count }.by(-1) + expect { described_class.new(current_user, params).execute(access_requester, **opts) }.to change { source.requesters.count }.by(-1) end it 'returns a <Source>Member' do - member = described_class.new(current_user).execute(access_requester, **opts) + member = described_class.new(current_user, params).execute(access_requester, **opts) expect(member).to be_a "#{source.class}Member".constantize expect(member.requested_at).to be_nil end context 'with a custom access level' do + let(:params) { { access_level: custom_access_level } } + it 'returns a ProjectMember with the custom access level' do - member = described_class.new(current_user, access_level: Gitlab::Access::MAINTAINER).execute(access_requester, **opts) + member = described_class.new(current_user, params).execute(access_requester, **opts) - expect(member.access_level).to eq(Gitlab::Access::MAINTAINER) + expect(member.access_level).to eq(custom_access_level) end end end @@ -111,5 +109,38 @@ RSpec.describe Members::ApproveAccessRequestService do let(:source) { group } end end + + context 'in a project' do + let_it_be(:group_project) { create(:project, :public, group: create(:group, :public)) } + + let(:source) { group_project } + let(:custom_access_level) { Gitlab::Access::OWNER } + let(:params) { { access_level: custom_access_level } } + + before do + group_project.request_access(access_requester_user) + end + + context 'maintainers' do + before do + group_project.add_maintainer(current_user) + end + + context 'cannot approve the access request of a requester to give them OWNER permissions' do + it_behaves_like 'a service raising Gitlab::Access::AccessDeniedError' + end + end + + context 'owners' do + before do + # so that `current_user` is considered an `OWNER` in the project via inheritance. + group_project.group.add_owner(current_user) + end + + context 'can approve the access request of a requester to give them OWNER permissions' do + it_behaves_like 'a service approving an access request' + end + end + end end end diff --git a/spec/services/merge_requests/merge_service_spec.rb b/spec/services/merge_requests/merge_service_spec.rb index 3e2cccfb350..a2d73d8c9b1 100644 --- a/spec/services/merge_requests/merge_service_spec.rb +++ b/spec/services/merge_requests/merge_service_spec.rb @@ -161,7 +161,7 @@ RSpec.describe MergeRequests::MergeService do end context 'with Jira integration' do - include JiraServiceHelper + include JiraIntegrationHelpers let(:jira_tracker) { project.create_jira_integration } let(:jira_issue) { ExternalIssue.new('JIRA-123', project) } diff --git a/spec/services/notes/copy_service_spec.rb b/spec/services/notes/copy_service_spec.rb index dd11fa15ea8..fd8802e6640 100644 --- a/spec/services/notes/copy_service_spec.rb +++ b/spec/services/notes/copy_service_spec.rb @@ -16,9 +16,8 @@ RSpec.describe Notes::CopyService do let_it_be(:group) { create(:group) } let_it_be(:from_project) { create(:project, :public, group: group) } let_it_be(:to_project) { create(:project, :public, group: group) } - - let(:from_noteable) { create(:issue, project: from_project) } - let(:to_noteable) { create(:issue, project: to_project) } + let_it_be(:from_noteable) { create(:issue, project: from_project) } + let_it_be(:to_noteable) { create(:issue, project: to_project) } subject(:execute_service) { described_class.new(user, from_noteable, to_noteable).execute } @@ -85,6 +84,15 @@ RSpec.describe Notes::CopyService do expect(execute_service).to be_success end end + + it 'copies rendered markdown from note_html' do + expect(Banzai::Renderer).not_to receive(:cacheless_render_field) + + execute_service + + new_note = to_noteable.notes.first + expect(new_note.note_html).to eq(notes.first.note_html) + end end context 'notes with mentions' do @@ -119,6 +127,13 @@ RSpec.describe Notes::CopyService do expect(new_note.author).to eq(note.author) end end + + it 'does not copy rendered markdown from note_html' do + execute_service + + new_note = to_noteable.notes.first + expect(new_note.note_html).not_to eq(note.note_html) + end end context 'notes with upload' do @@ -137,6 +152,13 @@ RSpec.describe Notes::CopyService do expect(note.note_html).not_to eq(new_note.note_html) end end + + it 'does not copy rendered markdown from note_html' do + execute_service + + new_note = to_noteable.notes.first + expect(new_note.note_html).not_to eq(note.note_html) + end end context 'discussion notes' do diff --git a/spec/support/helpers/jira_service_helper.rb b/spec/support/helpers/jira_integration_helpers.rb index 3cfd0de06e8..66940314589 100644 --- a/spec/support/helpers/jira_service_helper.rb +++ b/spec/support/helpers/jira_integration_helpers.rb @@ -1,8 +1,8 @@ # frozen_string_literal: true -module JiraServiceHelper - JIRA_URL = "http://jira.example.net" - JIRA_API = JIRA_URL + "/rest/api/2" +module JiraIntegrationHelpers + JIRA_URL = 'http://jira.example.net' + JIRA_API = "#{JIRA_URL}/rest/api/2" def jira_integration_settings url = JIRA_URL @@ -17,6 +17,7 @@ module JiraServiceHelper end def jira_issue_comments + # rubocop: disable Layout/LineLength "{\"startAt\":0,\"maxResults\":11,\"total\":11, \"comments\":[{\"self\":\"http://0.0.0.0:4567/rest/api/2/issue/10002/comment/10609\", \"id\":\"10609\",\"author\":{\"self\":\"http://0.0.0.0:4567/rest/api/2/user?username=gitlab\", @@ -51,30 +52,31 @@ module JiraServiceHelper \"updated\":\"2015-04-01T03:45:55.667+0200\" } ]}" + # rubocop: enable Layout/LineLength end def jira_project_url - JIRA_API + "/project" + "#{JIRA_API}/project" end def jira_api_comment_url(issue_id) - JIRA_API + "/issue/#{issue_id}/comment" + "#{JIRA_API}/issue/#{issue_id}/comment" end def jira_api_remote_link_url(issue_id) - JIRA_API + "/issue/#{issue_id}/remotelink" + "#{JIRA_API}/issue/#{issue_id}/remotelink" end def jira_api_transition_url(issue_id) - JIRA_API + "/issue/#{issue_id}/transitions" + "#{JIRA_API}/issue/#{issue_id}/transitions" end def jira_api_test_url - JIRA_API + "/myself" + "#{JIRA_API}/myself" end def jira_issue_url(issue_id) - JIRA_API + "/issue/#{issue_id}" + "#{JIRA_API}/issue/#{issue_id}" end def stub_jira_integration_test diff --git a/spec/support/shared_contexts/features/integrations/integrations_shared_context.rb b/spec/support/shared_contexts/features/integrations/integrations_shared_context.rb index 893eae19482..a644e5d5b9c 100644 --- a/spec/support/shared_contexts/features/integrations/integrations_shared_context.rb +++ b/spec/support/shared_contexts/features/integrations/integrations_shared_context.rb @@ -2,7 +2,7 @@ Integration.available_integration_names.each do |integration| RSpec.shared_context integration do - include JiraServiceHelper if integration == 'jira' + include JiraIntegrationHelpers if integration == 'jira' let(:dashed_integration) { integration.dasherize } let(:integration_method) { Project.integration_association_name(integration) } diff --git a/spec/support/shared_examples/models/application_setting_shared_examples.rb b/spec/support/shared_examples/models/application_setting_shared_examples.rb index 74ec6474e80..6e7d04d3cba 100644 --- a/spec/support/shared_examples/models/application_setting_shared_examples.rb +++ b/spec/support/shared_examples/models/application_setting_shared_examples.rb @@ -238,8 +238,16 @@ RSpec.shared_examples 'application settings examples' do end describe '#allowed_key_types' do - it 'includes all key types by default' do - expect(setting.allowed_key_types).to contain_exactly(*Gitlab::SSHPublicKey.supported_types) + context 'in non-FIPS mode', fips_mode: false do + it 'includes all key types by default' do + expect(setting.allowed_key_types).to contain_exactly(*Gitlab::SSHPublicKey.supported_types) + end + end + + context 'in FIPS mode', :fips_mode do + it 'excludes DSA from supported key types' do + expect(setting.allowed_key_types).to contain_exactly(*Gitlab::SSHPublicKey.supported_types - %i(dsa)) + end end it 'excludes disabled key types' do diff --git a/spec/support/shared_examples/services/alert_management_shared_examples.rb b/spec/support/shared_examples/services/alert_management_shared_examples.rb index 23aee912d2d..f644f1a1687 100644 --- a/spec/support/shared_examples/services/alert_management_shared_examples.rb +++ b/spec/support/shared_examples/services/alert_management_shared_examples.rb @@ -32,7 +32,7 @@ RSpec.shared_context 'incident management settings enabled' do end before do - allow(ProjectServiceWorker).to receive(:perform_async) + allow(Integrations::ExecuteWorker).to receive(:perform_async) allow(service) .to receive(:incident_management_setting) .and_return(incident_management_setting) diff --git a/spec/workers/deployments/hooks_worker_spec.rb b/spec/workers/deployments/hooks_worker_spec.rb index a9240b45360..7c5f288fa57 100644 --- a/spec/workers/deployments/hooks_worker_spec.rb +++ b/spec/workers/deployments/hooks_worker_spec.rb @@ -7,7 +7,7 @@ RSpec.describe Deployments::HooksWorker do describe '#perform' do before do - allow(ProjectServiceWorker).to receive(:perform_async) + allow(Integrations::ExecuteWorker).to receive(:perform_async) end it 'logs deployment and project IDs as metadata' do @@ -25,7 +25,7 @@ RSpec.describe Deployments::HooksWorker do project = deployment.project service = create(:integrations_slack, project: project, deployment_events: true) - expect(ProjectServiceWorker).to receive(:perform_async).with(service.id, an_instance_of(Hash)) + expect(Integrations::ExecuteWorker).to receive(:perform_async).with(service.id, an_instance_of(Hash)) worker.perform(deployment_id: deployment.id, status_changed_at: Time.current) end @@ -35,13 +35,13 @@ RSpec.describe Deployments::HooksWorker do project = deployment.project create(:integrations_slack, project: project, deployment_events: true, active: false) - expect(ProjectServiceWorker).not_to receive(:perform_async) + expect(Integrations::ExecuteWorker).not_to receive(:perform_async) worker.perform(deployment_id: deployment.id, status_changed_at: Time.current) end it 'does not execute if a deployment does not exist' do - expect(ProjectServiceWorker).not_to receive(:perform_async) + expect(Integrations::ExecuteWorker).not_to receive(:perform_async) worker.perform(deployment_id: non_existing_record_id, status_changed_at: Time.current) end diff --git a/spec/workers/every_sidekiq_worker_spec.rb b/spec/workers/every_sidekiq_worker_spec.rb index 820076a597a..330afa6fbd4 100644 --- a/spec/workers/every_sidekiq_worker_spec.rb +++ b/spec/workers/every_sidekiq_worker_spec.rb @@ -305,6 +305,7 @@ RSpec.describe 'Every Sidekiq worker' do 'IncidentManagement::OncallRotations::PersistAllRotationsShiftsJob' => 3, 'IncidentManagement::OncallRotations::PersistShiftsJob' => 3, 'IncidentManagement::PagerDuty::ProcessIncidentWorker' => 3, + 'Integrations::ExecuteWorker' => 3, 'InvalidGpgSignatureUpdateWorker' => 3, 'IrkerWorker' => 3, 'IssuableExportCsvWorker' => 3, diff --git a/spec/workers/gitlab/jira_import/stage/import_issues_worker_spec.rb b/spec/workers/gitlab/jira_import/stage/import_issues_worker_spec.rb index 10702c17cb5..2b08a592164 100644 --- a/spec/workers/gitlab/jira_import/stage/import_issues_worker_spec.rb +++ b/spec/workers/gitlab/jira_import/stage/import_issues_worker_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' RSpec.describe Gitlab::JiraImport::Stage::ImportIssuesWorker do - include JiraServiceHelper + include JiraIntegrationHelpers let_it_be(:user) { create(:user) } let_it_be(:project) { create(:project, import_type: 'jira') } diff --git a/spec/workers/gitlab/jira_import/stage/import_labels_worker_spec.rb b/spec/workers/gitlab/jira_import/stage/import_labels_worker_spec.rb index 52c516b9ff9..d15f2caba19 100644 --- a/spec/workers/gitlab/jira_import/stage/import_labels_worker_spec.rb +++ b/spec/workers/gitlab/jira_import/stage/import_labels_worker_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' RSpec.describe Gitlab::JiraImport::Stage::ImportLabelsWorker do - include JiraServiceHelper + include JiraIntegrationHelpers let_it_be(:user) { create(:user) } let_it_be(:project) { create(:project, import_type: 'jira') } diff --git a/spec/workers/project_service_worker_spec.rb b/spec/workers/integrations/execute_worker_spec.rb index 55ec07ff79c..19600f35c8f 100644 --- a/spec/workers/project_service_worker_spec.rb +++ b/spec/workers/integrations/execute_worker_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require 'spec_helper' -RSpec.describe ProjectServiceWorker, '#perform' do +RSpec.describe Integrations::ExecuteWorker, '#perform' do let_it_be(:integration) { create(:jira_integration) } let(:worker) { described_class.new } @@ -36,4 +36,26 @@ RSpec.describe ProjectServiceWorker, '#perform' do end.not_to raise_error end end + + context 'when using the old worker class' do + let(:described_class) { ProjectServiceWorker } + + it 'uses the correct worker attributes', :aggregate_failures do + expect(described_class.sidekiq_options).to include('retry' => 3, 'dead' => false) + expect(described_class.get_data_consistency).to eq(:always) + expect(described_class.get_feature_category).to eq(:integrations) + expect(described_class.get_urgency).to eq(:low) + expect(described_class.worker_has_external_dependencies?).to be(true) + end + + it 'executes integration with given data' do + data = { test: 'test' } + + expect_next_found_instance_of(integration.class) do |integration| + expect(integration).to receive(:execute).with(data) + end + + worker.perform(integration.id, data) + end + end end |