diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2022-06-03 00:09:25 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2022-06-03 00:09:25 +0300 |
commit | 6ddc820225c148a923a154ab6d6f0a8c791a089d (patch) | |
tree | 23a648fd2a83f54d5535dda197ed1ac6e5315493 /app | |
parent | 9b40f0e0d63ff2a8ed1686f8713701688600a998 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
21 files changed, 189 insertions, 51 deletions
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 |