Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2022-06-03 00:09:25 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2022-06-03 00:09:25 +0300
commit6ddc820225c148a923a154ab6d6f0a8c791a089d (patch)
tree23a648fd2a83f54d5535dda197ed1ac6e5315493 /app
parent9b40f0e0d63ff2a8ed1686f8713701688600a998 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
-rw-r--r--app/assets/javascripts/editor/schema/ci.json5
-rw-r--r--app/assets/javascripts/pipelines/components/graph/linked_pipeline.vue9
-rw-r--r--app/assets/javascripts/repository/components/blob_viewers/sketch_viewer.vue2
-rw-r--r--app/assets/javascripts/vue_shared/components/notes/skeleton_note.vue6
-rw-r--r--app/controllers/admin/users_controller.rb2
-rw-r--r--app/controllers/confirmations_controller.rb2
-rw-r--r--app/controllers/profiles/accounts_controller.rb2
-rw-r--r--app/controllers/profiles/active_sessions_controller.rb2
-rw-r--r--app/controllers/profiles_controller.rb5
-rw-r--r--app/controllers/users/terms_controller.rb2
-rw-r--r--app/controllers/users_controller.rb3
-rw-r--r--app/models/application_setting_implementation.rb27
-rw-r--r--app/models/concerns/cache_markdown_field.rb7
-rw-r--r--app/models/integration.rb6
-rw-r--r--app/services/issuable/clone/base_service.rb7
-rw-r--r--app/services/markdown_content_rewriter_service.rb62
-rw-r--r--app/services/members/approve_access_request_service.rb17
-rw-r--r--app/services/notes/copy_service.rb17
-rw-r--r--app/workers/all_queues.yml9
-rw-r--r--app/workers/integrations/execute_worker.rb27
-rw-r--r--app/workers/project_service_worker.rb21
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