diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2021-12-20 13:37:47 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2021-12-20 13:37:47 +0000 |
commit | aee0a117a889461ce8ced6fcf73207fe017f1d99 (patch) | |
tree | 891d9ef189227a8445d83f35c1b0fc99573f4380 /app/controllers | |
parent | 8d46af3258650d305f53b819eabf7ab18d22f59e (diff) | |
download | gitlab-ce-aee0a117a889461ce8ced6fcf73207fe017f1d99.tar.gz |
Add latest changes from gitlab-org/gitlab@14-6-stable-eev14.6.0-rc42
Diffstat (limited to 'app/controllers')
85 files changed, 556 insertions, 389 deletions
diff --git a/app/controllers/admin/plan_limits_controller.rb b/app/controllers/admin/plan_limits_controller.rb index 88bc5ea0198..420fd93fad5 100644 --- a/app/controllers/admin/plan_limits_controller.rb +++ b/app/controllers/admin/plan_limits_controller.rb @@ -31,6 +31,7 @@ class Admin::PlanLimitsController < Admin::ApplicationController params.require(:plan_limits).permit(%i[ plan_id conan_max_file_size + helm_max_file_size maven_max_file_size npm_max_file_size nuget_max_file_size diff --git a/app/controllers/admin/version_check_controller.rb b/app/controllers/admin/version_check_controller.rb new file mode 100644 index 00000000000..dde1a7abafa --- /dev/null +++ b/app/controllers/admin/version_check_controller.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +class Admin::VersionCheckController < Admin::ApplicationController + feature_category :not_owned + + def version_check + response = VersionCheck.new.response + + expires_in 1.minute if response + render json: response + end +end diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 3af1afab06e..d3ecbdcc1f6 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -23,6 +23,7 @@ class ApplicationController < ActionController::Base include Gitlab::Utils::StrongMemoize include ::Gitlab::EndpointAttributes include FlocOptOut + include CheckRateLimit before_action :authenticate_user!, except: [:route_not_found] before_action :enforce_terms!, if: :should_enforce_terms? @@ -66,10 +67,6 @@ class ApplicationController < ActionController::Base :manifest_import_enabled?, :phabricator_import_enabled?, :masked_page_url - # Adds `no-store` to the DEFAULT_CACHE_CONTROL, to prevent security - # concerns due to caching private data. - DEFAULT_GITLAB_CACHE_CONTROL = "#{ActionDispatch::Http::Cache::Response::DEFAULT_CACHE_CONTROL}, no-store" - def self.endpoint_id_for_action(action_name) "#{self.name}##{action_name}" end @@ -283,10 +280,7 @@ class ApplicationController < ActionController::Base end def default_cache_headers - if current_user - headers['Cache-Control'] = default_cache_control - headers['Pragma'] = 'no-cache' # HTTP 1.0 compatibility - end + headers['Pragma'] = 'no-cache' # HTTP 1.0 compatibility end def stream_csv_headers(csv_filename) @@ -297,14 +291,6 @@ class ApplicationController < ActionController::Base headers['Content-Disposition'] = "attachment; filename=\"#{csv_filename}\"" end - def default_cache_control - if request.xhr? - ActionDispatch::Http::Cache::Response::DEFAULT_CACHE_CONTROL - else - DEFAULT_GITLAB_CACHE_CONTROL - end - end - def validate_user_service_ticket! return unless signed_in? && session[:service_tickets] diff --git a/app/controllers/autocomplete_controller.rb b/app/controllers/autocomplete_controller.rb index 5cb5690d72d..c32a7f10aa4 100644 --- a/app/controllers/autocomplete_controller.rb +++ b/app/controllers/autocomplete_controller.rb @@ -9,6 +9,8 @@ class AutocompleteController < ApplicationController feature_category :code_review, [:merge_request_target_branches] feature_category :continuous_delivery, [:deploy_keys_with_owners] + urgency :low, [:merge_request_target_branches] + def users group = Autocomplete::GroupFinder .new(current_user, project, params) diff --git a/app/controllers/clusters/clusters_controller.rb b/app/controllers/clusters/clusters_controller.rb index 32de9e69c85..15a261f572a 100644 --- a/app/controllers/clusters/clusters_controller.rb +++ b/app/controllers/clusters/clusters_controller.rb @@ -280,7 +280,10 @@ class Clusters::ClustersController < Clusters::BaseController end def generate_gcp_authorize_url - state = generate_session_key_redirect(clusterable.new_path(provider: :gcp).to_s) + new_path = clusterable.new_path(provider: :gcp).to_s + error_path = @project ? project_clusters_path(@project) : new_path + + state = generate_session_key_redirect(new_path, error_path) @authorize_url = GoogleApi::CloudPlatform::Client.new( nil, callback_google_api_auth_url, @@ -339,9 +342,10 @@ class Clusters::ClustersController < Clusters::BaseController session[GoogleApi::CloudPlatform::Client.session_key_for_expires_at] end - def generate_session_key_redirect(uri) + def generate_session_key_redirect(uri, error_uri) GoogleApi::CloudPlatform::Client.new_session_key_for_redirect_uri do |key| session[key] = uri + session[:error_uri] = error_uri end end diff --git a/app/controllers/concerns/authenticates_with_two_factor.rb b/app/controllers/concerns/authenticates_with_two_factor.rb index da5b7ccfbf0..14dcec33545 100644 --- a/app/controllers/concerns/authenticates_with_two_factor.rb +++ b/app/controllers/concerns/authenticates_with_two_factor.rb @@ -23,9 +23,9 @@ module AuthenticatesWithTwoFactor session[:otp_user_id] = user.id session[:user_password_hash] = Digest::SHA256.hexdigest(user.encrypted_password) - push_frontend_feature_flag(:webauthn) + push_frontend_feature_flag(:webauthn, default_enabled: :yaml) - if user.two_factor_webauthn_enabled? + if Feature.enabled?(:webauthn, default_enabled: :yaml) setup_webauthn_authentication(user) else setup_u2f_authentication(user) diff --git a/app/controllers/concerns/authenticates_with_two_factor_for_admin_mode.rb b/app/controllers/concerns/authenticates_with_two_factor_for_admin_mode.rb index 574fc6c0f37..05be04059fd 100644 --- a/app/controllers/concerns/authenticates_with_two_factor_for_admin_mode.rb +++ b/app/controllers/concerns/authenticates_with_two_factor_for_admin_mode.rb @@ -11,7 +11,7 @@ module AuthenticatesWithTwoFactorForAdminMode return handle_locked_user(user) unless user.can?(:log_in) session[:otp_user_id] = user.id - push_frontend_feature_flag(:webauthn) + push_frontend_feature_flag(:webauthn, default_enabled: :yaml) if user.two_factor_webauthn_enabled? setup_webauthn_authentication(user) diff --git a/app/controllers/concerns/check_rate_limit.rb b/app/controllers/concerns/check_rate_limit.rb index c4de3315e22..5ccdf843525 100644 --- a/app/controllers/concerns/check_rate_limit.rb +++ b/app/controllers/concerns/check_rate_limit.rb @@ -5,19 +5,27 @@ # Controller concern that checks if the rate limit for a given action is throttled by calling the # Gitlab::ApplicationRateLimiter class. If the action is throttled for the current user, the request # will be logged and an error message will be rendered with a Too Many Requests response status. +# See lib/api/helpers/rate_limiter.rb for API version module CheckRateLimit - def check_rate_limit(key) - return unless rate_limiter.throttled?(key, scope: current_user, users_allowlist: rate_limit_users_allowlist) + def check_rate_limit!(key, scope:, redirect_back: false, **options) + return unless rate_limiter.throttled?(key, scope: scope, **options) rate_limiter.log_request(request, "#{key}_request_limit".to_sym, current_user) - render plain: _('This endpoint has been requested too many times. Try again later.'), status: :too_many_requests + + return yield if block_given? + + message = _('This endpoint has been requested too many times. Try again later.') + + if redirect_back + redirect_back_or_default(options: { alert: message }) + else + render plain: message, status: :too_many_requests + end end + private + def rate_limiter ::Gitlab::ApplicationRateLimiter end - - def rate_limit_users_allowlist - Gitlab::CurrentSettings.current_application_settings.notes_create_limit_allowlist - end end diff --git a/app/controllers/concerns/cycle_analytics_params.rb b/app/controllers/concerns/cycle_analytics_params.rb index 626093b4588..70bcefe339c 100644 --- a/app/controllers/concerns/cycle_analytics_params.rb +++ b/app/controllers/concerns/cycle_analytics_params.rb @@ -23,6 +23,7 @@ module CycleAnalyticsParams opts[:from] = params[:from] || start_date(params) opts[:to] = params[:to] if params[:to] opts[:end_event_filter] = params[:end_event_filter] if params[:end_event_filter] + opts[:use_aggregated_data_collector] = params[:use_aggregated_data_collector] if params[:use_aggregated_data_collector] opts.merge!(params.slice(*::Gitlab::Analytics::CycleAnalytics::RequestParams::FINDER_PARAM_NAMES)) opts.merge!(date_range(params)) end diff --git a/app/controllers/concerns/dependency_proxy/group_access.rb b/app/controllers/concerns/dependency_proxy/group_access.rb index 07aca72b22f..44611641529 100644 --- a/app/controllers/concerns/dependency_proxy/group_access.rb +++ b/app/controllers/concerns/dependency_proxy/group_access.rb @@ -5,13 +5,13 @@ module DependencyProxy extend ActiveSupport::Concern included do - before_action :verify_dependency_proxy_enabled! + before_action :verify_dependency_proxy_available! before_action :authorize_read_dependency_proxy! end private - def verify_dependency_proxy_enabled! + def verify_dependency_proxy_available! render_404 unless group&.dependency_proxy_feature_available? end diff --git a/app/controllers/concerns/integrations/actions.rb b/app/controllers/concerns/integrations/actions.rb index 6490742c0f8..1f788860c8f 100644 --- a/app/controllers/concerns/integrations/actions.rb +++ b/app/controllers/concerns/integrations/actions.rb @@ -23,7 +23,7 @@ module Integrations::Actions format.html do if saved PropagateIntegrationWorker.perform_async(integration.id) - redirect_to scoped_edit_integration_path(integration), notice: success_message + redirect_to scoped_edit_integration_path(integration, project: integration.project, group: integration.group), notice: success_message else render 'shared/integrations/edit' end diff --git a/app/controllers/concerns/integrations/hooks_execution.rb b/app/controllers/concerns/integrations/hooks_execution.rb index af039057a9c..6a9d3d51f9b 100644 --- a/app/controllers/concerns/integrations/hooks_execution.rb +++ b/app/controllers/concerns/integrations/hooks_execution.rb @@ -32,16 +32,4 @@ module Integrations::HooksExecution flash[:alert] = "Hook execution failed: #{message}" end end - - def create_rate_limit(key, scope) - if rate_limiter.throttled?(key, scope: [scope, current_user]) - rate_limiter.log_request(request, "#{key}_request_limit".to_sym, current_user) - - render plain: _('This endpoint has been requested too many times. Try again later.'), status: :too_many_requests - end - end - - def rate_limiter - ::Gitlab::ApplicationRateLimiter - end end diff --git a/app/controllers/concerns/issuable_actions.rb b/app/controllers/concerns/issuable_actions.rb index 2d7fbb78209..bac9732018c 100644 --- a/app/controllers/concerns/issuable_actions.rb +++ b/app/controllers/concerns/issuable_actions.rb @@ -17,6 +17,7 @@ module IssuableActions def show respond_to do |format| format.html do + @show_crm_contacts = issuable.is_a?(Issue) && can?(current_user, :read_crm_contact, issuable.project.group) # rubocop:disable Gitlab/ModuleWithInstanceVariables @issuable_sidebar = serializer.represent(issuable, serializer: 'sidebar') # rubocop:disable Gitlab/ModuleWithInstanceVariables render 'show' end diff --git a/app/controllers/concerns/membership_actions.rb b/app/controllers/concerns/membership_actions.rb index 8fd4e98d557..f716c1f6c2f 100644 --- a/app/controllers/concerns/membership_actions.rb +++ b/app/controllers/concerns/membership_actions.rb @@ -26,7 +26,6 @@ module MembershipActions member_data = if member.expires? { - expires_in: helpers.distance_of_time_in_words_to_now(member.expires_at), expires_soon: member.expires_soon?, expires_at_formatted: member.expires_at.to_time.in_time_zone.to_s(:medium) } diff --git a/app/controllers/concerns/notes_actions.rb b/app/controllers/concerns/notes_actions.rb index c2ee735a2b5..8410a8779f6 100644 --- a/app/controllers/concerns/notes_actions.rb +++ b/app/controllers/concerns/notes_actions.rb @@ -3,7 +3,6 @@ module NotesActions include RendersNotes include Gitlab::Utils::StrongMemoize - include CheckRateLimit extend ActiveSupport::Concern # last_fetched_at is an integer number of microseconds, which is the same @@ -16,7 +15,11 @@ module NotesActions before_action :require_noteable!, only: [:index, :create] before_action :authorize_admin_note!, only: [:update, :destroy] before_action :note_project, only: [:create] - before_action -> { check_rate_limit(:notes_create) }, only: [:create] + before_action -> { + check_rate_limit!(:notes_create, + scope: current_user, + users_allowlist: Gitlab::CurrentSettings.current_application_settings.notes_create_limit_allowlist) + }, only: [:create] end def index @@ -341,3 +344,5 @@ module NotesActions noteable.discussions_rendered_on_frontend? end end + +NotesActions.prepend_mod_with('NotesActions') diff --git a/app/controllers/concerns/one_trust_csp.rb b/app/controllers/concerns/one_trust_csp.rb index fbd44f52590..cd35eeb587c 100644 --- a/app/controllers/concerns/one_trust_csp.rb +++ b/app/controllers/concerns/one_trust_csp.rb @@ -8,11 +8,11 @@ module OneTrustCSP next unless helpers.one_trust_enabled? || policy.directives.present? default_script_src = policy.directives['script-src'] || policy.directives['default-src'] - script_src_values = Array.wrap(default_script_src) | ["'unsafe-eval'", 'https://cdn.cookielaw.org https://*.onetrust.com'] + script_src_values = Array.wrap(default_script_src) | ["'unsafe-eval'", 'https://cdn.cookielaw.org', 'https://*.onetrust.com'] policy.script_src(*script_src_values) default_connect_src = policy.directives['connect-src'] || policy.directives['default-src'] - connect_src_values = Array.wrap(default_connect_src) | ['https://cdn.cookielaw.org'] + connect_src_values = Array.wrap(default_connect_src) | ['https://cdn.cookielaw.org', 'https://*.onetrust.com'] policy.connect_src(*connect_src_values) end end diff --git a/app/controllers/concerns/preview_markdown.rb b/app/controllers/concerns/preview_markdown.rb index 2916762e31f..1d2f9e31c46 100644 --- a/app/controllers/concerns/preview_markdown.rb +++ b/app/controllers/concerns/preview_markdown.rb @@ -21,7 +21,7 @@ module PreviewMarkdown def projects_filter_params { - issuable_state_filter_enabled: true, + issuable_reference_expansion_enabled: true, suggestions_filter_enabled: params[:preview_suggestions].present? } end diff --git a/app/controllers/concerns/snippets/blobs_actions.rb b/app/controllers/concerns/snippets/blobs_actions.rb index db56ce8f193..b510594ad63 100644 --- a/app/controllers/concerns/snippets/blobs_actions.rb +++ b/app/controllers/concerns/snippets/blobs_actions.rb @@ -51,3 +51,5 @@ module Snippets::BlobsActions params[:snippet_id] end end + +Snippets::BlobsActions.prepend_mod diff --git a/app/controllers/concerns/sourcegraph_decorator.rb b/app/controllers/concerns/sourcegraph_decorator.rb index 5ef09b9221f..061990a4361 100644 --- a/app/controllers/concerns/sourcegraph_decorator.rb +++ b/app/controllers/concerns/sourcegraph_decorator.rb @@ -11,7 +11,7 @@ module SourcegraphDecorator next unless Gitlab::CurrentSettings.sourcegraph_enabled default_connect_src = p.directives['connect-src'] || p.directives['default-src'] - connect_src_values = Array.wrap(default_connect_src) | [Gitlab::CurrentSettings.sourcegraph_url] + connect_src_values = Array.wrap(default_connect_src) | [Gitlab::Utils.append_path(Gitlab::CurrentSettings.sourcegraph_url, '.api/')] p.connect_src(*connect_src_values) end end diff --git a/app/controllers/concerns/wiki_actions.rb b/app/controllers/concerns/wiki_actions.rb index 848b7ee44c5..714a6f280f3 100644 --- a/app/controllers/concerns/wiki_actions.rb +++ b/app/controllers/concerns/wiki_actions.rb @@ -21,6 +21,10 @@ module WikiActions before_action :load_sidebar, except: [:pages] before_action :set_content_class + before_action do + push_frontend_feature_flag(:wiki_switch_between_content_editor_raw_markdown, @group, default_enabled: :yaml) + end + before_action only: [:show, :edit, :update] do @valid_encoding = valid_encoding? end @@ -79,7 +83,8 @@ module WikiActions render 'shared/wikis/show' elsif file_blob - send_blob(wiki.repository, file_blob) + # This is needed by [GitLab JH](https://gitlab.com/gitlab-jh/gitlab/-/issues/247) + send_wiki_file_blob(wiki, file_blob) elsif show_create_form? # Assign a title to the WikiPage unless `id` is a randomly generated slug from #new title = params[:id] unless params[:random_title].present? @@ -301,4 +306,10 @@ module WikiActions view: diff_view } end + + def send_wiki_file_blob(wiki, file_blob) + send_blob(wiki.repository, file_blob) + end end + +WikiActions.prepend_mod diff --git a/app/controllers/confirmations_controller.rb b/app/controllers/confirmations_controller.rb index 6725e19df25..dd30d688fa8 100644 --- a/app/controllers/confirmations_controller.rb +++ b/app/controllers/confirmations_controller.rb @@ -3,6 +3,7 @@ class ConfirmationsController < Devise::ConfirmationsController include AcceptsPendingInvitations include GitlabRecaptcha + include OneTrustCSP prepend_before_action :check_recaptcha, only: :create before_action :load_recaptcha, only: :new diff --git a/app/controllers/dashboard_controller.rb b/app/controllers/dashboard_controller.rb index 8d7686a95fb..2ecd17db487 100644 --- a/app/controllers/dashboard_controller.rb +++ b/app/controllers/dashboard_controller.rb @@ -18,6 +18,8 @@ class DashboardController < Dashboard::ApplicationController feature_category :team_planning, [:issues, :issues_calendar] feature_category :code_review, [:merge_requests] + urgency :low, [:merge_requests] + def activity respond_to do |format| format.html diff --git a/app/controllers/google_api/authorizations_controller.rb b/app/controllers/google_api/authorizations_controller.rb index 76a1c43dfa3..b9c5e87c69c 100644 --- a/app/controllers/google_api/authorizations_controller.rb +++ b/app/controllers/google_api/authorizations_controller.rb @@ -8,19 +8,36 @@ module GoogleApi feature_category :kubernetes_management + ## + # handle the response from google after the user + # goes through authentication and authorization process def callback - token, expires_at = GoogleApi::CloudPlatform::Client - .new(nil, callback_google_api_auth_url) - .get_token(params[:code]) - - session[GoogleApi::CloudPlatform::Client.session_key_for_token] = token - session[GoogleApi::CloudPlatform::Client.session_key_for_expires_at] = - expires_at.to_s - + redirect_uri = redirect_uri_from_session + ## + # when the user declines authorizations + # `error` param is returned + if params[:error] + flash[:alert] = _('Google Cloud authorizations required') + redirect_uri = session[:error_uri] + ## + # on success, the `code` param is returned + elsif params[:code] + token, expires_at = GoogleApi::CloudPlatform::Client + .new(nil, callback_google_api_auth_url) + .get_token(params[:code]) + + session[GoogleApi::CloudPlatform::Client.session_key_for_token] = token + session[GoogleApi::CloudPlatform::Client.session_key_for_expires_at] = expires_at.to_s + redirect_uri = redirect_uri_from_session + end + ## + # or google may just timeout rescue ::Faraday::TimeoutError, ::Faraday::ConnectionFailed flash[:alert] = _('Timeout connecting to the Google API. Please try again.') + ## + # regardless, we redirect the user appropriately ensure - redirect_to redirect_uri_from_session + redirect_to redirect_uri end private diff --git a/app/controllers/graphql_controller.rb b/app/controllers/graphql_controller.rb index 899fa614949..f48d03869a4 100644 --- a/app/controllers/graphql_controller.rb +++ b/app/controllers/graphql_controller.rb @@ -50,6 +50,8 @@ class GraphqlController < ApplicationController end rescue_from StandardError do |exception| + @exception_object = exception + log_exception(exception) if Rails.env.test? || Rails.env.development? @@ -197,7 +199,9 @@ class GraphqlController < ApplicationController # Merging to :metadata will ensure these are logged as top level keys payload[:metadata] ||= {} - payload[:metadata].merge!(graphql: logs) + payload[:metadata][:graphql] = logs + + payload[:exception_object] = @exception_object if @exception_object end def logs diff --git a/app/controllers/groups/autocomplete_sources_controller.rb b/app/controllers/groups/autocomplete_sources_controller.rb index 82f8854bd2b..17cdcd9cb9b 100644 --- a/app/controllers/groups/autocomplete_sources_controller.rb +++ b/app/controllers/groups/autocomplete_sources_controller.rb @@ -5,6 +5,8 @@ class Groups::AutocompleteSourcesController < Groups::ApplicationController feature_category :team_planning, [:issues, :labels, :milestones, :commands] feature_category :code_review, [:merge_requests] + urgency :low, [:merge_requests] + def members render json: ::Groups::ParticipantsService.new(@group, current_user).execute(target) end diff --git a/app/controllers/groups/boards_controller.rb b/app/controllers/groups/boards_controller.rb index 3152c4d733f..3fbcb2fd7aa 100644 --- a/app/controllers/groups/boards_controller.rb +++ b/app/controllers/groups/boards_controller.rb @@ -11,7 +11,6 @@ class Groups::BoardsController < Groups::ApplicationController push_frontend_feature_flag(:board_multi_select, group, default_enabled: :yaml) push_frontend_feature_flag(:swimlanes_buffered_rendering, group, default_enabled: :yaml) push_frontend_feature_flag(:iteration_cadences, group, default_enabled: :yaml) - push_frontend_feature_flag(:labels_widget, group, default_enabled: :yaml) experiment(:prominent_create_board_btn, subject: current_user) do |e| e.use { } e.try { } diff --git a/app/controllers/groups/crm/contacts_controller.rb b/app/controllers/groups/crm/contacts_controller.rb new file mode 100644 index 00000000000..f00f4d1df25 --- /dev/null +++ b/app/controllers/groups/crm/contacts_controller.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +class Groups::Crm::ContactsController < Groups::ApplicationController + feature_category :team_planning + + before_action :authorize_read_crm_contact! + + def new + render action: "index" + end + + def edit + render action: "index" + end + + private + + def authorize_read_crm_contact! + render_404 unless can?(current_user, :read_crm_contact, group) + end +end diff --git a/app/controllers/groups/crm/organizations_controller.rb b/app/controllers/groups/crm/organizations_controller.rb new file mode 100644 index 00000000000..ab720f490be --- /dev/null +++ b/app/controllers/groups/crm/organizations_controller.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +class Groups::Crm::OrganizationsController < Groups::ApplicationController + feature_category :team_planning + + before_action :authorize_read_crm_organization! + + def new + render action: "index" + end + + private + + def authorize_read_crm_organization! + render_404 unless can?(current_user, :read_crm_organization, group) + end +end diff --git a/app/controllers/groups/crm_controller.rb b/app/controllers/groups/crm_controller.rb deleted file mode 100644 index 40661b09be6..00000000000 --- a/app/controllers/groups/crm_controller.rb +++ /dev/null @@ -1,30 +0,0 @@ -# frozen_string_literal: true - -class Groups::CrmController < Groups::ApplicationController - feature_category :team_planning - - before_action :authorize_read_crm_contact!, only: [:contacts] - before_action :authorize_read_crm_organization!, only: [:organizations] - - def contacts - respond_to do |format| - format.html - end - end - - def organizations - respond_to do |format| - format.html - end - end - - private - - def authorize_read_crm_contact! - render_404 unless can?(current_user, :read_crm_contact, group) - end - - def authorize_read_crm_organization! - render_404 unless can?(current_user, :read_crm_organization, group) - end -end diff --git a/app/controllers/groups/dependency_proxies_controller.rb b/app/controllers/groups/dependency_proxies_controller.rb index b037aa52939..2e120de435e 100644 --- a/app/controllers/groups/dependency_proxies_controller.rb +++ b/app/controllers/groups/dependency_proxies_controller.rb @@ -5,30 +5,19 @@ module Groups include ::DependencyProxy::GroupAccess before_action :authorize_admin_dependency_proxy!, only: :update - before_action :dependency_proxy + before_action :verify_dependency_proxy_enabled! feature_category :package_registry - def show - @blobs_count = group.dependency_proxy_blobs.count - @blobs_total_size = group.dependency_proxy_blobs.total_size - end - - def update - dependency_proxy.update(dependency_proxy_params) - - redirect_to group_dependency_proxy_path(group) - end - private def dependency_proxy @dependency_proxy ||= - group.dependency_proxy_setting || group.create_dependency_proxy_setting + group.dependency_proxy_setting || group.create_dependency_proxy_setting! end - def dependency_proxy_params - params.require(:dependency_proxy_group_setting).permit(:enabled) + def verify_dependency_proxy_enabled! + render_404 unless dependency_proxy.enabled? end end end diff --git a/app/controllers/groups/dependency_proxy_for_containers_controller.rb b/app/controllers/groups/dependency_proxy_for_containers_controller.rb index fc930ffebbd..171314b5f26 100644 --- a/app/controllers/groups/dependency_proxy_for_containers_controller.rb +++ b/app/controllers/groups/dependency_proxy_for_containers_controller.rb @@ -19,7 +19,7 @@ class Groups::DependencyProxyForContainersController < ::Groups::DependencyProxy feature_category :dependency_proxy def manifest - result = DependencyProxy::FindOrCreateManifestService.new(group, image, tag, token).execute + result = DependencyProxy::FindCachedManifestService.new(group, image, tag, token).execute if result[:status] == :success if result[:manifest] diff --git a/app/controllers/groups/variables_controller.rb b/app/controllers/groups/variables_controller.rb index 9dbbd385ea8..1e23db9f32b 100644 --- a/app/controllers/groups/variables_controller.rb +++ b/app/controllers/groups/variables_controller.rb @@ -8,6 +8,8 @@ module Groups feature_category :pipeline_authoring + urgency :low, [:show] + def show respond_to do |format| format.json do diff --git a/app/controllers/groups_controller.rb b/app/controllers/groups_controller.rb index 6ae711a6e14..62336c7eede 100644 --- a/app/controllers/groups_controller.rb +++ b/app/controllers/groups_controller.rb @@ -37,7 +37,7 @@ class GroupsController < Groups::ApplicationController push_frontend_feature_flag(:iteration_cadences, @group, default_enabled: :yaml) end - before_action :export_rate_limit, only: [:export, :download_export] + before_action :check_export_rate_limit!, only: [:export, :download_export] helper_method :captcha_required? @@ -59,6 +59,9 @@ class GroupsController < Groups::ApplicationController feature_category :projects, [:projects] feature_category :importers, [:export, :download_export] + urgency :high, [:unfoldered_environment_names] + urgency :low, [:merge_requests] + def index redirect_to(current_user ? dashboard_groups_path : explore_groups_path) end @@ -92,7 +95,6 @@ class GroupsController < Groups::ApplicationController if @group.import_state&.in_progress? redirect_to group_import_path(@group) else - publish_invite_members_for_task_experiment render_show_html end end @@ -312,16 +314,12 @@ class GroupsController < Groups::ApplicationController url_for(safe_params) end - def export_rate_limit + def check_export_rate_limit! prefixed_action = "group_#{params[:action]}".to_sym scope = params[:action] == :download_export ? @group : nil - if Gitlab::ApplicationRateLimiter.throttled?(prefixed_action, scope: [current_user, scope].compact) - Gitlab::ApplicationRateLimiter.log_request(request, "#{prefixed_action}_request_limit".to_sym, current_user) - - render plain: _('This endpoint has been requested too many times. Try again later.'), status: :too_many_requests - end + check_rate_limit!(prefixed_action, scope: [current_user, scope].compact) end def ensure_export_enabled @@ -380,13 +378,6 @@ class GroupsController < Groups::ApplicationController def captcha_required? captcha_enabled? && !params[:parent_id] end - - def publish_invite_members_for_task_experiment - return unless params[:open_modal] == 'invite_members_for_task' - return unless current_user&.can?(:admin_group_member, @group) - - experiment(:invite_members_for_task, namespace: @group).publish_to_client - end end GroupsController.prepend_mod_with('GroupsController') diff --git a/app/controllers/help_controller.rb b/app/controllers/help_controller.rb index e0020c22145..f267d383804 100644 --- a/app/controllers/help_controller.rb +++ b/app/controllers/help_controller.rb @@ -59,10 +59,6 @@ class HelpController < ApplicationController @instance_configuration = InstanceConfiguration.new end - def ui - @user = User.new(id: 0, name: 'John Doe', username: '@johndoe') - end - private def path_params diff --git a/app/controllers/import/base_controller.rb b/app/controllers/import/base_controller.rb index 53856e4575b..7ad3a2ee358 100644 --- a/app/controllers/import/base_controller.rb +++ b/app/controllers/import/base_controller.rb @@ -3,7 +3,7 @@ class Import::BaseController < ApplicationController include ActionView::Helpers::SanitizeHelper - before_action :import_rate_limit, only: [:create] + before_action -> { check_rate_limit!(:project_import, scope: [current_user, :project_import], redirect_back: true) }, only: [:create] feature_category :importers def status @@ -98,18 +98,4 @@ class Import::BaseController < ApplicationController def project_save_error(project) project.errors.full_messages.join(', ') end - - def import_rate_limit - key = "project_import".to_sym - - if rate_limiter.throttled?(key, scope: [current_user, key]) - rate_limiter.log_request(request, "#{key}_request_limit".to_sym, current_user) - - redirect_back_or_default(options: { alert: _('This endpoint has been requested too many times. Try again later.') }) - end - end - - def rate_limiter - ::Gitlab::ApplicationRateLimiter - end end diff --git a/app/controllers/import/bulk_imports_controller.rb b/app/controllers/import/bulk_imports_controller.rb index bec26cb547d..f26c06b7e37 100644 --- a/app/controllers/import/bulk_imports_controller.rb +++ b/app/controllers/import/bulk_imports_controller.rb @@ -40,13 +40,9 @@ class Import::BulkImportsController < ApplicationController end def create - response = ::BulkImports::CreateService.new(current_user, create_params, credentials).execute + responses = create_params.map { |entry| ::BulkImports::CreateService.new(current_user, entry, credentials).execute } - if response.success? - render json: response.payload.to_json(only: [:id]) - else - render json: { error: response.message }, status: response.http_status - end + render json: responses.map { |response| { success: response.success?, id: response.payload[:id], message: response.message } } end def realtime_changes diff --git a/app/controllers/import/gitlab_groups_controller.rb b/app/controllers/import/gitlab_groups_controller.rb index 503b10f766b..aca71f6d57a 100644 --- a/app/controllers/import/gitlab_groups_controller.rb +++ b/app/controllers/import/gitlab_groups_controller.rb @@ -4,7 +4,7 @@ class Import::GitlabGroupsController < ApplicationController include WorkhorseAuthorization before_action :ensure_group_import_enabled - before_action :import_rate_limit, only: %i[create] + before_action :check_import_rate_limit!, only: %i[create] feature_category :importers @@ -55,12 +55,9 @@ class Import::GitlabGroupsController < ApplicationController render_404 unless Feature.enabled?(:group_import_export, @group, default_enabled: true) end - def import_rate_limit - if Gitlab::ApplicationRateLimiter.throttled?(:group_import, scope: current_user) - Gitlab::ApplicationRateLimiter.log_request(request, :group_import_request_limit, current_user) - - flash[:alert] = _('This endpoint has been requested too many times. Try again later.') - redirect_to new_group_path + def check_import_rate_limit! + check_rate_limit!(:group_import, scope: current_user) do + redirect_to new_group_path, alert: _('This endpoint has been requested too many times. Try again later.') end end diff --git a/app/controllers/invites_controller.rb b/app/controllers/invites_controller.rb index d4b1306cc5e..2a7f2d42e2a 100644 --- a/app/controllers/invites_controller.rb +++ b/app/controllers/invites_controller.rb @@ -77,12 +77,6 @@ class InvitesController < ApplicationController def track_invite_join_click return unless member && initial_invite_email? - if params[:experiment_name] == 'invite_email_preview_text' - experiment(:invite_email_preview_text, actor: member).track(:join_clicked) - elsif params[:experiment_name] == 'invite_email_from' - experiment(:invite_email_from, actor: member).track(:join_clicked) - end - Gitlab::Tracking.event(self.class.name, 'join_clicked', label: 'invite_email', property: member.id.to_s) end @@ -104,7 +98,6 @@ class InvitesController < ApplicationController session[:invite_email] = member.invite_email session[:originating_member_id] = member.id if initial_invite_email? - session[:invite_email_experiment_name] = params[:experiment_name] if initial_invite_email? && params[:experiment_name] end def initial_invite_email? diff --git a/app/controllers/omniauth_callbacks_controller.rb b/app/controllers/omniauth_callbacks_controller.rb index 9d7a1712698..dc5b22e1606 100644 --- a/app/controllers/omniauth_callbacks_controller.rb +++ b/app/controllers/omniauth_callbacks_controller.rb @@ -9,7 +9,7 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController after_action :verify_known_sign_in - protect_from_forgery except: [:kerberos, :saml, :cas3, :failure], with: :exception, prepend: true + protect_from_forgery except: [:kerberos, :saml, :cas3, :failure] + AuthHelper.saml_providers, with: :exception, prepend: true feature_category :authentication_and_authorization @@ -162,6 +162,10 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController user = auth_user.find_and_update! if auth_user.valid_sign_in? + # In this case the `#current_user` would not be set. So we can't fetch it + # from that in `#context_user`. Pushing it manually here makes the information + # available in the logs for this request. + Gitlab::ApplicationContext.push(user: user) log_audit_event(user, with: oauth['provider']) set_remember_me(user) @@ -287,10 +291,6 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController def fail_admin_mode_invalid_credentials redirect_to new_admin_session_path, alert: _('Invalid login or password') end - - def context_user - current_user - end end OmniauthCallbacksController.prepend_mod_with('OmniauthCallbacksController') diff --git a/app/controllers/profiles/emails_controller.rb b/app/controllers/profiles/emails_controller.rb index 6e5b18cb885..be2cb270a19 100644 --- a/app/controllers/profiles/emails_controller.rb +++ b/app/controllers/profiles/emails_controller.rb @@ -2,8 +2,10 @@ class Profiles::EmailsController < Profiles::ApplicationController before_action :find_email, only: [:destroy, :resend_confirmation_instructions] - before_action -> { rate_limit!(:profile_add_new_email) }, only: [:create] - before_action -> { rate_limit!(:profile_resend_email_confirmation) }, only: [:resend_confirmation_instructions] + before_action -> { check_rate_limit!(:profile_add_new_email, scope: current_user, redirect_back: true) }, + only: [:create] + before_action -> { check_rate_limit!(:profile_resend_email_confirmation, scope: current_user, redirect_back: true) }, + only: [:resend_confirmation_instructions] feature_category :users @@ -42,16 +44,6 @@ class Profiles::EmailsController < Profiles::ApplicationController private - def rate_limit!(action) - rate_limiter = ::Gitlab::ApplicationRateLimiter - - if rate_limiter.throttled?(action, scope: current_user) - rate_limiter.log_request(request, action, current_user) - - redirect_back_or_default(options: { alert: _('This action has been performed too many times. Try again later.') }) - end - end - def email_params params.require(:email).permit(:email) end diff --git a/app/controllers/profiles/two_factor_auths_controller.rb b/app/controllers/profiles/two_factor_auths_controller.rb index e607346b40e..77fae34e2d2 100644 --- a/app/controllers/profiles/two_factor_auths_controller.rb +++ b/app/controllers/profiles/two_factor_auths_controller.rb @@ -8,7 +8,7 @@ class Profiles::TwoFactorAuthsController < Profiles::ApplicationController helper_method :current_password_required? before_action do - push_frontend_feature_flag(:webauthn) + push_frontend_feature_flag(:webauthn, default_enabled: :yaml) end feature_category :authentication_and_authorization @@ -44,7 +44,7 @@ class Profiles::TwoFactorAuthsController < Profiles::ApplicationController @qr_code = build_qr_code @account_string = account_string - if Feature.enabled?(:webauthn) + if Feature.enabled?(:webauthn, default_enabled: :yaml) setup_webauthn_registration else setup_u2f_registration @@ -69,7 +69,7 @@ class Profiles::TwoFactorAuthsController < Profiles::ApplicationController @error = { message: _('Invalid pin code.') } @qr_code = build_qr_code - if Feature.enabled?(:webauthn) + if Feature.enabled?(:webauthn, default_enabled: :yaml) setup_webauthn_registration else setup_u2f_registration diff --git a/app/controllers/profiles_controller.rb b/app/controllers/profiles_controller.rb index 6330a6aa107..e6b80f90dca 100644 --- a/app/controllers/profiles_controller.rb +++ b/app/controllers/profiles_controller.rb @@ -8,7 +8,7 @@ class ProfilesController < Profiles::ApplicationController before_action :authorize_change_username!, only: :update_username skip_before_action :require_email, only: [:show, :update] before_action do - push_frontend_feature_flag(:webauthn) + push_frontend_feature_flag(:webauthn, default_enabled: :yaml) end feature_category :users diff --git a/app/controllers/projects/autocomplete_sources_controller.rb b/app/controllers/projects/autocomplete_sources_controller.rb index 0d5f64c739c..cf432cfb429 100644 --- a/app/controllers/projects/autocomplete_sources_controller.rb +++ b/app/controllers/projects/autocomplete_sources_controller.rb @@ -8,6 +8,8 @@ class Projects::AutocompleteSourcesController < Projects::ApplicationController feature_category :users, [:members] feature_category :snippets, [:snippets] + urgency :low, [:merge_requests] + def members render json: ::Projects::ParticipantsService.new(@project, current_user).execute(target) end diff --git a/app/controllers/projects/blame_controller.rb b/app/controllers/projects/blame_controller.rb index 0f87690bba5..57a06f26f8c 100644 --- a/app/controllers/projects/blame_controller.rb +++ b/app/controllers/projects/blame_controller.rb @@ -27,3 +27,5 @@ class Projects::BlameController < Projects::ApplicationController @blame = Gitlab::View::Presenter::Factory.new(@blame, project: @project, path: @path).fabricate! end end + +Projects::BlameController.prepend_mod diff --git a/app/controllers/projects/blob_controller.rb b/app/controllers/projects/blob_controller.rb index cd50c8cf5b1..b30ef7506aa 100644 --- a/app/controllers/projects/blob_controller.rb +++ b/app/controllers/projects/blob_controller.rb @@ -44,7 +44,7 @@ class Projects::BlobController < Projects::ApplicationController before_action do push_frontend_feature_flag(:refactor_blob_viewer, @project, default_enabled: :yaml) - push_frontend_feature_flag(:refactor_text_viewer, @project, default_enabled: :yaml) + push_frontend_feature_flag(:highlight_js, @project, default_enabled: :yaml) push_frontend_feature_flag(:consolidated_edit_button, @project, default_enabled: :yaml) push_licensed_feature(:file_locks) if @project.licensed_feature_available?(:file_locks) end @@ -99,7 +99,7 @@ class Projects::BlobController < Projects::ApplicationController @content = params[:content] @blob.load_all_data! diffy = Diffy::Diff.new(@blob.data, @content, diff: '-U 3', include_diff_info: true) - diff_lines = diffy.diff.scan(/.*\n/)[2..-1] + diff_lines = diffy.diff.scan(/.*\n/)[2..] diff_lines = Gitlab::Diff::Parser.new.parse(diff_lines).to_a @diff_lines = Gitlab::Diff::Highlight.new(diff_lines, repository: @repository).highlight @@ -298,3 +298,5 @@ class Projects::BlobController < Projects::ApplicationController experiment(:code_quality_walkthrough, namespace: @project.root_ancestor).track(:commit_created) end end + +Projects::BlobController.prepend_mod diff --git a/app/controllers/projects/boards_controller.rb b/app/controllers/projects/boards_controller.rb index 7354c2c71ac..81ad6243efe 100644 --- a/app/controllers/projects/boards_controller.rb +++ b/app/controllers/projects/boards_controller.rb @@ -11,7 +11,6 @@ class Projects::BoardsController < Projects::ApplicationController push_frontend_feature_flag(:issue_boards_filtered_search, project, default_enabled: :yaml) push_frontend_feature_flag(:board_multi_select, project, default_enabled: :yaml) push_frontend_feature_flag(:iteration_cadences, project&.group, default_enabled: :yaml) - push_frontend_feature_flag(:labels_widget, project, default_enabled: :yaml) experiment(:prominent_create_board_btn, subject: current_user) do |e| e.use { } e.try { } diff --git a/app/controllers/projects/ci/lints_controller.rb b/app/controllers/projects/ci/lints_controller.rb index 9dc3194df85..7ef5016ac00 100644 --- a/app/controllers/projects/ci/lints_controller.rb +++ b/app/controllers/projects/ci/lints_controller.rb @@ -6,6 +6,7 @@ class Projects::Ci::LintsController < Projects::ApplicationController feature_category :pipeline_authoring respond_to :json, only: [:create] + urgency :low, [:create] def show end diff --git a/app/controllers/projects/ci/pipeline_editor_controller.rb b/app/controllers/projects/ci/pipeline_editor_controller.rb index 600516f95a2..6f12e3940dd 100644 --- a/app/controllers/projects/ci/pipeline_editor_controller.rb +++ b/app/controllers/projects/ci/pipeline_editor_controller.rb @@ -9,6 +9,8 @@ class Projects::Ci::PipelineEditorController < Projects::ApplicationController feature_category :pipeline_authoring + urgency :low, [:show] + def show end @@ -21,7 +23,7 @@ class Projects::Ci::PipelineEditorController < Projects::ApplicationController def setup_walkthrough_experiment experiment(:pipeline_editor_walkthrough, namespace: @project.namespace, sticky_to: current_user) do |e| e.candidate {} - e.record! + e.publish_to_database end end end diff --git a/app/controllers/projects/forks_controller.rb b/app/controllers/projects/forks_controller.rb index 5154f145b46..ba83f8dad35 100644 --- a/app/controllers/projects/forks_controller.rb +++ b/app/controllers/projects/forks_controller.rb @@ -22,6 +22,8 @@ class Projects::ForksController < Projects::ApplicationController end def index + @sort = params[:sort] + @total_forks_count = project.forks.size @public_forks_count = project.forks.public_only.size @private_forks_count = @total_forks_count - project.forks.public_and_internal_only.size diff --git a/app/controllers/projects/google_cloud/base_controller.rb b/app/controllers/projects/google_cloud/base_controller.rb new file mode 100644 index 00000000000..aff305ab7d6 --- /dev/null +++ b/app/controllers/projects/google_cloud/base_controller.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +class Projects::GoogleCloud::BaseController < Projects::ApplicationController + feature_category :five_minute_production_app + + before_action :admin_project_google_cloud! + before_action :google_oauth2_enabled! + before_action :feature_flag_enabled! + + private + + def admin_project_google_cloud! + access_denied! unless can?(current_user, :admin_project_google_cloud, project) + end + + def google_oauth2_enabled! + config = Gitlab::Auth::OAuth::Provider.config_for('google_oauth2') + if config.app_id.blank? || config.app_secret.blank? + access_denied! 'This GitLab instance not configured for Google Oauth2.' + end + end + + def feature_flag_enabled! + access_denied! unless Feature.enabled?(:incubation_5mp_google_cloud, project) + end +end diff --git a/app/controllers/projects/google_cloud/service_accounts_controller.rb b/app/controllers/projects/google_cloud/service_accounts_controller.rb new file mode 100644 index 00000000000..a69a744154c --- /dev/null +++ b/app/controllers/projects/google_cloud/service_accounts_controller.rb @@ -0,0 +1,85 @@ +# frozen_string_literal: true + +class Projects::GoogleCloud::ServiceAccountsController < Projects::GoogleCloud::BaseController + before_action :validate_gcp_token! + + def index + @google_cloud_path = project_google_cloud_index_path(project) + google_api_client = GoogleApi::CloudPlatform::Client.new(token_in_session, nil) + gcp_projects = google_api_client.list_projects + + if gcp_projects.empty? + @js_data = { screen: 'no_gcp_projects' }.to_json + render status: :unauthorized, template: 'projects/google_cloud/errors/no_gcp_projects' + else + @js_data = { + screen: 'service_accounts_form', + gcpProjects: gcp_projects, + environments: project.environments, + cancelPath: project_google_cloud_index_path(project) + }.to_json + end + rescue Google::Apis::ClientError => error + handle_gcp_error(error, project) + end + + def create + google_api_client = GoogleApi::CloudPlatform::Client.new(token_in_session, nil) + service_accounts_service = GoogleCloud::ServiceAccountsService.new(project) + gcp_project = params[:gcp_project] + environment = params[:environment] + generated_name = "GitLab :: #{@project.name} :: #{environment}" + generated_desc = "GitLab generated service account for project '#{@project.name}' and environment '#{environment}'" + + service_account = google_api_client.create_service_account(gcp_project, generated_name, generated_desc) + service_account_key = google_api_client.create_service_account_key(gcp_project, service_account.unique_id) + + service_accounts_service.add_for_project( + environment, + service_account.project_id, + service_account.to_json, + service_account_key.to_json + ) + + redirect_to project_google_cloud_index_path(project), notice: _('Service account generated successfully') + rescue Google::Apis::ClientError, Google::Apis::ServerError, Google::Apis::AuthorizationError => error + handle_gcp_error(error, project) + end + + private + + def validate_gcp_token! + is_token_valid = GoogleApi::CloudPlatform::Client.new(token_in_session, nil) + .validate_token(expires_at_in_session) + + return if is_token_valid + + return_url = project_google_cloud_index_path(project) + state = generate_session_key_redirect(request.url, return_url) + @authorize_url = GoogleApi::CloudPlatform::Client.new(nil, + callback_google_api_auth_url, + state: state).authorize_url + redirect_to @authorize_url + end + + def generate_session_key_redirect(uri, error_uri) + GoogleApi::CloudPlatform::Client.new_session_key_for_redirect_uri do |key| + session[key] = uri + session[:error_uri] = error_uri + end + end + + def token_in_session + session[GoogleApi::CloudPlatform::Client.session_key_for_token] + end + + def expires_at_in_session + session[GoogleApi::CloudPlatform::Client.session_key_for_expires_at] + end + + def handle_gcp_error(error, project) + Gitlab::ErrorTracking.track_exception(error, project_id: project.id) + @js_data = { screen: 'gcp_error', error: error.to_s }.to_json + render status: :unauthorized, template: 'projects/google_cloud/errors/gcp_error' + end +end diff --git a/app/controllers/projects/google_cloud_controller.rb b/app/controllers/projects/google_cloud_controller.rb index 7257ed1ef6f..1fa8ae60376 100644 --- a/app/controllers/projects/google_cloud_controller.rb +++ b/app/controllers/projects/google_cloud_controller.rb @@ -1,34 +1,12 @@ # frozen_string_literal: true -class Projects::GoogleCloudController < Projects::ApplicationController - feature_category :google_cloud - - before_action :admin_project_google_cloud? - before_action :google_oauth2_enabled? - before_action :feature_flag_enabled? - +class Projects::GoogleCloudController < Projects::GoogleCloud::BaseController def index @js_data = { + screen: 'home', serviceAccounts: GoogleCloud::ServiceAccountsService.new(project).find_for_project, - createServiceAccountUrl: '#mocked-url-create-service', + createServiceAccountUrl: project_google_cloud_service_accounts_path(project), emptyIllustrationUrl: ActionController::Base.helpers.image_path('illustrations/pipelines_empty.svg') }.to_json end - - private - - def admin_project_google_cloud? - access_denied! unless can?(current_user, :admin_project_google_cloud, project) - end - - def google_oauth2_enabled? - config = Gitlab::Auth::OAuth::Provider.config_for('google_oauth2') - if config.app_id.blank? || config.app_secret.blank? - access_denied! 'This GitLab instance not configured for Google Oauth2.' - end - end - - def feature_flag_enabled? - access_denied! unless Feature.enabled?(:incubation_5mp_google_cloud) - end end diff --git a/app/controllers/projects/hooks_controller.rb b/app/controllers/projects/hooks_controller.rb index c79e5a8cc85..99eba32e00f 100644 --- a/app/controllers/projects/hooks_controller.rb +++ b/app/controllers/projects/hooks_controller.rb @@ -6,7 +6,7 @@ class Projects::HooksController < Projects::ApplicationController # Authorize before_action :authorize_admin_project! before_action :hook_logs, only: :edit - before_action -> { create_rate_limit(:project_testing_hook, @project) }, only: :test + before_action -> { check_rate_limit!(:project_testing_hook, scope: [@project, current_user]) }, only: :test respond_to :html diff --git a/app/controllers/projects/integrations/shimos_controller.rb b/app/controllers/projects/integrations/shimos_controller.rb new file mode 100644 index 00000000000..827dbb8f3f9 --- /dev/null +++ b/app/controllers/projects/integrations/shimos_controller.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +module Projects + module Integrations + class ShimosController < Projects::ApplicationController + feature_category :integrations + + before_action :ensure_renderable + + def show; end + + private + + def ensure_renderable + render_404 unless Feature.enabled?(:shimo_integration, project) && project.has_shimo? && project.shimo_integration&.render? + end + end + end +end diff --git a/app/controllers/projects/issues_controller.rb b/app/controllers/projects/issues_controller.rb index 853e9c7ccdd..fc67cd98d15 100644 --- a/app/controllers/projects/issues_controller.rb +++ b/app/controllers/projects/issues_controller.rb @@ -10,7 +10,7 @@ class Projects::IssuesController < Projects::ApplicationController include RecordUserLastActivity ISSUES_EXCEPT_ACTIONS = %i[index calendar new create bulk_update import_csv export_csv service_desk].freeze - SET_ISSUEABLES_INDEX_ONLY_ACTIONS = %i[index calendar service_desk].freeze + SET_ISSUABLES_INDEX_ONLY_ACTIONS = %i[index calendar service_desk].freeze prepend_before_action(only: [:index]) { authenticate_sessionless_user!(:rss) } prepend_before_action(only: [:calendar]) { authenticate_sessionless_user!(:ics) } @@ -22,7 +22,7 @@ class Projects::IssuesController < Projects::ApplicationController before_action :issue, unless: ->(c) { ISSUES_EXCEPT_ACTIONS.include?(c.action_name.to_sym) } after_action :log_issue_show, unless: ->(c) { ISSUES_EXCEPT_ACTIONS.include?(c.action_name.to_sym) } - before_action :set_issuables_index, if: ->(c) { SET_ISSUEABLES_INDEX_ONLY_ACTIONS.include?(c.action_name.to_sym) } + before_action :set_issuables_index, if: ->(c) { SET_ISSUABLES_INDEX_ONLY_ACTIONS.include?(c.action_name.to_sym) } # Allow write(create) issue before_action :authorize_create_issue!, only: [:new, :create] @@ -37,7 +37,9 @@ class Projects::IssuesController < Projects::ApplicationController before_action :authorize_download_code!, only: [:related_branches] # Limit the amount of issues created per minute - before_action :create_rate_limit, only: [:create], if: -> { Feature.disabled?('rate_limited_service_issues_create', project, default_enabled: :yaml) } + before_action -> { check_rate_limit!(:issues_create, scope: [@project, @current_user])}, + only: [:create], + if: -> { Feature.disabled?('rate_limited_service_issues_create', project, default_enabled: :yaml) } before_action do push_frontend_feature_flag(:tribute_autocomplete, @project) @@ -49,19 +51,9 @@ class Projects::IssuesController < Projects::ApplicationController before_action only: :show do push_frontend_feature_flag(:real_time_issue_sidebar, @project, default_enabled: :yaml) - push_frontend_feature_flag(:confidential_notes, @project, default_enabled: :yaml) + push_frontend_feature_flag(:confidential_notes, project&.group, default_enabled: :yaml) push_frontend_feature_flag(:issue_assignees_widget, @project, default_enabled: :yaml) - push_frontend_feature_flag(:labels_widget, @project, default_enabled: :yaml) push_frontend_feature_flag(:paginated_issue_discussions, @project, default_enabled: :yaml) - - experiment(:invite_members_in_comment, namespace: @project.root_ancestor) do |experiment_instance| - experiment_instance.exclude! unless helpers.can_admin_project_member?(@project) - - experiment_instance.use {} - experiment_instance.try(:invite_member_link) {} - - experiment_instance.track(:view, property: @project.root_ancestor.id.to_s) - end end around_action :allow_gitaly_ref_name_caching, only: [:discussions] @@ -373,20 +365,6 @@ class Projects::IssuesController < Projects::ApplicationController project_compare_path(project, from: project.default_branch, to: branch[:name]) end - def create_rate_limit - key = :issues_create - - if rate_limiter.throttled?(key, scope: [@project, @current_user]) - rate_limiter.log_request(request, "#{key}_request_limit".to_sym, current_user) - - render plain: _('This endpoint has been requested too many times. Try again later.'), status: :too_many_requests - end - end - - def rate_limiter - ::Gitlab::ApplicationRateLimiter - end - def service_desk? action_name == 'service_desk' end diff --git a/app/controllers/projects/jobs_controller.rb b/app/controllers/projects/jobs_controller.rb index 81b8da9cba3..fa7c62c34dd 100644 --- a/app/controllers/projects/jobs_controller.rb +++ b/app/controllers/projects/jobs_controller.rb @@ -4,8 +4,8 @@ class Projects::JobsController < Projects::ApplicationController include SendFileUpload include ContinueParams - before_action :find_job_as_build, except: [:index, :play] - before_action :find_job_as_processable, only: [:play] + before_action :find_job_as_build, except: [:index, :play, :show] + before_action :find_job_as_processable, only: [:play, :show] before_action :authorize_read_build_trace!, only: [:trace, :raw] before_action :authorize_read_build! before_action :authorize_update_build!, @@ -42,7 +42,7 @@ class Projects::JobsController < Projects::ApplicationController format.json do Gitlab::PollingInterval.set_header(response, interval: 10_000) - render json: BuildSerializer + render json: Ci::JobSerializer .new(project: @project, current_user: @current_user) .represent(@build.present(current_user: current_user), {}, BuildDetailsEntity) end @@ -118,7 +118,7 @@ class Projects::JobsController < Projects::ApplicationController end def status - render json: BuildSerializer + render json: Ci::JobSerializer .new(project: @project, current_user: @current_user) .represent_status(@build.present(current_user: current_user)) end diff --git a/app/controllers/projects/learn_gitlab_controller.rb b/app/controllers/projects/learn_gitlab_controller.rb index 91a43c5f03f..177533b89c8 100644 --- a/app/controllers/projects/learn_gitlab_controller.rb +++ b/app/controllers/projects/learn_gitlab_controller.rb @@ -3,6 +3,7 @@ class Projects::LearnGitlabController < Projects::ApplicationController before_action :authenticate_user! before_action :check_experiment_enabled? + before_action :enable_invite_for_help_continuous_onboarding_experiment feature_category :users @@ -14,4 +15,13 @@ class Projects::LearnGitlabController < Projects::ApplicationController def check_experiment_enabled? return access_denied! unless helpers.learn_gitlab_enabled?(project) end + + def enable_invite_for_help_continuous_onboarding_experiment + return unless current_user.can?(:admin_group_member, project.namespace) + + experiment(:invite_for_help_continuous_onboarding, namespace: project.namespace) do |e| + e.candidate {} + e.publish_to_database + end + end end diff --git a/app/controllers/projects/merge_requests/conflicts_controller.rb b/app/controllers/projects/merge_requests/conflicts_controller.rb index a8038878504..76a233afa13 100644 --- a/app/controllers/projects/merge_requests/conflicts_controller.rb +++ b/app/controllers/projects/merge_requests/conflicts_controller.rb @@ -5,6 +5,12 @@ class Projects::MergeRequests::ConflictsController < Projects::MergeRequests::Ap before_action :authorize_can_resolve_conflicts! + urgency :low, [ + :show, + :conflict_for_path, + :resolve_conflicts + ] + def show respond_to do |format| format.html do diff --git a/app/controllers/projects/merge_requests/content_controller.rb b/app/controllers/projects/merge_requests/content_controller.rb index 399745151b1..588fc85ff77 100644 --- a/app/controllers/projects/merge_requests/content_controller.rb +++ b/app/controllers/projects/merge_requests/content_controller.rb @@ -13,6 +13,11 @@ class Projects::MergeRequests::ContentController < Projects::MergeRequests::Appl FAST_POLLING_INTERVAL = 10.seconds.in_milliseconds SLOW_POLLING_INTERVAL = 5.minutes.in_milliseconds + urgency :low, [ + :widget, + :cached_widget + ] + def widget respond_to do |format| format.json do diff --git a/app/controllers/projects/merge_requests/creations_controller.rb b/app/controllers/projects/merge_requests/creations_controller.rb index ecc5ad1f84e..beb179f584b 100644 --- a/app/controllers/projects/merge_requests/creations_controller.rb +++ b/app/controllers/projects/merge_requests/creations_controller.rb @@ -10,6 +10,15 @@ class Projects::MergeRequests::CreationsController < Projects::MergeRequests::Ap before_action :apply_diff_view_cookie!, only: [:diffs, :diff_for_path] before_action :build_merge_request, except: [:create] + urgency :low, [ + :new, + :create, + :pipelines, + :diffs, + :branch_from, + :branch_to + ] + def new define_new_vars end diff --git a/app/controllers/projects/merge_requests/diffs_controller.rb b/app/controllers/projects/merge_requests/diffs_controller.rb index 1188aec24a8..32ca7d779d2 100644 --- a/app/controllers/projects/merge_requests/diffs_controller.rb +++ b/app/controllers/projects/merge_requests/diffs_controller.rb @@ -14,6 +14,13 @@ class Projects::MergeRequests::DiffsController < Projects::MergeRequests::Applic after_action :track_viewed_diffs_events, only: [:diffs_batch] + urgency :low, [ + :show, + :diff_for_path, + :diffs_batch, + :diffs_metadata + ] + def show render_diffs end @@ -36,6 +43,7 @@ class Projects::MergeRequests::DiffsController < Projects::MergeRequests::Applic options = { environment: environment, merge_request: @merge_request, + commit: commit, diff_view: diff_view, merge_ref_head_diff: render_merge_ref_head_diff?, pagination_data: diffs.pagination_data, diff --git a/app/controllers/projects/merge_requests/drafts_controller.rb b/app/controllers/projects/merge_requests/drafts_controller.rb index ca3f36cafe1..645720a0889 100644 --- a/app/controllers/projects/merge_requests/drafts_controller.rb +++ b/app/controllers/projects/merge_requests/drafts_controller.rb @@ -9,6 +9,13 @@ class Projects::MergeRequests::DraftsController < Projects::MergeRequests::Appli before_action :authorize_admin_draft!, only: [:update, :destroy] before_action :authorize_admin_draft!, if: -> { action_name == 'publish' && params[:id].present? } + urgency :low, [ + :create, + :update, + :destroy, + :publish + ] + def index drafts = prepare_notes_for_rendering(draft_notes) render json: DraftNoteSerializer.new(current_user: current_user).represent(drafts) @@ -110,7 +117,7 @@ class Projects::MergeRequests::DraftsController < Projects::MergeRequests::Appli def render_draft_note(note) params = { target_id: merge_request.id, target_type: 'MergeRequest', text: note.note } result = PreviewMarkdownService.new(@project, current_user, params).execute - markdown_params = { markdown_engine: result[:markdown_engine], issuable_state_filter_enabled: true } + markdown_params = { markdown_engine: result[:markdown_engine], issuable_reference_expansion_enabled: true } note.rendered_note = view_context.markdown(result[:text], markdown_params) note.users_referenced = result[:users] diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb index 6c5a8aa0610..7133233f083 100644 --- a/app/controllers/projects/merge_requests_controller.rb +++ b/app/controllers/projects/merge_requests_controller.rb @@ -42,21 +42,11 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo push_frontend_feature_flag(:restructured_mr_widget, project, default_enabled: :yaml) push_frontend_feature_flag(:mr_changes_fluid_layout, project, default_enabled: :yaml) push_frontend_feature_flag(:mr_attention_requests, project, default_enabled: :yaml) - push_frontend_feature_flag(:labels_widget, project, default_enabled: :yaml) # Usage data feature flags push_frontend_feature_flag(:users_expanding_widgets_usage_data, @project, default_enabled: :yaml) push_frontend_feature_flag(:diff_settings_usage_data, default_enabled: :yaml) push_frontend_feature_flag(:diff_searching_usage_data, @project, default_enabled: :yaml) - - experiment(:invite_members_in_comment, namespace: @project.root_ancestor) do |experiment_instance| - experiment_instance.exclude! unless helpers.can_admin_project_member?(@project) - - experiment_instance.use {} - experiment_instance.try(:invite_member_link) {} - - experiment_instance.track(:view, property: @project.root_ancestor.id.to_s) - end end before_action do @@ -74,15 +64,28 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo :show, :toggle_award_emoji, :toggle_subscription, :update ] - feature_category :code_testing, [ - :test_reports, :coverage_reports, :codequality_reports, - :codequality_mr_diff_reports - ] - + feature_category :code_testing, [:test_reports, :coverage_reports] + feature_category :code_quality, [:codequality_reports, :codequality_mr_diff_reports] feature_category :accessibility_testing, [:accessibility_reports] feature_category :infrastructure_as_code, [:terraform_reports] feature_category :continuous_integration, [:pipeline_status, :pipelines, :exposed_artifacts] + urgency :high, [:export_csv] + urgency :low, [ + :index, + :show, + :commits, + :bulk_update, + :edit, + :update, + :cancel_auto_merge, + :merge, + :ci_environments_status, + :destroy, + :rebase, + :discussions + ] + def index @merge_requests = @issuables @@ -286,7 +289,7 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo if merge_request.errors.present? render json: @merge_request.errors, status: :bad_request else - render json: serializer.represent(@merge_request, serializer: 'basic') + render json: serializer.represent(@merge_request, serializer: params[:serializer] || 'basic') end end end diff --git a/app/controllers/projects/notes_controller.rb b/app/controllers/projects/notes_controller.rb index e8057308386..7322e08e62e 100644 --- a/app/controllers/projects/notes_controller.rb +++ b/app/controllers/projects/notes_controller.rb @@ -57,7 +57,7 @@ class Projects::NotesController < Projects::ApplicationController def outdated_line_change diff_lines = Rails.cache.fetch(['note', note.id, 'oudated_line_change'], expires_in: 7.days) do - ::MergeRequests::OutdatedDiscussionDiffLinesService.new(project: @project, note: note).execute.to_json + ::MergeRequests::OutdatedDiscussionDiffLinesService.new(project: note.noteable.source_project, note: note).execute.to_json end render json: diff_lines diff --git a/app/controllers/projects/pipeline_schedules_controller.rb b/app/controllers/projects/pipeline_schedules_controller.rb index 4af7508b935..ac94cc001dd 100644 --- a/app/controllers/projects/pipeline_schedules_controller.rb +++ b/app/controllers/projects/pipeline_schedules_controller.rb @@ -3,7 +3,7 @@ class Projects::PipelineSchedulesController < Projects::ApplicationController before_action :schedule, except: [:index, :new, :create] - before_action :play_rate_limit, only: [:play] + before_action :check_play_rate_limit!, only: [:play] before_action :authorize_play_pipeline_schedule!, only: [:play] before_action :authorize_read_pipeline_schedule! before_action :authorize_create_pipeline_schedule!, only: [:new, :create] @@ -81,19 +81,15 @@ class Projects::PipelineSchedulesController < Projects::ApplicationController private - def play_rate_limit + def check_play_rate_limit! return unless current_user - if rate_limiter.throttled?(:play_pipeline_schedule, scope: [current_user, schedule]) + check_rate_limit!(:play_pipeline_schedule, scope: [current_user, schedule]) do flash[:alert] = _('You cannot play this scheduled pipeline at the moment. Please wait a minute.') redirect_to pipeline_schedules_path(@project) end end - def rate_limiter - ::Gitlab::ApplicationRateLimiter - end - def schedule @schedule ||= project.pipeline_schedules.find(params[:id]) end diff --git a/app/controllers/projects/pipelines_controller.rb b/app/controllers/projects/pipelines_controller.rb index a2312484a9b..71dc67bb6dc 100644 --- a/app/controllers/projects/pipelines_controller.rb +++ b/app/controllers/projects/pipelines_controller.rb @@ -14,13 +14,22 @@ class Projects::PipelinesController < Projects::ApplicationController before_action :authorize_update_pipeline!, only: [:retry, :cancel] before_action :ensure_pipeline, only: [:show, :downloadable_artifacts] + before_action do + push_frontend_feature_flag(:jobs_tab_vue, @project, default_enabled: :yaml) + end + # Will be removed with https://gitlab.com/gitlab-org/gitlab/-/issues/225596 before_action :redirect_for_legacy_scope_filter, only: [:index], if: -> { request.format.html? } around_action :allow_gitaly_ref_name_caching, only: [:index, :show] + # Will be removed with https://gitlab.com/gitlab-org/gitlab/-/issues/345074 track_redis_hll_event :charts, name: 'p_analytics_pipelines' + track_redis_hll_event :charts, name: 'p_analytics_ci_cd_pipelines', if: -> { should_track_ci_cd_pipelines? } + track_redis_hll_event :charts, name: 'p_analytics_ci_cd_deployment_frequency', if: -> { should_track_ci_cd_deployment_frequency? } + track_redis_hll_event :charts, name: 'p_analytics_ci_cd_lead_time', if: -> { should_track_ci_cd_lead_time? } + wrap_parameters Ci::Pipeline POLLING_INTERVAL = 10_000 @@ -307,7 +316,7 @@ class Projects::PipelinesController < Projects::ApplicationController e.control {} e.candidate {} - e.record! + e.publish_to_database end end @@ -320,9 +329,21 @@ class Projects::PipelinesController < Projects::ApplicationController e.control {} e.candidate {} - e.record! + e.publish_to_database end end + + def should_track_ci_cd_pipelines? + params[:chart].blank? || params[:chart] == 'pipelines' + end + + def should_track_ci_cd_deployment_frequency? + params[:chart] == 'deployment-frequency' + end + + def should_track_ci_cd_lead_time? + params[:chart] == 'lead-time' + end end Projects::PipelinesController.prepend_mod_with('Projects::PipelinesController') diff --git a/app/controllers/projects/prometheus/alerts_controller.rb b/app/controllers/projects/prometheus/alerts_controller.rb index 312919831d4..7aebff13278 100644 --- a/app/controllers/projects/prometheus/alerts_controller.rb +++ b/app/controllers/projects/prometheus/alerts_controller.rb @@ -82,17 +82,17 @@ module Projects def create_service Projects::Prometheus::Alerts::CreateService - .new(project, current_user, alerts_params) + .new(project: project, current_user: current_user, params: alerts_params) end def update_service Projects::Prometheus::Alerts::UpdateService - .new(project, current_user, alerts_params) + .new(project: project, current_user: current_user, params: alerts_params) end def destroy_service Projects::Prometheus::Alerts::DestroyService - .new(project, current_user, nil) + .new(project: project, current_user: current_user, params: nil) end def schedule_prometheus_update! diff --git a/app/controllers/projects/raw_controller.rb b/app/controllers/projects/raw_controller.rb index e86d2490282..9707b70f26f 100644 --- a/app/controllers/projects/raw_controller.rb +++ b/app/controllers/projects/raw_controller.rb @@ -13,7 +13,7 @@ class Projects::RawController < Projects::ApplicationController before_action :set_ref_and_path before_action :require_non_empty_project before_action :authorize_download_code! - before_action :show_rate_limit, only: [:show], unless: :external_storage_request? + before_action :check_show_rate_limit!, only: [:show], unless: :external_storage_request? before_action :redirect_to_external_storage, only: :show, if: :static_objects_external_storage_enabled? feature_category :source_code_management @@ -33,21 +33,11 @@ class Projects::RawController < Projects::ApplicationController @ref, @path = extract_ref(get_id) end - def show_rate_limit - if rate_limiter.throttled?(:show_raw_controller, scope: [@project, @path], threshold: raw_blob_request_limit) - rate_limiter.log_request(request, :raw_blob_request_limit, current_user) - + def check_show_rate_limit! + check_rate_limit!(:raw_blob, scope: [@project, @path]) do render plain: _('You cannot access the raw file. Please wait a minute.'), status: :too_many_requests end end - - def rate_limiter - ::Gitlab::ApplicationRateLimiter - end - - def raw_blob_request_limit - Gitlab::CurrentSettings - .current_application_settings - .raw_blob_request_limit - end end + +Projects::RawController.prepend_mod diff --git a/app/controllers/projects/repositories_controller.rb b/app/controllers/projects/repositories_controller.rb index 8beebb52980..77826a2f789 100644 --- a/app/controllers/projects/repositories_controller.rb +++ b/app/controllers/projects/repositories_controller.rb @@ -3,16 +3,16 @@ class Projects::RepositoriesController < Projects::ApplicationController include ExtractsPath include StaticObjectExternalStorage - include Gitlab::RateLimitHelpers include HotlinkInterceptor + include Gitlab::RepositoryArchiveRateLimiter prepend_before_action(only: [:archive]) { authenticate_sessionless_user!(:archive) } skip_before_action :default_cache_headers, only: :archive # Authorize + before_action :check_archive_rate_limiting!, only: :archive before_action :require_non_empty_project, except: :create - before_action :archive_rate_limit!, only: :archive before_action :intercept_hotlinking!, only: :archive before_action :assign_archive_vars, only: :archive before_action :assign_append_sha, only: :archive @@ -42,12 +42,6 @@ class Projects::RepositoriesController < Projects::ApplicationController private - def archive_rate_limit! - if archive_rate_limit_reached?(current_user, @project) - render plain: ::Gitlab::RateLimitHelpers::ARCHIVE_RATE_LIMIT_REACHED_MESSAGE, status: :too_many_requests - end - end - def repo_params @repo_params ||= { ref: @ref, path: params[:path], format: params[:format], append_sha: @append_sha } end @@ -125,6 +119,12 @@ class Projects::RepositoriesController < Projects::ApplicationController [path, nil] end end + + def check_archive_rate_limiting! + check_archive_rate_limit!(current_user, @project) do + render(plain: _('This archive has been requested too many times. Try again later.'), status: :too_many_requests) + end + end end Projects::RepositoriesController.prepend_mod_with('Projects::RepositoriesController') diff --git a/app/controllers/projects/runners_controller.rb b/app/controllers/projects/runners_controller.rb index e841c3e3d49..62a9f8a4625 100644 --- a/app/controllers/projects/runners_controller.rb +++ b/app/controllers/projects/runners_controller.rb @@ -4,8 +4,6 @@ class Projects::RunnersController < Projects::ApplicationController before_action :authorize_admin_build! before_action :runner, only: [:edit, :update, :destroy, :pause, :resume, :show] - layout 'project_settings' - feature_category :runner def index diff --git a/app/controllers/projects/settings/ci_cd_controller.rb b/app/controllers/projects/settings/ci_cd_controller.rb index 4fe37352995..ef6c10d43cd 100644 --- a/app/controllers/projects/settings/ci_cd_controller.rb +++ b/app/controllers/projects/settings/ci_cd_controller.rb @@ -9,10 +9,10 @@ module Projects layout 'project_settings' before_action :authorize_admin_pipeline! + before_action :check_builds_available! before_action :define_variables before_action do push_frontend_feature_flag(:ajax_new_deploy_token, @project) - push_frontend_feature_flag(:ci_scoped_job_token, @project, default_enabled: :yaml) end helper_method :highlight_badge diff --git a/app/controllers/projects/tree_controller.rb b/app/controllers/projects/tree_controller.rb index f8f2c1f0836..660ebcc30d3 100644 --- a/app/controllers/projects/tree_controller.rb +++ b/app/controllers/projects/tree_controller.rb @@ -60,3 +60,5 @@ class Projects::TreeController < Projects::ApplicationController } end end + +Projects::TreeController.prepend_mod diff --git a/app/controllers/projects/usage_quotas_controller.rb b/app/controllers/projects/usage_quotas_controller.rb index b319e427eaa..680874ffee4 100644 --- a/app/controllers/projects/usage_quotas_controller.rb +++ b/app/controllers/projects/usage_quotas_controller.rb @@ -9,14 +9,5 @@ class Projects::UsageQuotasController < Projects::ApplicationController def index @hide_search_settings = true - @storage_app_data = { - project_path: @project.full_path, - usage_quotas_help_page_path: help_page_path('user/usage_quotas'), - build_artifacts_help_page_path: help_page_path('ci/pipelines/job_artifacts', anchor: 'when-job-artifacts-are-deleted'), - packages_help_page_path: help_page_path('user/packages/package_registry/index.md', anchor: 'delete-a-package'), - repository_help_page_path: help_page_path('user/project/repository/reducing_the_repo_size_using_git'), - snippets_help_page_path: help_page_path('user/snippets', anchor: 'reduce-snippets-repository-size'), - wiki_help_page_path: help_page_path('administration/wikis/index.md', anchor: 'reduce-wiki-repository-size') - } end end diff --git a/app/controllers/projects/variables_controller.rb b/app/controllers/projects/variables_controller.rb index f93c75a203e..e7bccf5a243 100644 --- a/app/controllers/projects/variables_controller.rb +++ b/app/controllers/projects/variables_controller.rb @@ -5,6 +5,8 @@ class Projects::VariablesController < Projects::ApplicationController feature_category :pipeline_authoring + urgency :low, [:show, :update] + def show respond_to do |format| format.json do diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index 5b17b75a963..04dde5ef7b2 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -30,14 +30,15 @@ class ProjectsController < Projects::ApplicationController before_action :event_filter, only: [:show, :activity] # Project Export Rate Limit - before_action :export_rate_limit, only: [:export, :download_export, :generate_new_export] + before_action :check_export_rate_limit!, only: [:export, :download_export, :generate_new_export] before_action do push_frontend_feature_flag(:lazy_load_commits, @project, default_enabled: :yaml) push_frontend_feature_flag(:refactor_blob_viewer, @project, default_enabled: :yaml) - push_frontend_feature_flag(:refactor_text_viewer, @project, default_enabled: :yaml) + push_frontend_feature_flag(:highlight_js, @project, default_enabled: :yaml) push_frontend_feature_flag(:increase_page_size_exponentially, @project, default_enabled: :yaml) push_frontend_feature_flag(:new_dir_modal, @project, default_enabled: :yaml) + push_licensed_feature(:file_locks) if @project.present? && @project.licensed_feature_available?(:file_locks) end layout :determine_layout @@ -51,7 +52,9 @@ class ProjectsController < Projects::ApplicationController feature_category :team_planning, [:preview_markdown, :new_issuable_address] feature_category :importers, [:export, :remove_export, :generate_new_export, :download_export] feature_category :code_review, [:unfoldered_environment_names] + urgency :low, [:refs] + urgency :high, [:unfoldered_environment_names] def index redirect_to(current_user ? root_path : explore_root_path) @@ -116,7 +119,10 @@ class ProjectsController < Projects::ApplicationController if @project.errors[:new_namespace].present? flash[:alert] = @project.errors[:new_namespace].first + return redirect_to edit_project_path(@project) end + + redirect_to edit_project_path(@project) end # rubocop: enable CodeReuse/ActiveRecord @@ -126,6 +132,8 @@ class ProjectsController < Projects::ApplicationController if ::Projects::UnlinkForkService.new(@project, current_user).execute flash[:notice] = _('The fork relationship has been removed.') end + + redirect_to edit_project_path(@project) end def activity @@ -452,6 +460,7 @@ class ProjectsController < Projects::ApplicationController :packages_enabled, :service_desk_enabled, :merge_commit_template, + :squash_commit_template, project_setting_attributes: project_setting_attributes ] + [project_feature_attributes: project_feature_attributes] end @@ -535,20 +544,12 @@ class ProjectsController < Projects::ApplicationController @project = @project.present(current_user: current_user) end - def export_rate_limit + def check_export_rate_limit! prefixed_action = "project_#{params[:action]}".to_sym project_scope = params[:action] == 'download_export' ? @project : nil - if rate_limiter.throttled?(prefixed_action, scope: [current_user, project_scope].compact) - rate_limiter.log_request(request, "#{prefixed_action}_request_limit".to_sym, current_user) - - render plain: _('This endpoint has been requested too many times. Try again later.'), status: :too_many_requests - end - end - - def rate_limiter - ::Gitlab::ApplicationRateLimiter + check_rate_limit!(prefixed_action, scope: [current_user, project_scope].compact) end def render_edit diff --git a/app/controllers/registrations/welcome_controller.rb b/app/controllers/registrations/welcome_controller.rb index 39d3125a4a3..41fd1b7a1e6 100644 --- a/app/controllers/registrations/welcome_controller.rb +++ b/app/controllers/registrations/welcome_controller.rb @@ -72,16 +72,10 @@ module Registrations end def show_tasks_to_be_done? - return unless experiment(:invite_members_for_task).enabled? - MemberTask.for_members(current_user.members).exists? end # overridden in EE - def trial_params - end - - # overridden in EE def update_success_path end end diff --git a/app/controllers/registrations_controller.rb b/app/controllers/registrations_controller.rb index 450c12a233b..ed3facd72c5 100644 --- a/app/controllers/registrations_controller.rb +++ b/app/controllers/registrations_controller.rb @@ -210,9 +210,6 @@ class RegistrationsController < Devise::RegistrationsController return unless member - experiment_name = session.delete(:invite_email_experiment_name) - experiment(:invite_email_preview_text, actor: member).track(:accepted) if experiment_name == 'invite_email_preview_text' - experiment(:invite_email_from, actor: member).track(:accepted) if experiment_name == 'invite_email_from' Gitlab::Tracking.event(self.class.name, 'accepted', label: 'invite_email', property: member.id.to_s) end diff --git a/app/controllers/repositories/git_http_client_controller.rb b/app/controllers/repositories/git_http_client_controller.rb index b3adda8c633..c002c9b83f9 100644 --- a/app/controllers/repositories/git_http_client_controller.rb +++ b/app/controllers/repositories/git_http_client_controller.rb @@ -8,12 +8,9 @@ module Repositories attr_reader :authentication_result, :redirected_path - delegate :actor, :authentication_abilities, to: :authentication_result, allow_nil: true + delegate :authentication_abilities, to: :authentication_result, allow_nil: true delegate :type, to: :authentication_result, allow_nil: true, prefix: :auth_result - alias_method :user, :actor - alias_method :authenticated_user, :actor - # Git clients will not know what authenticity token to send along skip_around_action :set_session_storage skip_before_action :verify_authenticity_token @@ -22,8 +19,16 @@ module Repositories feature_category :source_code_management + def authenticated_user + authentication_result&.user || authentication_result&.deploy_token + end + private + def user + authenticated_user + end + def download_request? raise NotImplementedError end diff --git a/app/controllers/repositories/lfs_api_controller.rb b/app/controllers/repositories/lfs_api_controller.rb index 30cafb6747e..d93d88c9e64 100644 --- a/app/controllers/repositories/lfs_api_controller.rb +++ b/app/controllers/repositories/lfs_api_controller.rb @@ -76,7 +76,10 @@ module Repositories existing_oids = project.lfs_objects_oids(oids: objects_oids) objects.each do |object| - object[:actions] = upload_actions(object) unless existing_oids.include?(object[:oid]) + next if existing_oids.include?(object[:oid]) + next if should_auto_link? && oids_from_fork.include?(object[:oid]) && link_to_project!(object) + + object[:actions] = upload_actions(object) end objects @@ -150,6 +153,34 @@ module Repositories Gitlab::LfsToken.new(user).basic_encoding end + + def should_auto_link? + return false unless Feature.enabled?(:lfs_auto_link_fork_source, project) + return false unless project.forked? + + # Sanity check in case for some reason the user doesn't have access to the parent + can?(user, :download_code, project.fork_source) + end + + def oids_from_fork + @oids_from_fork ||= project.lfs_objects_oids_from_fork_source(oids: objects_oids) + end + + def link_to_project!(object) + lfs_object = LfsObject.for_oid_and_size(object[:oid], object[:size]) + + return unless lfs_object + + LfsObjectsProject.link_to_project!(lfs_object, project) + + Gitlab::AppJsonLogger.info(message: "LFS object auto-linked to forked project", + lfs_object_oid: lfs_object.oid, + lfs_object_size: lfs_object.size, + source_project_id: project.fork_source.id, + source_project_path: project.fork_source.full_path, + target_project_id: project.project_id, + target_project_path: project.full_path) + end end end diff --git a/app/controllers/search_controller.rb b/app/controllers/search_controller.rb index 0e285dae089..99a6dfa811e 100644 --- a/app/controllers/search_controller.rb +++ b/app/controllers/search_controller.rb @@ -5,14 +5,13 @@ class SearchController < ApplicationController include SearchHelper include RedisTracking - RESCUE_FROM_TIMEOUT_ACTIONS = [:count, :show].freeze + RESCUE_FROM_TIMEOUT_ACTIONS = [:count, :show, :autocomplete].freeze track_redis_hll_event :show, name: 'i_search_total' around_action :allow_gitaly_ref_name_caching before_action :block_anonymous_global_searches, :check_scope_global_search_enabled, except: :opensearch - before_action :strip_surrounding_whitespace_from_search, except: :opensearch skip_before_action :authenticate_user! requires_cross_project_access if: -> do search_term_present = params[:search].present? || params[:term].present? @@ -74,11 +73,7 @@ class SearchController < ApplicationController def autocomplete term = params[:term] - if params[:project_id].present? - @project = Project.find_by(id: params[:project_id]) - @project = nil unless can?(current_user, :read_project, @project) - end - + @project = search_service.project @ref = params[:project_ref] if params[:project_ref].present? render json: search_autocomplete_opts(term).to_json @@ -97,12 +92,12 @@ class SearchController < ApplicationController def search_term_valid? unless search_service.valid_query_length? - flash[:alert] = t('errors.messages.search_chars_too_long', count: SearchService::SEARCH_CHAR_LIMIT) + flash[:alert] = t('errors.messages.search_chars_too_long', count: Gitlab::Search::Params::SEARCH_CHAR_LIMIT) return false end unless search_service.valid_terms_count? - flash[:alert] = t('errors.messages.search_terms_too_long', count: SearchService::SEARCH_TERM_LIMIT) + flash[:alert] = t('errors.messages.search_terms_too_long', count: Gitlab::Search::Params::SEARCH_TERM_LIMIT) return false end @@ -147,10 +142,15 @@ class SearchController < ApplicationController payload[:metadata]['meta.search.filters.confidential'] = params[:confidential] payload[:metadata]['meta.search.filters.state'] = params[:state] payload[:metadata]['meta.search.force_search_results'] = params[:force_search_results] + + if search_service.abuse_detected? + payload[:metadata]['abuse.confidence'] = Gitlab::Abuse.confidence(:certain) + payload[:metadata]['abuse.messages'] = search_service.abuse_messages + end end def block_anonymous_global_searches - return if params[:project_id].present? || params[:group_id].present? + return unless search_service.global_search? return if current_user return unless ::Feature.enabled?(:block_anonymous_global_searches, type: :ops) @@ -160,7 +160,7 @@ class SearchController < ApplicationController end def check_scope_global_search_enabled - return if params[:project_id].present? || params[:group_id].present? + return unless search_service.global_search? search_allowed = case params[:scope] when 'blobs' @@ -189,20 +189,15 @@ class SearchController < ApplicationController @timeout = true - if count_action_name? + case action_name.to_sym + when :count render json: {}, status: :request_timeout + when :autocomplete + render json: [], status: :request_timeout else render status: :request_timeout end end - - def count_action_name? - action_name.to_sym == :count - end - - def strip_surrounding_whitespace_from_search - %i(term search).each { |param| params[param]&.strip! } - end end SearchController.prepend_mod_with('SearchController') diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb index bbd7e5d5725..7e8e3ea8789 100644 --- a/app/controllers/sessions_controller.rb +++ b/app/controllers/sessions_controller.rb @@ -32,7 +32,7 @@ class SessionsController < Devise::SessionsController before_action :load_recaptcha before_action :set_invite_params, only: [:new] before_action do - push_frontend_feature_flag(:webauthn) + push_frontend_feature_flag(:webauthn, default_enabled: :yaml) end after_action :log_failed_login, if: :action_new_and_failed_login? @@ -84,6 +84,8 @@ class SessionsController < Devise::SessionsController end def destroy + headers['Clear-Site-Data'] = '"*"' + Gitlab::AppLogger.info("User Logout: username=#{current_user.username} ip=#{request.remote_ip}") super # hide the signed_out notice @@ -303,9 +305,9 @@ class SessionsController < Devise::SessionsController def authentication_method if user_params[:otp_attempt] AuthenticationEvent::TWO_FACTOR - elsif user_params[:device_response] && Feature.enabled?(:webauthn) + elsif user_params[:device_response] && Feature.enabled?(:webauthn, default_enabled: :yaml) AuthenticationEvent::TWO_FACTOR_WEBAUTHN - elsif user_params[:device_response] && !Feature.enabled?(:webauthn) + elsif user_params[:device_response] && !Feature.enabled?(:webauthn, default_enabled: :yaml) AuthenticationEvent::TWO_FACTOR_U2F else AuthenticationEvent::STANDARD diff --git a/app/controllers/user_callouts_controller.rb b/app/controllers/user_callouts_controller.rb deleted file mode 100644 index f52a09adf5a..00000000000 --- a/app/controllers/user_callouts_controller.rb +++ /dev/null @@ -1,29 +0,0 @@ -# frozen_string_literal: true - -class UserCalloutsController < ApplicationController - feature_category :navigation - - def create - if callout.persisted? - respond_to do |format| - format.json { head :ok } - end - else - respond_to do |format| - format.json { head :bad_request } - end - end - end - - private - - def callout - Users::DismissUserCalloutService.new( - container: nil, current_user: current_user, params: { feature_name: feature_name } - ).execute - end - - def feature_name - params.require(:feature_name) - end -end diff --git a/app/controllers/users/callouts_controller.rb b/app/controllers/users/callouts_controller.rb new file mode 100644 index 00000000000..fe308d9dd1e --- /dev/null +++ b/app/controllers/users/callouts_controller.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +module Users + class CalloutsController < ApplicationController + feature_category :navigation + + def create + if callout.persisted? + respond_to do |format| + format.json { head :ok } + end + else + respond_to do |format| + format.json { head :bad_request } + end + end + end + + private + + def callout + Users::DismissCalloutService.new( + container: nil, current_user: current_user, params: { feature_name: feature_name } + ).execute + end + + def feature_name + params.require(:feature_name) + end + end +end diff --git a/app/controllers/users/group_callouts_controller.rb b/app/controllers/users/group_callouts_controller.rb index cc27452e6a3..abca12ccea7 100644 --- a/app/controllers/users/group_callouts_controller.rb +++ b/app/controllers/users/group_callouts_controller.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module Users - class GroupCalloutsController < UserCalloutsController + class GroupCalloutsController < Users::CalloutsController private def callout diff --git a/app/controllers/users/terms_controller.rb b/app/controllers/users/terms_controller.rb index 7fbf0faa68b..f0d95b56d33 100644 --- a/app/controllers/users/terms_controller.rb +++ b/app/controllers/users/terms_controller.rb @@ -3,6 +3,7 @@ module Users class TermsController < ApplicationController include InternalRedirect + include OneTrustCSP skip_before_action :authenticate_user!, only: [:index] skip_before_action :enforce_terms! |