From d9ab72d6080f594d0b3cae15f14b3ef2c6c638cb Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Wed, 20 Oct 2021 08:43:02 +0000 Subject: Add latest changes from gitlab-org/gitlab@14-4-stable-ee --- app/controllers/admin/dashboard_controller.rb | 9 ++- .../admin/instance_review_controller.rb | 2 +- .../admin/serverless/domains_controller.rb | 78 ---------------------- app/controllers/admin/topics/avatars_controller.rb | 14 ++++ app/controllers/admin/topics_controller.rb | 57 ++++++++++++++++ app/controllers/application_controller.rb | 30 ++++++--- app/controllers/concerns/group_tree.rb | 9 ++- app/controllers/concerns/issuable_actions.rb | 6 +- app/controllers/concerns/notes_actions.rb | 2 +- app/controllers/concerns/one_trust_csp.rb | 19 ++++++ .../concerns/registry/connection_errors_handler.rb | 38 +++++++++++ app/controllers/dashboard/projects_controller.rb | 2 +- app/controllers/graphql_controller.rb | 8 +++ app/controllers/groups/boards_controller.rb | 1 + .../dependency_proxy/application_controller.rb | 32 +++------ .../dependency_proxy_for_containers_controller.rb | 46 ++++++++++++- app/controllers/groups/group_members_controller.rb | 22 ++++-- app/controllers/groups/packages_controller.rb | 4 ++ .../groups/registry/repositories_controller.rb | 1 + app/controllers/groups/runners_controller.rb | 14 ++-- .../groups/settings/ci_cd_controller.rb | 5 ++ app/controllers/health_controller.rb | 2 + app/controllers/help_controller.rb | 1 - app/controllers/import/bulk_imports_controller.rb | 24 ++----- app/controllers/import/url_controller.rb | 20 ++++++ .../jira_connect/app_descriptor_controller.rb | 1 + .../jira_connect/application_controller.rb | 4 ++ app/controllers/jira_connect/events_controller.rb | 31 +++++++-- app/controllers/metrics_controller.rb | 1 + app/controllers/profiles/passwords_controller.rb | 25 +++---- .../profiles/two_factor_auths_controller.rb | 2 - app/controllers/profiles_controller.rb | 3 +- .../projects/alerting/notifications_controller.rb | 12 ++++ app/controllers/projects/badges_controller.rb | 5 +- app/controllers/projects/blob_controller.rb | 1 + app/controllers/projects/boards_controller.rb | 1 + app/controllers/projects/branches_controller.rb | 5 ++ .../daily_build_group_report_results_controller.rb | 2 +- .../projects/ci/pipeline_editor_controller.rb | 3 +- .../projects/cluster_agents_controller.rb | 19 ++++++ .../projects/google_cloud_controller.rb | 16 +++++ app/controllers/projects/issues_controller.rb | 2 +- app/controllers/projects/jobs_controller.rb | 5 +- .../projects/merge_requests_controller.rb | 20 +++--- .../projects/packages/packages_controller.rb | 4 ++ .../projects/project_members_controller.rb | 22 ++++-- .../projects/registry/repositories_controller.rb | 3 +- .../projects/security/configuration_controller.rb | 2 +- .../projects/serverless/functions_controller.rb | 2 +- .../projects/settings/ci_cd_controller.rb | 5 ++ app/controllers/projects/tags_controller.rb | 12 ++-- app/controllers/projects/tree_controller.rb | 2 + .../projects/usage_quotas_controller.rb | 1 + app/controllers/projects_controller.rb | 15 ++++- app/controllers/registrations_controller.rb | 6 ++ .../repositories/git_http_controller.rb | 7 +- app/controllers/search_controller.rb | 6 ++ app/controllers/sessions_controller.rb | 1 + app/controllers/uploads_controller.rb | 5 +- 59 files changed, 488 insertions(+), 209 deletions(-) delete mode 100644 app/controllers/admin/serverless/domains_controller.rb create mode 100644 app/controllers/admin/topics/avatars_controller.rb create mode 100644 app/controllers/admin/topics_controller.rb create mode 100644 app/controllers/concerns/one_trust_csp.rb create mode 100644 app/controllers/concerns/registry/connection_errors_handler.rb create mode 100644 app/controllers/import/url_controller.rb create mode 100644 app/controllers/projects/cluster_agents_controller.rb create mode 100644 app/controllers/projects/google_cloud_controller.rb (limited to 'app/controllers') diff --git a/app/controllers/admin/dashboard_controller.rb b/app/controllers/admin/dashboard_controller.rb index ba24e3e619b..d12ccfc7423 100644 --- a/app/controllers/admin/dashboard_controller.rb +++ b/app/controllers/admin/dashboard_controller.rb @@ -15,7 +15,14 @@ class Admin::DashboardController < Admin::ApplicationController @groups = Group.order_id_desc.with_route.limit(10) @notices = Gitlab::ConfigChecker::PumaRuggedChecker.check @notices += Gitlab::ConfigChecker::ExternalDatabaseChecker.check - @redis_versions = [Gitlab::Redis::Queues, Gitlab::Redis::SharedState, Gitlab::Redis::Cache, Gitlab::Redis::TraceChunks].map(&:version).uniq + @redis_versions = [ + Gitlab::Redis::Queues, + Gitlab::Redis::SharedState, + Gitlab::Redis::Cache, + Gitlab::Redis::TraceChunks, + Gitlab::Redis::RateLimiting, + Gitlab::Redis::Sessions + ].map(&:version).uniq end # rubocop: enable CodeReuse/ActiveRecord diff --git a/app/controllers/admin/instance_review_controller.rb b/app/controllers/admin/instance_review_controller.rb index 88ca2c88aab..5567ffbdc84 100644 --- a/app/controllers/admin/instance_review_controller.rb +++ b/app/controllers/admin/instance_review_controller.rb @@ -3,7 +3,7 @@ class Admin::InstanceReviewController < Admin::ApplicationController feature_category :devops_reports def index - redirect_to("#{::Gitlab::SubscriptionPortal::SUBSCRIPTIONS_URL}/instance_review?#{instance_review_params}") + redirect_to("#{Gitlab::SubscriptionPortal.subscriptions_instance_review_url}?#{instance_review_params}") end def instance_review_params diff --git a/app/controllers/admin/serverless/domains_controller.rb b/app/controllers/admin/serverless/domains_controller.rb deleted file mode 100644 index 49cd9f7a36d..00000000000 --- a/app/controllers/admin/serverless/domains_controller.rb +++ /dev/null @@ -1,78 +0,0 @@ -# frozen_string_literal: true - -class Admin::Serverless::DomainsController < Admin::ApplicationController - before_action :check_feature_flag - before_action :domain, only: [:update, :verify, :destroy] - - feature_category :serverless - - def index - @domain = PagesDomain.instance_serverless.first_or_initialize - end - - def create - if PagesDomain.instance_serverless.exists? - return redirect_to admin_serverless_domains_path, notice: _('An instance-level serverless domain already exists.') - end - - @domain = PagesDomain.instance_serverless.create(create_params) - - if @domain.persisted? - redirect_to admin_serverless_domains_path, notice: _('Domain was successfully created.') - else - render 'index' - end - end - - def update - if domain.update(update_params) - redirect_to admin_serverless_domains_path, notice: _('Domain was successfully updated.') - else - render 'index' - end - end - - def destroy - if domain.serverless_domain_clusters.exists? - return redirect_to admin_serverless_domains_path, - status: :conflict, - notice: _('Domain cannot be deleted while associated to one or more clusters.') - end - - domain.destroy! - - redirect_to admin_serverless_domains_path, - status: :found, - notice: _('Domain was successfully deleted.') - end - - def verify - result = VerifyPagesDomainService.new(domain).execute - - if result[:status] == :success - flash[:notice] = _('Successfully verified domain ownership') - else - flash[:alert] = _('Failed to verify domain ownership') - end - - redirect_to admin_serverless_domains_path - end - - private - - def domain - @domain = PagesDomain.instance_serverless.find(params[:id]) - end - - def check_feature_flag - render_404 unless Feature.enabled?(:serverless_domain) - end - - def update_params - params.require(:pages_domain).permit(:user_provided_certificate, :user_provided_key) - end - - def create_params - params.require(:pages_domain).permit(:domain, :user_provided_certificate, :user_provided_key) - end -end diff --git a/app/controllers/admin/topics/avatars_controller.rb b/app/controllers/admin/topics/avatars_controller.rb new file mode 100644 index 00000000000..7acdec424b4 --- /dev/null +++ b/app/controllers/admin/topics/avatars_controller.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +class Admin::Topics::AvatarsController < Admin::ApplicationController + feature_category :projects + + def destroy + @topic = Projects::Topic.find(params[:topic_id]) + + @topic.remove_avatar! + @topic.save + + redirect_to edit_admin_topic_path(@topic), status: :found + end +end diff --git a/app/controllers/admin/topics_controller.rb b/app/controllers/admin/topics_controller.rb new file mode 100644 index 00000000000..ccc38ba7cd5 --- /dev/null +++ b/app/controllers/admin/topics_controller.rb @@ -0,0 +1,57 @@ +# frozen_string_literal: true + +class Admin::TopicsController < Admin::ApplicationController + include SendFileUpload + include PreviewMarkdown + + before_action :topic, only: [:edit, :update] + + feature_category :projects + + def index + @topics = Projects::TopicsFinder.new(params: params.permit(:search)).execute.page(params[:page]).without_count + end + + def new + @topic = Projects::Topic.new + end + + def edit + end + + def create + @topic = Projects::Topic.new(topic_params) + + if @topic.save + redirect_to edit_admin_topic_path(@topic), notice: _('Topic %{topic_name} was successfully created.') % { topic_name: @topic.name } + else + render "new" + end + end + + def update + if @topic.update(topic_params) + redirect_to edit_admin_topic_path(@topic), notice: _('Topic was successfully updated.') + else + render "edit" + end + end + + private + + def topic + @topic ||= Projects::Topic.find(params[:id]) + end + + def topic_params + params.require(:projects_topic).permit(allowed_topic_params) + end + + def allowed_topic_params + [ + :avatar, + :description, + :name + ] + end +end diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index a83458f3260..b22167a3952 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -21,7 +21,7 @@ class ApplicationController < ActionController::Base include Impersonation include Gitlab::Logging::CloudflareHelper include Gitlab::Utils::StrongMemoize - include ::Gitlab::WithFeatureCategory + include ::Gitlab::EndpointAttributes include FlocOptOut before_action :authenticate_user!, except: [:route_not_found] @@ -70,6 +70,10 @@ class ApplicationController < ActionController::Base # 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 + rescue_from Encoding::CompatibilityError do |exception| log_exception(exception) render "errors/encoding", layout: "errors", status: :internal_server_error @@ -104,6 +108,12 @@ class ApplicationController < ActionController::Base head :forbidden, retry_after: Gitlab::Auth::UniqueIpsLimiter.config.unique_ips_limit_time_window end + rescue_from RateLimitedService::RateLimitedError do |e| + e.log_request(request, current_user) + response.headers.merge!(e.headers) + render plain: e.message, status: :too_many_requests + end + def redirect_back_or_default(default: root_path, options: {}) redirect_back(fallback_location: default, **options) end @@ -131,6 +141,14 @@ class ApplicationController < ActionController::Base end end + def feature_category + self.class.feature_category_for_action(action_name).to_s + end + + def urgency + self.class.urgency_for_action(action_name) + end + protected def workhorse_excluded_content_types @@ -457,7 +475,7 @@ class ApplicationController < ActionController::Base user: -> { context_user }, project: -> { @project if @project&.persisted? }, namespace: -> { @group if @group&.persisted? }, - caller_id: caller_id, + caller_id: self.class.endpoint_id_for_action(action_name), remote_ip: request.ip, feature_category: feature_category ) @@ -543,14 +561,6 @@ class ApplicationController < ActionController::Base auth_user if strong_memoized?(:auth_user) end - def caller_id - "#{self.class.name}##{action_name}" - end - - def feature_category - self.class.feature_category_for_action(action_name).to_s - end - def required_signup_info return unless current_user return unless current_user.role_required? diff --git a/app/controllers/concerns/group_tree.rb b/app/controllers/concerns/group_tree.rb index d076c62c707..35c1f358a77 100644 --- a/app/controllers/concerns/group_tree.rb +++ b/app/controllers/concerns/group_tree.rb @@ -38,8 +38,13 @@ module GroupTree # # Pagination needs to be applied before loading the ancestors to # make sure ancestors are not cut off by pagination. - Gitlab::ObjectHierarchy.new(Group.where(id: filtered_groups.select(:id))) - .base_and_ancestors + filtered_groups_relation = Group.where(id: filtered_groups.select(:id)) + + if Feature.enabled?(:linear_group_tree_ancestor_scopes, current_user, default_enabled: :yaml) + filtered_groups_relation.self_and_ancestors + else + Gitlab::ObjectHierarchy.new(filtered_groups_relation).base_and_ancestors + end end # rubocop: enable CodeReuse/ActiveRecord end diff --git a/app/controllers/concerns/issuable_actions.rb b/app/controllers/concerns/issuable_actions.rb index 7ee680db7f9..e1e662a1968 100644 --- a/app/controllers/concerns/issuable_actions.rb +++ b/app/controllers/concerns/issuable_actions.rb @@ -158,8 +158,10 @@ module IssuableActions discussions = Discussion.build_collection(notes, issuable) - if issuable.is_a?(MergeRequest) && Feature.enabled?(:merge_request_discussion_cache, issuable.target_project, default_enabled: :yaml) - render_cached(discussions, with: discussion_serializer, context: self) + if issuable.is_a?(MergeRequest) + cache_context = [current_user&.cache_key, project.team.human_max_access(current_user&.id)].join(':') + + render_cached(discussions, with: discussion_serializer, cache_context: -> (_) { cache_context }, context: self) else render json: discussion_serializer.represent(discussions, context: self) end diff --git a/app/controllers/concerns/notes_actions.rb b/app/controllers/concerns/notes_actions.rb index 2d8168af2e3..c2ee735a2b5 100644 --- a/app/controllers/concerns/notes_actions.rb +++ b/app/controllers/concerns/notes_actions.rb @@ -62,7 +62,7 @@ module NotesActions json.merge!(note_json(@note)) end - if @note.errors.present? && @note.errors.keys != [:commands_only] + if @note.errors.present? && @note.errors.attribute_names != [:commands_only] render json: json, status: :unprocessable_entity else render json: json diff --git a/app/controllers/concerns/one_trust_csp.rb b/app/controllers/concerns/one_trust_csp.rb new file mode 100644 index 00000000000..4e98ec586ca --- /dev/null +++ b/app/controllers/concerns/one_trust_csp.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +module OneTrustCSP + extend ActiveSupport::Concern + + included do + content_security_policy do |policy| + next if policy.directives.blank? + + 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'] + 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'] + policy.connect_src(*connect_src_values) + end + end +end diff --git a/app/controllers/concerns/registry/connection_errors_handler.rb b/app/controllers/concerns/registry/connection_errors_handler.rb new file mode 100644 index 00000000000..2b24f3b5b31 --- /dev/null +++ b/app/controllers/concerns/registry/connection_errors_handler.rb @@ -0,0 +1,38 @@ +# frozen_string_literal: true + +module Registry + module ConnectionErrorsHandler + extend ActiveSupport::Concern + + included do + rescue_from ContainerRegistry::Path::InvalidRegistryPathError, with: :invalid_registry_path + rescue_from Faraday::Error, with: :connection_error + + before_action :ping_container_registry + end + + private + + # rubocop:disable Gitlab/ModuleWithInstanceVariables + # These instance variables are only read by a view helper to pass + # them to the frontend + # See app/views/projects/registry/repositories/index.html.haml + # app/views/groups/registry/repositories/index.html.haml + def invalid_registry_path + @invalid_path_error = true + + render :index + end + + def connection_error + @connection_error = true + + render :index + end + # rubocop:enable Gitlab/ModuleWithInstanceVariables + + def ping_container_registry + ContainerRegistry::Client.registry_info + end + end +end diff --git a/app/controllers/dashboard/projects_controller.rb b/app/controllers/dashboard/projects_controller.rb index 74ad78ff4c1..d861ef646f8 100644 --- a/app/controllers/dashboard/projects_controller.rb +++ b/app/controllers/dashboard/projects_controller.rb @@ -36,7 +36,7 @@ class Dashboard::ProjectsController < Dashboard::ApplicationController # rubocop: disable CodeReuse/ActiveRecord def starred @projects = load_projects(params.merge(starred: true)) - .includes(:forked_from_project, :topics, :topics_acts_as_taggable) + .includes(:forked_from_project, :topics) @groups = [] diff --git a/app/controllers/graphql_controller.rb b/app/controllers/graphql_controller.rb index 515fbd7b482..0722a712b5c 100644 --- a/app/controllers/graphql_controller.rb +++ b/app/controllers/graphql_controller.rb @@ -1,6 +1,8 @@ # frozen_string_literal: true class GraphqlController < ApplicationController + extend ::Gitlab::Utils::Override + # Unauthenticated users have access to the API for public data skip_before_action :authenticate_user! @@ -35,6 +37,7 @@ class GraphqlController < ApplicationController # callback execution order here around_action :sessionless_bypass_admin_mode!, if: :sessionless_user? + # The default feature category is overridden to read from request feature_category :not_owned def execute @@ -64,6 +67,11 @@ class GraphqlController < ApplicationController render_error(exception.message, status: :unprocessable_entity) end + override :feature_category + def feature_category + ::Gitlab::FeatureCategories.default.from_request(request) || super + end + private def disallow_mutations_for_get diff --git a/app/controllers/groups/boards_controller.rb b/app/controllers/groups/boards_controller.rb index 60708c13b85..e8e6a7e5c1a 100644 --- a/app/controllers/groups/boards_controller.rb +++ b/app/controllers/groups/boards_controller.rb @@ -11,6 +11,7 @@ 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) end feature_category :boards diff --git a/app/controllers/groups/dependency_proxy/application_controller.rb b/app/controllers/groups/dependency_proxy/application_controller.rb index fd9db41f748..18a6ff93e15 100644 --- a/app/controllers/groups/dependency_proxy/application_controller.rb +++ b/app/controllers/groups/dependency_proxy/application_controller.rb @@ -21,8 +21,14 @@ module Groups authenticate_with_http_token do |token, _| @authentication_result = EMPTY_AUTH_RESULT - found_user = user_from_token(token) - sign_in(found_user) if found_user.is_a?(User) + user_or_deploy_token = ::DependencyProxy::AuthTokenService.user_or_deploy_token_from_jwt(token) + + if user_or_deploy_token.is_a?(User) + @authentication_result = Gitlab::Auth::Result.new(user_or_deploy_token, nil, :user, []) + sign_in(user_or_deploy_token) + elsif user_or_deploy_token.is_a?(DeployToken) + @authentication_result = Gitlab::Auth::Result.new(user_or_deploy_token, nil, :deploy_token, []) + end end request_bearer_token! unless authenticated_user @@ -39,28 +45,6 @@ module Groups response.headers['WWW-Authenticate'] = ::DependencyProxy::Registry.authenticate_header render plain: '', status: :unauthorized end - - def user_from_token(token) - token_payload = ::DependencyProxy::AuthTokenService.decoded_token_payload(token) - - if token_payload['user_id'] - token_user = User.find(token_payload['user_id']) - return unless token_user - - @authentication_result = Gitlab::Auth::Result.new(token_user, nil, :user, []) - return token_user - elsif token_payload['deploy_token'] - deploy_token = DeployToken.active.find_by_token(token_payload['deploy_token']) - return unless deploy_token - - @authentication_result = Gitlab::Auth::Result.new(deploy_token, nil, :deploy_token, []) - return deploy_token - end - - nil - rescue JWT::DecodeError, JWT::ExpiredSignature, JWT::ImmatureSignature - nil - end 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 f7dc552bd3e..e19b8ae35f8 100644 --- a/app/controllers/groups/dependency_proxy_for_containers_controller.rb +++ b/app/controllers/groups/dependency_proxy_for_containers_controller.rb @@ -5,11 +5,15 @@ class Groups::DependencyProxyForContainersController < ::Groups::DependencyProxy include DependencyProxy::GroupAccess include SendFileUpload include ::PackagesHelper # for event tracking + include WorkhorseRequest before_action :ensure_group - before_action :ensure_token_granted! + before_action :ensure_token_granted!, only: [:blob, :manifest] before_action :ensure_feature_enabled! + before_action :verify_workhorse_api!, only: [:authorize_upload_blob, :upload_blob] + skip_before_action :verify_authenticity_token, only: [:authorize_upload_blob, :upload_blob] + attr_reader :token feature_category :dependency_proxy @@ -38,6 +42,8 @@ class Groups::DependencyProxyForContainersController < ::Groups::DependencyProxy end def blob + return blob_via_workhorse if Feature.enabled?(:dependency_proxy_workhorse, group, default_enabled: :yaml) + result = DependencyProxy::FindOrCreateBlobService .new(group, image, token, params[:sha]).execute @@ -50,11 +56,47 @@ class Groups::DependencyProxyForContainersController < ::Groups::DependencyProxy end end + def authorize_upload_blob + set_workhorse_internal_api_content_type + + render json: DependencyProxy::FileUploader.workhorse_authorize(has_length: false) + end + + def upload_blob + @group.dependency_proxy_blobs.create!( + file_name: blob_file_name, + file: params[:file], + size: params[:file].size + ) + + event_name = tracking_event_name(object_type: :blob, from_cache: false) + track_package_event(event_name, :dependency_proxy, namespace: group, user: auth_user) + + head :ok + end + private + def blob_via_workhorse + blob = @group.dependency_proxy_blobs.find_by_file_name(blob_file_name) + + if blob.present? + event_name = tracking_event_name(object_type: :blob, from_cache: true) + track_package_event(event_name, :dependency_proxy, namespace: group, user: auth_user) + + send_upload(blob.file) + else + send_dependency(token, DependencyProxy::Registry.blob_url(image, params[:sha]), blob_file_name) + end + end + + def blob_file_name + @blob_file_name ||= params[:sha].sub('sha256:', '') + '.gz' + end + def group strong_memoize(:group) do - Group.find_by_full_path(params[:group_id], follow_redirects: request.get?) + Group.find_by_full_path(params[:group_id], follow_redirects: true) end end diff --git a/app/controllers/groups/group_members_controller.rb b/app/controllers/groups/group_members_controller.rb index 9b8d5cfe476..6e59f159636 100644 --- a/app/controllers/groups/group_members_controller.rb +++ b/app/controllers/groups/group_members_controller.rb @@ -25,19 +25,15 @@ class Groups::GroupMembersController < Groups::ApplicationController def index @sort = params[:sort].presence || sort_value_name - @members = GroupMembersFinder - .new(@group, current_user, params: filter_params) - .execute(include_relations: requested_relations) - if can?(current_user, :admin_group_member, @group) @skip_groups = @group.related_group_ids - @invited_members = @members.invite + @invited_members = invited_members @invited_members = @invited_members.search_invite_email(params[:search_invited]) if params[:search_invited].present? @invited_members = present_invited_members(@invited_members) end - @members = present_group_members(@members.non_invite) + @members = present_group_members(non_invited_members) @requesters = present_members( AccessRequestsFinder.new(@group).execute(current_user) @@ -51,6 +47,20 @@ class Groups::GroupMembersController < Groups::ApplicationController private + def group_members + @group_members ||= GroupMembersFinder + .new(@group, current_user, params: filter_params) + .execute(include_relations: requested_relations) + end + + def invited_members + group_members.invite.with_invited_user_state + end + + def non_invited_members + group_members.non_invite + end + def present_invited_members(invited_members) present_members(invited_members .page(params[:invited_members_page]) diff --git a/app/controllers/groups/packages_controller.rb b/app/controllers/groups/packages_controller.rb index 47f1816cc4c..d02a8262948 100644 --- a/app/controllers/groups/packages_controller.rb +++ b/app/controllers/groups/packages_controller.rb @@ -6,6 +6,10 @@ module Groups feature_category :package_registry + before_action do + push_frontend_feature_flag(:package_list_apollo, default_enabled: :yaml) + end + private def verify_packages_enabled! diff --git a/app/controllers/groups/registry/repositories_controller.rb b/app/controllers/groups/registry/repositories_controller.rb index 3aaaf6ade6b..549a148bfb8 100644 --- a/app/controllers/groups/registry/repositories_controller.rb +++ b/app/controllers/groups/registry/repositories_controller.rb @@ -3,6 +3,7 @@ module Groups module Registry class RepositoriesController < Groups::ApplicationController include PackagesHelper + include ::Registry::ConnectionErrorsHandler before_action :verify_container_registry_enabled! before_action :authorize_read_container_image! diff --git a/app/controllers/groups/runners_controller.rb b/app/controllers/groups/runners_controller.rb index f37c08da22a..5c21c7b023c 100644 --- a/app/controllers/groups/runners_controller.rb +++ b/app/controllers/groups/runners_controller.rb @@ -10,8 +10,10 @@ class Groups::RunnersController < Groups::ApplicationController feature_category :runner def index - finder = Ci::RunnersFinder.new(current_user: current_user, params: { group: @group }) - @group_runners_limited_count = finder.execute.except(:limit, :offset).page.total_count_with_limit(:all, limit: 1000) + ::Gitlab::Database.allow_cross_joins_across_databases(url: 'https://gitlab.com/gitlab-org/gitlab/-/issues/336433') do + finder = Ci::RunnersFinder.new(current_user: current_user, params: { group: @group }) + @group_runners_limited_count = finder.execute.except(:limit, :offset).page.total_count_with_limit(:all, limit: 1000) + end end def runner_list_group_view_vue_ui_enabled @@ -61,9 +63,11 @@ class Groups::RunnersController < Groups::ApplicationController private def runner - @runner ||= Ci::RunnersFinder.new(current_user: current_user, params: { group: @group }).execute - .except(:limit, :offset) - .find(params[:id]) + ::Gitlab::Database.allow_cross_joins_across_databases(url: 'https://gitlab.com/gitlab-org/gitlab/-/issues/336433') do + @runner ||= Ci::RunnersFinder.new(current_user: current_user, params: { group: @group }).execute + .except(:limit, :offset) + .find(params[:id]) + end end def runner_params diff --git a/app/controllers/groups/settings/ci_cd_controller.rb b/app/controllers/groups/settings/ci_cd_controller.rb index a290ef9b5e7..e125385f841 100644 --- a/app/controllers/groups/settings/ci_cd_controller.rb +++ b/app/controllers/groups/settings/ci_cd_controller.rb @@ -23,6 +23,11 @@ module Groups @group_runners = runners_finder.execute.page(params[:page]).per(NUMBER_OF_RUNNERS_PER_PAGE) @sort = runners_finder.sort_key + + # Allow sql generated by the two relations above, @all_group_runners and @group_runners + ::Gitlab::Database.allow_cross_joins_across_databases(url: 'https://gitlab.com/gitlab-org/gitlab/-/issues/336433') do + render + end end def update diff --git a/app/controllers/health_controller.rb b/app/controllers/health_controller.rb index 99b0b775217..071378f266e 100644 --- a/app/controllers/health_controller.rb +++ b/app/controllers/health_controller.rb @@ -16,6 +16,8 @@ class HealthController < ActionController::Base Gitlab::HealthChecks::Redis::QueuesCheck, Gitlab::HealthChecks::Redis::SharedStateCheck, Gitlab::HealthChecks::Redis::TraceChunksCheck, + Gitlab::HealthChecks::Redis::RateLimitingCheck, + Gitlab::HealthChecks::Redis::SessionsCheck, Gitlab::HealthChecks::GitalyCheck ].freeze diff --git a/app/controllers/help_controller.rb b/app/controllers/help_controller.rb index a1fb74cf277..0ad7478584f 100644 --- a/app/controllers/help_controller.rb +++ b/app/controllers/help_controller.rb @@ -72,7 +72,6 @@ class HelpController < ApplicationController end def redirect_to_documentation_website? - return false unless Feature.enabled?(:help_page_documentation_redirect) return false unless Gitlab::UrlSanitizer.valid_web?(documentation_url) true diff --git a/app/controllers/import/bulk_imports_controller.rb b/app/controllers/import/bulk_imports_controller.rb index da936215ad4..bec26cb547d 100644 --- a/app/controllers/import/bulk_imports_controller.rb +++ b/app/controllers/import/bulk_imports_controller.rb @@ -22,13 +22,16 @@ class Import::BulkImportsController < ApplicationController def status respond_to do |format| format.json do - data = importable_data + data = ::BulkImports::GetImportableDataService.new(params, query_params, credentials).execute pagination_headers.each do |header| - response.set_header(header, data.headers[header]) + response.set_header(header, data[:response].headers[header]) end - render json: { importable_data: serialized_data(data.parsed_response) } + json_response = { importable_data: serialized_data(data[:response].parsed_response) } + json_response[:version_validation] = data[:version_validation] + + render json: json_response end format.html do @source_url = session[url_key] @@ -37,7 +40,7 @@ class Import::BulkImportsController < ApplicationController end def create - response = BulkImportService.new(current_user, create_params, credentials).execute + response = ::BulkImports::CreateService.new(current_user, create_params, credentials).execute if response.success? render json: response.payload.to_json(only: [:id]) @@ -66,10 +69,6 @@ class Import::BulkImportsController < ApplicationController @serializer ||= BaseSerializer.new(current_user: current_user) end - def importable_data - client.get('groups', query_params) - end - # Default query string params used to fetch groups from GitLab source instance # # top_level_only: fetch only top level groups (subgroups are fetched during import itself) @@ -85,15 +84,6 @@ class Import::BulkImportsController < ApplicationController query_params end - def client - @client ||= BulkImports::Clients::HTTP.new( - url: session[url_key], - token: session[access_token_key], - per_page: params[:per_page], - page: params[:page] - ) - end - def configure_params params.permit(access_token_key, url_key) end diff --git a/app/controllers/import/url_controller.rb b/app/controllers/import/url_controller.rb new file mode 100644 index 00000000000..4e4b6ad125e --- /dev/null +++ b/app/controllers/import/url_controller.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +class Import::UrlController < ApplicationController + feature_category :importers + + def validate + result = Import::ValidateRemoteGitEndpointService.new(validate_params).execute + if result.success? + render json: { success: true } + else + render json: { success: false, message: result.message } + end + end + + private + + def validate_params + params.permit(:user, :password, :url) + end +end diff --git a/app/controllers/jira_connect/app_descriptor_controller.rb b/app/controllers/jira_connect/app_descriptor_controller.rb index 74fac6ff9bb..e96242c7052 100644 --- a/app/controllers/jira_connect/app_descriptor_controller.rb +++ b/app/controllers/jira_connect/app_descriptor_controller.rb @@ -32,6 +32,7 @@ class JiraConnect::AppDescriptorController < JiraConnect::ApplicationController apiVersion: 1, apiMigrations: { 'context-qsh': true, + 'signed-install': signed_install_active?, gdpr: true } } diff --git a/app/controllers/jira_connect/application_controller.rb b/app/controllers/jira_connect/application_controller.rb index 352e78d6255..ecb23c326fe 100644 --- a/app/controllers/jira_connect/application_controller.rb +++ b/app/controllers/jira_connect/application_controller.rb @@ -74,4 +74,8 @@ class JiraConnect::ApplicationController < ApplicationController params[:jwt] || request.headers['Authorization']&.split(' ', 2)&.last end end + + def signed_install_active? + Feature.enabled?(:jira_connect_asymmetric_jwt) + end end diff --git a/app/controllers/jira_connect/events_controller.rb b/app/controllers/jira_connect/events_controller.rb index fe66e742c44..76ac15f7631 100644 --- a/app/controllers/jira_connect/events_controller.rb +++ b/app/controllers/jira_connect/events_controller.rb @@ -3,13 +3,18 @@ class JiraConnect::EventsController < JiraConnect::ApplicationController # See https://developer.atlassian.com/cloud/jira/software/app-descriptor/#lifecycle - skip_before_action :verify_atlassian_jwt!, only: :installed - before_action :verify_qsh_claim!, only: :uninstalled + skip_before_action :verify_atlassian_jwt! + before_action :verify_asymmetric_atlassian_jwt!, if: :signed_install_active? + + before_action :verify_atlassian_jwt!, only: :uninstalled, unless: :signed_install_active? + before_action :verify_qsh_claim!, only: :uninstalled, unless: :signed_install_active? def installed - return head :ok if atlassian_jwt_valid? + return head :ok if !signed_install_active? && atlassian_jwt_valid? + + return head :ok if current_jira_installation - installation = JiraConnectInstallation.new(install_params) + installation = JiraConnectInstallation.new(event_params) if installation.save head :ok @@ -28,7 +33,23 @@ class JiraConnect::EventsController < JiraConnect::ApplicationController private - def install_params + def event_params params.permit(:clientKey, :sharedSecret, :baseUrl).transform_keys(&:underscore) end + + def verify_asymmetric_atlassian_jwt! + asymmetric_jwt = Atlassian::JiraConnect::AsymmetricJwt.new(auth_token, jwt_verification_claims) + + return head :unauthorized unless asymmetric_jwt.valid? + + @current_jira_installation = JiraConnectInstallation.find_by_client_key(asymmetric_jwt.iss_claim) + end + + def jwt_verification_claims + { + aud: jira_connect_base_url(protocol: 'https'), + iss: event_params[:client_key], + qsh: Atlassian::Jwt.create_query_string_hash(request.url, request.method, jira_connect_base_url) + } + end end diff --git a/app/controllers/metrics_controller.rb b/app/controllers/metrics_controller.rb index a0c307a0a03..d3dea2ce159 100644 --- a/app/controllers/metrics_controller.rb +++ b/app/controllers/metrics_controller.rb @@ -7,6 +7,7 @@ class MetricsController < ActionController::Base def index response = if Gitlab::Metrics.prometheus_metrics_enabled? + Gitlab::Metrics::RailsSlis.initialize_request_slis_if_needed! metrics_service.metrics_text else help_page = help_page_url('administration/monitoring/prometheus/gitlab_metrics', diff --git a/app/controllers/profiles/passwords_controller.rb b/app/controllers/profiles/passwords_controller.rb index c8c2dd1c7d6..5eb0f80ddc9 100644 --- a/app/controllers/profiles/passwords_controller.rb +++ b/app/controllers/profiles/passwords_controller.rb @@ -15,17 +15,11 @@ class Profiles::PasswordsController < Profiles::ApplicationController end def create - unless @user.password_automatically_set || @user.valid_password?(user_params[:current_password]) + unless @user.password_automatically_set || @user.valid_password?(user_params[:password]) redirect_to new_profile_password_path, alert: _('You must provide a valid current password') return end - password_attributes = { - password: user_params[:password], - password_confirmation: user_params[:password_confirmation], - password_automatically_set: false - } - result = Users::UpdateService.new(current_user, password_attributes.merge(user: @user)).execute if result[:status] == :success @@ -41,12 +35,7 @@ class Profiles::PasswordsController < Profiles::ApplicationController end def update - password_attributes = user_params.select do |key, value| - %w(password password_confirmation).include?(key.to_s) - end - password_attributes[:password_automatically_set] = false - - unless @user.password_automatically_set || @user.valid_password?(user_params[:current_password]) + unless @user.password_automatically_set || @user.valid_password?(user_params[:password]) handle_invalid_current_password_attempt! redirect_to edit_profile_password_path, alert: _('You must provide a valid current password') @@ -94,6 +83,14 @@ class Profiles::PasswordsController < Profiles::ApplicationController end def user_params - params.require(:user).permit(:current_password, :password, :password_confirmation) + params.require(:user).permit(:password, :new_password, :password_confirmation) + end + + def password_attributes + { + password: user_params[:new_password], + password_confirmation: user_params[:password_confirmation], + password_automatically_set: false + } end end diff --git a/app/controllers/profiles/two_factor_auths_controller.rb b/app/controllers/profiles/two_factor_auths_controller.rb index de22a0e47d5..e0b5d6be155 100644 --- a/app/controllers/profiles/two_factor_auths_controller.rb +++ b/app/controllers/profiles/two_factor_auths_controller.rb @@ -237,8 +237,6 @@ class Profiles::TwoFactorAuthsController < Profiles::ApplicationController end def ensure_verified_primary_email - return unless Feature.enabled?(:ensure_verified_primary_email_for_2fa, default_enabled: :yaml) - unless current_user.two_factor_enabled? || current_user.primary_email_verified? redirect_to profile_emails_path, notice: s_('You need to verify your primary email first before enabling Two-Factor Authentication.') end diff --git a/app/controllers/profiles_controller.rb b/app/controllers/profiles_controller.rb index 29ae268ef67..69257081cc9 100644 --- a/app/controllers/profiles_controller.rb +++ b/app/controllers/profiles_controller.rb @@ -18,7 +18,7 @@ class ProfilesController < Profiles::ApplicationController def update respond_to do |format| - result = Users::UpdateService.new(current_user, user_params.merge(user: @user)).execute + result = Users::UpdateService.new(current_user, user_params.merge(user: @user)).execute(check_password: true) if result[:status] == :success message = s_("Profiles|Profile was successfully updated") @@ -129,6 +129,7 @@ class ProfilesController < Profiles::ApplicationController :job_title, :pronouns, :pronunciation, + :validation_password, status: [:emoji, :message, :availability] ] end diff --git a/app/controllers/projects/alerting/notifications_controller.rb b/app/controllers/projects/alerting/notifications_controller.rb index db5d91308db..95b403faf55 100644 --- a/app/controllers/projects/alerting/notifications_controller.rb +++ b/app/controllers/projects/alerting/notifications_controller.rb @@ -3,6 +3,8 @@ module Projects module Alerting class NotificationsController < Projects::ApplicationController + include ActionController::HttpAuthentication::Basic + respond_to :json skip_before_action :verify_authenticity_token @@ -27,9 +29,19 @@ module Projects end def extract_alert_manager_token(request) + extract_bearer_token(request) || extract_basic_auth_token(request) + end + + def extract_bearer_token(request) Doorkeeper::OAuth::Token.from_bearer_authorization(request) end + def extract_basic_auth_token(request) + _username, token = user_name_and_password(request) + + token + end + def notify_service notify_service_class.new(project, notification_payload) end diff --git a/app/controllers/projects/badges_controller.rb b/app/controllers/projects/badges_controller.rb index f75ab5cdbf2..0cd59c136e5 100644 --- a/app/controllers/projects/badges_controller.rb +++ b/app/controllers/projects/badges_controller.rb @@ -24,7 +24,10 @@ class Projects::BadgesController < Projects::ApplicationController .new(project, params[:ref], opts: { job: params[:job], key_text: params[:key_text], - key_width: params[:key_width] + key_width: params[:key_width], + min_good: params[:min_good], + min_acceptable: params[:min_acceptable], + min_medium: params[:min_medium] }) render_badge coverage_report diff --git a/app/controllers/projects/blob_controller.rb b/app/controllers/projects/blob_controller.rb index acf6b6116b8..17fd28ee06a 100644 --- a/app/controllers/projects/blob_controller.rb +++ b/app/controllers/projects/blob_controller.rb @@ -43,6 +43,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(:consolidated_edit_button, @project, default_enabled: :yaml) push_licensed_feature(:file_locks) if @project.licensed_feature_available?(:file_locks) end diff --git a/app/controllers/projects/boards_controller.rb b/app/controllers/projects/boards_controller.rb index 316582f3994..834e4baa7dd 100644 --- a/app/controllers/projects/boards_controller.rb +++ b/app/controllers/projects/boards_controller.rb @@ -11,6 +11,7 @@ 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) end feature_category :boards diff --git a/app/controllers/projects/branches_controller.rb b/app/controllers/projects/branches_controller.rb index 3be10559e80..b75effc52d1 100644 --- a/app/controllers/projects/branches_controller.rb +++ b/app/controllers/projects/branches_controller.rb @@ -33,6 +33,11 @@ class Projects::BranchesController < Projects::ApplicationController Gitlab::GitalyClient.allow_n_plus_1_calls do render end + rescue Gitlab::Git::CommandError => e + Gitlab::ErrorTracking.track_exception(e) + + @gitaly_unavailable = true + render end format.json do branches = BranchesFinder.new(@repository, params).execute diff --git a/app/controllers/projects/ci/daily_build_group_report_results_controller.rb b/app/controllers/projects/ci/daily_build_group_report_results_controller.rb index fee216da492..b2b5e096105 100644 --- a/app/controllers/projects/ci/daily_build_group_report_results_controller.rb +++ b/app/controllers/projects/ci/daily_build_group_report_results_controller.rb @@ -4,7 +4,7 @@ class Projects::Ci::DailyBuildGroupReportResultsController < Projects::Applicati before_action :authorize_read_build_report_results! before_action :validate_param_type! - feature_category :continuous_integration + feature_category :code_testing def index respond_to do |format| diff --git a/app/controllers/projects/ci/pipeline_editor_controller.rb b/app/controllers/projects/ci/pipeline_editor_controller.rb index 550877548e1..22cd247644d 100644 --- a/app/controllers/projects/ci/pipeline_editor_controller.rb +++ b/app/controllers/projects/ci/pipeline_editor_controller.rb @@ -3,8 +3,7 @@ class Projects::Ci::PipelineEditorController < Projects::ApplicationController before_action :check_can_collaborate! before_action do - push_frontend_feature_flag(:pipeline_editor_empty_state_action, @project, default_enabled: :yaml) - push_frontend_feature_flag(:pipeline_editor_drawer, @project, default_enabled: :yaml) + push_frontend_feature_flag(:pipeline_editor_mini_graph, @project, default_enabled: :yaml) push_frontend_feature_flag(:schema_linting, @project, default_enabled: :yaml) end diff --git a/app/controllers/projects/cluster_agents_controller.rb b/app/controllers/projects/cluster_agents_controller.rb new file mode 100644 index 00000000000..e7fbe93131d --- /dev/null +++ b/app/controllers/projects/cluster_agents_controller.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +class Projects::ClusterAgentsController < Projects::ApplicationController + before_action :authorize_can_read_cluster_agent! + + feature_category :kubernetes_management + + def show + @agent_name = params[:name] + end + + private + + def authorize_can_read_cluster_agent! + return if can?(current_user, :admin_cluster, project) + + access_denied! + end +end diff --git a/app/controllers/projects/google_cloud_controller.rb b/app/controllers/projects/google_cloud_controller.rb new file mode 100644 index 00000000000..d185457aeb3 --- /dev/null +++ b/app/controllers/projects/google_cloud_controller.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +class Projects::GoogleCloudController < Projects::ApplicationController + before_action :authorize_can_manage_google_cloud_deployments! + + feature_category :release_orchestration + + def index + end + + private + + def authorize_can_manage_google_cloud_deployments! + access_denied! unless can?(current_user, :manage_project_google_cloud, project) + end +end diff --git a/app/controllers/projects/issues_controller.rb b/app/controllers/projects/issues_controller.rb index f885ff9b45b..fd508d5f127 100644 --- a/app/controllers/projects/issues_controller.rb +++ b/app/controllers/projects/issues_controller.rb @@ -37,7 +37,7 @@ 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] + before_action :create_rate_limit, only: [:create], if: -> { Feature.disabled?('rate_limited_service_issues_create', project, default_enabled: :yaml) } before_action do push_frontend_feature_flag(:tribute_autocomplete, @project) diff --git a/app/controllers/projects/jobs_controller.rb b/app/controllers/projects/jobs_controller.rb index 778623a05c6..994be5c2b5c 100644 --- a/app/controllers/projects/jobs_controller.rb +++ b/app/controllers/projects/jobs_controller.rb @@ -44,7 +44,7 @@ class Projects::JobsController < Projects::ApplicationController render json: BuildSerializer .new(project: @project, current_user: @current_user) - .represent(@build, {}, BuildDetailsEntity) + .represent(@build.present(current_user: current_user), {}, BuildDetailsEntity) end end end @@ -120,7 +120,7 @@ class Projects::JobsController < Projects::ApplicationController def status render json: BuildSerializer .new(project: @project, current_user: @current_user) - .represent_status(@build) + .represent_status(@build.present(current_user: current_user)) end def erase @@ -225,7 +225,6 @@ class Projects::JobsController < Projects::ApplicationController def find_job_as_build @build = project.builds.find(params[:id]) - .present(current_user: current_user) end def find_job_as_processable diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb index cb68aaf4583..46df514abcb 100644 --- a/app/controllers/projects/merge_requests_controller.rb +++ b/app/controllers/projects/merge_requests_controller.rb @@ -37,10 +37,10 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo push_frontend_feature_flag(:core_security_mr_widget_counts, @project) push_frontend_feature_flag(:paginated_notes, @project, default_enabled: :yaml) push_frontend_feature_flag(:confidential_notes, @project, default_enabled: :yaml) - push_frontend_feature_flag(:usage_data_i_testing_summary_widget_total, @project, default_enabled: :yaml) push_frontend_feature_flag(:improved_emoji_picker, project, default_enabled: :yaml) push_frontend_feature_flag(:diffs_virtual_scrolling, project, default_enabled: :yaml) push_frontend_feature_flag(:restructured_mr_widget, project, default_enabled: :yaml) + push_frontend_feature_flag(:mr_changes_fluid_layout, project, default_enabled: :yaml) # Usage data feature flags push_frontend_feature_flag(:users_expanding_widgets_usage_data, @project, default_enabled: :yaml) @@ -192,15 +192,17 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo Gitlab::PollingInterval.set_header(response, interval: 10_000) - render json: { - pipelines: PipelineSerializer - .new(project: @project, current_user: @current_user) - .with_pagination(request, response) - .represent(@pipelines), - count: { - all: @pipelines.count + ::Gitlab::Database.allow_cross_joins_across_databases(url: 'https://gitlab.com/gitlab-org/gitlab/-/issues/336891') do + render json: { + pipelines: PipelineSerializer + .new(project: @project, current_user: @current_user) + .with_pagination(request, response) + .represent(@pipelines), + count: { + all: @pipelines.count + } } - } + end end def sast_reports diff --git a/app/controllers/projects/packages/packages_controller.rb b/app/controllers/projects/packages/packages_controller.rb index 5de71466c10..dd7c2ad3cbd 100644 --- a/app/controllers/projects/packages/packages_controller.rb +++ b/app/controllers/projects/packages/packages_controller.rb @@ -7,6 +7,10 @@ module Projects feature_category :package_registry + before_action do + push_frontend_feature_flag(:package_list_apollo, default_enabled: :yaml) + end + def show @package = project.packages.find(params[:id]) end diff --git a/app/controllers/projects/project_members_controller.rb b/app/controllers/projects/project_members_controller.rb index b979276437c..e8074f7d793 100644 --- a/app/controllers/projects/project_members_controller.rb +++ b/app/controllers/projects/project_members_controller.rb @@ -19,16 +19,12 @@ class Projects::ProjectMembersController < Projects::ApplicationController @group_links = @project.project_group_links @group_links = @group_links.search(params[:search_groups]) if params[:search_groups].present? - project_members = MembersFinder - .new(@project, current_user, params: filter_params) - .execute(include_relations: requested_relations) - if can?(current_user, :admin_project_member, @project) - @invited_members = present_members(project_members.invite) + @invited_members = present_members(invited_members) @requesters = present_members(AccessRequestsFinder.new(@project).execute(current_user)) end - @project_members = present_members(project_members.non_invite.page(params[:page])) + @project_members = present_members(non_invited_members.page(params[:page])) @project_member = @project.project_members.new end @@ -55,6 +51,20 @@ class Projects::ProjectMembersController < Projects::ApplicationController private + def members + @members ||= MembersFinder + .new(@project, current_user, params: filter_params) + .execute(include_relations: requested_relations) + end + + def invited_members + members.invite.with_invited_user_state + end + + def non_invited_members + members.non_invite + end + def filter_params params.permit(:search).merge(sort: @sort) end diff --git a/app/controllers/projects/registry/repositories_controller.rb b/app/controllers/projects/registry/repositories_controller.rb index 8acebd89033..ad3b2bc98e7 100644 --- a/app/controllers/projects/registry/repositories_controller.rb +++ b/app/controllers/projects/registry/repositories_controller.rb @@ -4,6 +4,7 @@ module Projects module Registry class RepositoriesController < ::Projects::Registry::ApplicationController include PackagesHelper + include ::Registry::ConnectionErrorsHandler before_action :authorize_update_container_image!, only: [:destroy] @@ -48,8 +49,6 @@ module Projects repository.save! if repository.has_tags? end end - rescue ContainerRegistry::Path::InvalidRegistryPathError - @character_error = true end end end diff --git a/app/controllers/projects/security/configuration_controller.rb b/app/controllers/projects/security/configuration_controller.rb index 19de157357a..444f4783a19 100644 --- a/app/controllers/projects/security/configuration_controller.rb +++ b/app/controllers/projects/security/configuration_controller.rb @@ -5,7 +5,7 @@ module Projects class ConfigurationController < Projects::ApplicationController include SecurityAndCompliancePermissions - feature_category :static_application_security_testing + feature_category :static_application_security_testing, [:show] def show render_403 unless can?(current_user, :read_security_configuration, project) diff --git a/app/controllers/projects/serverless/functions_controller.rb b/app/controllers/projects/serverless/functions_controller.rb index 4168880001c..3fc379a135a 100644 --- a/app/controllers/projects/serverless/functions_controller.rb +++ b/app/controllers/projects/serverless/functions_controller.rb @@ -5,7 +5,7 @@ module Projects class FunctionsController < Projects::ApplicationController before_action :authorize_read_cluster! - feature_category :serverless + feature_category :not_owned def index respond_to do |format| diff --git a/app/controllers/projects/settings/ci_cd_controller.rb b/app/controllers/projects/settings/ci_cd_controller.rb index 960c0beb244..3033dac8246 100644 --- a/app/controllers/projects/settings/ci_cd_controller.rb +++ b/app/controllers/projects/settings/ci_cd_controller.rb @@ -25,6 +25,11 @@ module Projects @project.triggers, current_user: current_user, project: @project ).to_json end + + # @assignable_runners is using ci_owned_runners + ::Gitlab::Database.allow_cross_joins_across_databases(url: 'https://gitlab.com/gitlab-org/gitlab/-/issues/336436') do + render + end end def update diff --git a/app/controllers/projects/tags_controller.rb b/app/controllers/projects/tags_controller.rb index 94b0473e1f3..02d36c3353d 100644 --- a/app/controllers/projects/tags_controller.rb +++ b/app/controllers/projects/tags_controller.rb @@ -18,17 +18,21 @@ class Projects::TagsController < Projects::ApplicationController params[:sort] = params[:sort].presence || sort_value_recently_updated @sort = params[:sort] - @tags = TagsFinder.new(@repository, params).execute - @tags = Kaminari.paginate_array(@tags).page(params[:page]) + @tags, @tags_loading_error = TagsFinder.new(@repository, params).execute + + @tags = Kaminari.paginate_array(@tags).page(params[:page]) tag_names = @tags.map(&:name) @tags_pipelines = @project.ci_pipelines.latest_successful_for_refs(tag_names) + @releases = project.releases.where(tag: tag_names) @tag_pipeline_statuses = Ci::CommitStatusesFinder.new(@project, @repository, current_user, @tags).execute respond_to do |format| - format.html - format.atom { render layout: 'xml.atom' } + status = @tags_loading_error ? :service_unavailable : :ok + + format.html { render status: status } + format.atom { render layout: 'xml.atom', status: status } end end # rubocop: enable CodeReuse/ActiveRecord diff --git a/app/controllers/projects/tree_controller.rb b/app/controllers/projects/tree_controller.rb index 6fd4c632dd3..a76d45411dd 100644 --- a/app/controllers/projects/tree_controller.rb +++ b/app/controllers/projects/tree_controller.rb @@ -16,7 +16,9 @@ class Projects::TreeController < Projects::ApplicationController before_action :authorize_edit_tree!, only: [:create_dir] before_action do + push_frontend_feature_flag(:lazy_load_commits, @project, default_enabled: :yaml) push_frontend_feature_flag(:paginated_tree_graphql_query, @project, default_enabled: :yaml) + push_frontend_feature_flag(:new_dir_modal, @project, default_enabled: :yaml) end feature_category :source_code_management diff --git a/app/controllers/projects/usage_quotas_controller.rb b/app/controllers/projects/usage_quotas_controller.rb index 179c7fc8db1..103e1cc596a 100644 --- a/app/controllers/projects/usage_quotas_controller.rb +++ b/app/controllers/projects/usage_quotas_controller.rb @@ -9,6 +9,7 @@ class Projects::UsageQuotasController < Projects::ApplicationController feature_category :utilization 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'), diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index de4e51a3a2f..26da0436dd8 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -33,9 +33,12 @@ class ProjectsController < Projects::ApplicationController before_action :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(:increase_page_size_exponentially, @project, default_enabled: :yaml) push_frontend_feature_flag(:paginated_tree_graphql_query, @project, default_enabled: :yaml) + push_frontend_feature_flag(:new_dir_modal, @project, default_enabled: :yaml) end layout :determine_layout @@ -72,6 +75,13 @@ class ProjectsController < Projects::ApplicationController @project = ::Projects::CreateService.new(current_user, project_params(attributes: project_params_create_attributes)).execute if @project.saved? + experiment(:new_project_sast_enabled, user: current_user).track(:created, + property: active_new_project_tab, + checked: Gitlab::Utils.to_boolean(project_params[:initialize_with_sast]), + project: @project, + namespace: @project.namespace + ) + redirect_to( project_path(@project, custom_import_params), notice: _("Project '%{project_name}' was successfully created.") % { project_name: @project.name } @@ -283,9 +293,9 @@ class ProjectsController < Projects::ApplicationController end if find_tags && @repository.tag_count.nonzero? - tags = TagsFinder.new(@repository, params).execute.take(100).map(&:name) + tags, _ = TagsFinder.new(@repository, params).execute - options['Tags'] = tags + options['Tags'] = tags.take(100).map(&:name) end # If reference is commit id - we should add it to branch/tag selectbox @@ -435,6 +445,7 @@ class ProjectsController < Projects::ApplicationController :template_name, :template_project_id, :merge_method, + :initialize_with_sast, :initialize_with_readme, :autoclose_referenced_issues, :suggestion_commit_message, diff --git a/app/controllers/registrations_controller.rb b/app/controllers/registrations_controller.rb index fe800de5dd8..450c12a233b 100644 --- a/app/controllers/registrations_controller.rb +++ b/app/controllers/registrations_controller.rb @@ -5,6 +5,7 @@ class RegistrationsController < Devise::RegistrationsController include AcceptsPendingInvitations include RecaptchaHelper include InvisibleCaptchaOnSignup + include OneTrustCSP layout 'devise' @@ -45,6 +46,11 @@ class RegistrationsController < Devise::RegistrationsController end def destroy + if current_user.required_terms_not_accepted? + redirect_to profile_account_path, status: :see_other, alert: s_('Profiles|You must accept the Terms of Service in order to perform this action.') + return + end + if destroy_confirmation_valid? current_user.delete_async(deleted_by: current_user) session.try(:destroy) diff --git a/app/controllers/repositories/git_http_controller.rb b/app/controllers/repositories/git_http_controller.rb index e51bfe6a37e..c3c6a51239d 100644 --- a/app/controllers/repositories/git_http_controller.rb +++ b/app/controllers/repositories/git_http_controller.rb @@ -11,6 +11,9 @@ module Repositories rescue_from Gitlab::GitAccess::NotFoundError, with: :render_404_with_exception rescue_from Gitlab::GitAccessProject::CreationError, with: :render_422_with_exception rescue_from Gitlab::GitAccess::TimeoutError, with: :render_503_with_exception + rescue_from GRPC::Unavailable do |e| + render_503_with_exception(e, message: 'The git server, Gitaly, is not available at this time. Please contact your administrator.') + end # GET /foo/bar.git/info/refs?service=git-upload-pack (git pull) # GET /foo/bar.git/info/refs?service=git-receive-pack (git push) @@ -71,8 +74,8 @@ module Repositories render plain: exception.message, status: :unprocessable_entity end - def render_503_with_exception(exception) - render plain: exception.message, status: :service_unavailable + def render_503_with_exception(exception, message: nil) + render plain: message || exception.message, status: :service_unavailable end def update_fetch_statistics diff --git a/app/controllers/search_controller.rb b/app/controllers/search_controller.rb index 5f1b3750e41..0a18559fc81 100644 --- a/app/controllers/search_controller.rb +++ b/app/controllers/search_controller.rb @@ -12,6 +12,7 @@ class SearchController < ApplicationController 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? @@ -23,6 +24,7 @@ class SearchController < ApplicationController layout 'search' feature_category :global_search + urgency :high, [:opensearch] def show @project = search_service.project @@ -196,6 +198,10 @@ class SearchController < ApplicationController 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 4fcf82c605b..bbd7e5d5725 100644 --- a/app/controllers/sessions_controller.rb +++ b/app/controllers/sessions_controller.rb @@ -9,6 +9,7 @@ class SessionsController < Devise::SessionsController include RendersLdapServers include KnownSignIn include Gitlab::Utils::StrongMemoize + include OneTrustCSP skip_before_action :check_two_factor_requirement, only: [:destroy] skip_before_action :check_password_expiration, only: [:destroy] diff --git a/app/controllers/uploads_controller.rb b/app/controllers/uploads_controller.rb index d040ac7f76c..d7eb3ccd274 100644 --- a/app/controllers/uploads_controller.rb +++ b/app/controllers/uploads_controller.rb @@ -13,6 +13,7 @@ class UploadsController < ApplicationController "group" => Group, "appearance" => Appearance, "personal_snippet" => PersonalSnippet, + "projects/topic" => Projects::Topic, nil => PersonalSnippet }.freeze @@ -54,6 +55,8 @@ class UploadsController < ApplicationController !secret? || can?(current_user, :update_user, model) when Appearance true + when Projects::Topic + true else permission = "read_#{model.class.underscore}".to_sym @@ -85,7 +88,7 @@ class UploadsController < ApplicationController def cache_settings case model - when User, Appearance + when User, Appearance, Projects::Topic [5.minutes, { public: true, must_revalidate: false }] when Project, Group [5.minutes, { private: true, must_revalidate: true }] -- cgit v1.2.3