diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2022-07-20 15:40:28 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2022-07-20 15:40:28 +0000 |
commit | b595cb0c1dec83de5bdee18284abe86614bed33b (patch) | |
tree | 8c3d4540f193c5ff98019352f554e921b3a41a72 /app/controllers | |
parent | 2f9104a328fc8a4bddeaa4627b595166d24671d0 (diff) | |
download | gitlab-ce-b595cb0c1dec83de5bdee18284abe86614bed33b.tar.gz |
Add latest changes from gitlab-org/gitlab@15-2-stable-eev15.2.0-rc42
Diffstat (limited to 'app/controllers')
79 files changed, 887 insertions, 449 deletions
diff --git a/app/controllers/admin/application_settings_controller.rb b/app/controllers/admin/application_settings_controller.rb index 7f95b136e4e..e05e87ffd89 100644 --- a/app/controllers/admin/application_settings_controller.rb +++ b/app/controllers/admin/application_settings_controller.rb @@ -28,7 +28,8 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController :create_self_monitoring_project, :status_create_self_monitoring_project, :delete_self_monitoring_project, - :status_delete_self_monitoring_project + :status_delete_self_monitoring_project, + :reset_error_tracking_access_token ] feature_category :source_code_management, [:repository, :clear_repository_check_states] @@ -37,6 +38,7 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController feature_category :service_ping, [:usage_data, :service_usage_data] feature_category :integrations, [:integrations] feature_category :pages, [:lets_encrypt_terms_of_service] + feature_category :error_tracking, [:reset_error_tracking_access_token] VALID_SETTING_PANELS = %w(general repository ci_cd reporting metrics_and_profiling @@ -96,6 +98,13 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController redirect_back_or_default end + def reset_error_tracking_access_token + @application_setting.reset_error_tracking_access_token! + + redirect_to general_admin_application_settings_path, + notice: _('New error tracking access token has been generated!') + end + def clear_repository_check_states RepositoryCheck::ClearWorker.perform_async # rubocop:disable CodeReuse/Worker diff --git a/app/controllers/admin/broadcast_messages_controller.rb b/app/controllers/admin/broadcast_messages_controller.rb index 865af244773..bf573d45852 100644 --- a/app/controllers/admin/broadcast_messages_controller.rb +++ b/app/controllers/admin/broadcast_messages_controller.rb @@ -5,7 +5,7 @@ class Admin::BroadcastMessagesController < Admin::ApplicationController before_action :finder, only: [:edit, :update, :destroy] - feature_category :navigation + feature_category :onboarding urgency :low # rubocop: disable CodeReuse/ActiveRecord diff --git a/app/controllers/admin/hooks_controller.rb b/app/controllers/admin/hooks_controller.rb index 6f5475a4a78..810801d4209 100644 --- a/app/controllers/admin/hooks_controller.rb +++ b/app/controllers/admin/hooks_controller.rb @@ -8,40 +8,6 @@ class Admin::HooksController < Admin::ApplicationController feature_category :integrations urgency :low, [:test] - def index - @hooks = SystemHook.all.load - @hook = SystemHook.new - end - - def create - @hook = SystemHook.new(hook_params.to_h) - - if @hook.save - redirect_to admin_hooks_path, notice: _('Hook was successfully created.') - else - @hooks = SystemHook.all - render :index - end - end - - def edit - end - - def update - if hook.update(hook_params) - flash[:notice] = _('System hook was successfully updated.') - redirect_to admin_hooks_path - else - render 'edit' - end - end - - def destroy - destroy_hook(hook) - - redirect_to admin_hooks_path, status: :found - end - def test result = TestHooks::SystemService.new(hook, current_user, params[:trigger]).execute @@ -52,6 +18,10 @@ class Admin::HooksController < Admin::ApplicationController private + def relation + SystemHook + end + def hook @hook ||= SystemHook.find(params[:id]) end @@ -60,12 +30,11 @@ class Admin::HooksController < Admin::ApplicationController @hook_logs ||= hook.web_hook_logs.recent.page(params[:page]) end - def hook_params - params.require(:hook).permit( - :enable_ssl_verification, - :token, - :url, - *SystemHook.triggers.values - ) + def hook_param_names + %i[enable_ssl_verification token url] + end + + def trigger_values + SystemHook.triggers.values end end diff --git a/app/controllers/admin/system_info_controller.rb b/app/controllers/admin/system_info_controller.rb index 7ae930abb84..f81b02ad31f 100644 --- a/app/controllers/admin/system_info_controller.rb +++ b/app/controllers/admin/system_info_controller.rb @@ -12,7 +12,10 @@ class Admin::SystemInfoController < Admin::ApplicationController EXCLUDED_MOUNT_TYPES = [ 'autofs', 'binfmt_misc', + 'bpf', 'cgroup', + 'cgroup2', + 'configfs', 'debugfs', 'devfs', 'devpts', diff --git a/app/controllers/admin/topics_controller.rb b/app/controllers/admin/topics_controller.rb index 908313bdb83..b451928e591 100644 --- a/app/controllers/admin/topics_controller.rb +++ b/app/controllers/admin/topics_controller.rb @@ -4,7 +4,7 @@ class Admin::TopicsController < Admin::ApplicationController include SendFileUpload include PreviewMarkdown - before_action :topic, only: [:edit, :update] + before_action :topic, only: [:edit, :update, :destroy] feature_category :projects @@ -37,6 +37,14 @@ class Admin::TopicsController < Admin::ApplicationController end end + def destroy + @topic.destroy! + + redirect_to admin_topics_path, + status: :found, + notice: _('Topic %{topic_name} was successfully removed.') % { topic_name: @topic.title_or_name } + end + private def topic diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 30760d472a4..71d9910b4b8 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -179,6 +179,10 @@ class ApplicationController < ActionController::Base payload[:queue_duration_s] = request.env[::Gitlab::Middleware::RailsQueueDuration::GITLAB_RAILS_QUEUE_DURATION_KEY] + if Feature.enabled?(:log_response_length) + payload[:response_bytes] = response.body_parts.sum(&:bytesize) + end + store_cloudflare_headers!(payload, request) end diff --git a/app/controllers/clusters/clusters_controller.rb b/app/controllers/clusters/clusters_controller.rb index a04fd09aa22..51150700860 100644 --- a/app/controllers/clusters/clusters_controller.rb +++ b/app/controllers/clusters/clusters_controller.rb @@ -50,7 +50,6 @@ class Clusters::ClustersController < Clusters::BaseController def show if params[:tab] == 'integrations' @prometheus_integration = Clusters::IntegrationPresenter.new(@cluster.find_or_build_integration_prometheus) - @elastic_stack_integration = Clusters::IntegrationPresenter.new(@cluster.find_or_build_integration_elastic_stack) end end diff --git a/app/controllers/concerns/google_analytics_csp.rb b/app/controllers/concerns/google_analytics_csp.rb new file mode 100644 index 00000000000..1a8e405928d --- /dev/null +++ b/app/controllers/concerns/google_analytics_csp.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +module GoogleAnalyticsCSP + extend ActiveSupport::Concern + + included do + content_security_policy do |policy| + next unless helpers.google_tag_manager_enabled? || policy.directives.present? + + default_script_src = policy.directives['script-src'] || policy.directives['default-src'] + script_src_values = Array.wrap(default_script_src) | ['*.googletagmanager.com'] + policy.script_src(*script_src_values) + + default_img_src = policy.directives['img-src'] || policy.directives['default-src'] + img_src_values = Array.wrap(default_img_src) | ['*.google-analytics.com', '*.googletagmanager.com'] + policy.img_src(*img_src_values) + + default_connect_src = policy.directives['connect-src'] || policy.directives['default-src'] + connect_src_values = + Array.wrap(default_connect_src) | ['*.google-analytics.com', '*.analytics.google.com', '*.googletagmanager.com'] + policy.connect_src(*connect_src_values) + end + end +end diff --git a/app/controllers/concerns/harbor/access.rb b/app/controllers/concerns/harbor/access.rb new file mode 100644 index 00000000000..70de72f15fc --- /dev/null +++ b/app/controllers/concerns/harbor/access.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +module Harbor + module Access + extend ActiveSupport::Concern + + included do + before_action :harbor_registry_enabled! + before_action :authorize_read_harbor_registry! + before_action do + push_frontend_feature_flag(:harbor_registry_integration) + end + + feature_category :integrations + end + + private + + def harbor_registry_enabled! + render_404 unless Feature.enabled?(:harbor_registry_integration) + end + + def authorize_read_harbor_registry! + raise NotImplementedError + end + end +end diff --git a/app/controllers/concerns/harbor/artifact.rb b/app/controllers/concerns/harbor/artifact.rb new file mode 100644 index 00000000000..c9d7d26fbb9 --- /dev/null +++ b/app/controllers/concerns/harbor/artifact.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true + +module Harbor + module Artifact + def index + respond_to do |format| + format.json do + artifacts + end + end + end + + private + + def query_params + params.permit(:repository_id, :search, :sort, :page, :limit) + end + + def query + Gitlab::Harbor::Query.new(container.harbor_integration, query_params) + end + + def artifacts + unless query.valid? + return render( + json: { message: 'Invalid parameters', errors: query.errors }, + status: :unprocessable_entity + ) + end + + artifacts_json = ::Integrations::HarborSerializers::ArtifactSerializer.new + .with_pagination(request, response) + .represent(query.artifacts) + render json: artifacts_json + end + + def container + raise NotImplementedError + end + end +end diff --git a/app/controllers/concerns/harbor/repository.rb b/app/controllers/concerns/harbor/repository.rb new file mode 100644 index 00000000000..0e541e2172e --- /dev/null +++ b/app/controllers/concerns/harbor/repository.rb @@ -0,0 +1,51 @@ +# frozen_string_literal: true + +module Harbor + module Repository + def index + respond_to do |format| + format.html + format.json do + repositories + end + end + end + + # The show action renders index to allow frontend routing to work on page refresh + def show + render :index + end + + private + + def query_params + params.permit(:search, :sort, :page, :limit) + end + + def query + Gitlab::Harbor::Query.new(container.harbor_integration, query_params) + end + + def repositories + unless query.valid? + return render( + json: { message: 'Invalid parameters', errors: query.errors }, + status: :unprocessable_entity + ) + end + + repositories_json = ::Integrations::HarborSerializers::RepositorySerializer.new + .with_pagination(request, response) + .represent( + query.repositories, + url: container.harbor_integration.url, + project_name: container.harbor_integration.project_name + ) + render json: repositories_json + end + + def container + raise NotImplementedError + end + end +end diff --git a/app/controllers/concerns/harbor/tag.rb b/app/controllers/concerns/harbor/tag.rb new file mode 100644 index 00000000000..e0c00d1155a --- /dev/null +++ b/app/controllers/concerns/harbor/tag.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true + +module Harbor + module Tag + def index + respond_to do |format| + format.json do + tags + end + end + end + + private + + def query_params + params.permit(:repository_id, :artifact_id, :sort, :page, :limit) + end + + def query + Gitlab::Harbor::Query.new(container.harbor_integration, query_params) + end + + def tags + unless query.valid? + return render( + json: { message: 'Invalid parameters', errors: query.errors }, + status: :unprocessable_entity + ) + end + + tags_json = ::Integrations::HarborSerializers::TagSerializer.new + .with_pagination(request, response) + .represent(query.tags) + render json: tags_json + end + + def container + raise NotImplementedError + end + end +end diff --git a/app/controllers/concerns/integrations/hooks_execution.rb b/app/controllers/concerns/integrations/hooks_execution.rb index 6a9d3d51f9b..fb26840168f 100644 --- a/app/controllers/concerns/integrations/hooks_execution.rb +++ b/app/controllers/concerns/integrations/hooks_execution.rb @@ -3,8 +3,68 @@ module Integrations::HooksExecution extend ActiveSupport::Concern + included do + attr_writer :hooks, :hook + end + + def index + self.hooks = relation.select(&:persisted?) + self.hook = relation.new + end + + def create + self.hook = relation.new(hook_params) + hook.save + + unless hook.valid? + self.hooks = relation.select(&:persisted?) + flash[:alert] = hook.errors.full_messages.join.html_safe + end + + redirect_to action: :index + end + + def update + if hook.update(hook_params) + flash[:notice] = _('Hook was successfully updated.') + redirect_to action: :index + else + render 'edit' + end + end + + def destroy + destroy_hook(hook) + + redirect_to action: :index, status: :found + end + + def edit + redirect_to(action: :index) unless hook + end + private + def hook_params + permitted = hook_param_names + trigger_values + permitted << { url_variables: [:key, :value] } + + ps = params.require(:hook).permit(*permitted).to_h + + ps[:url_variables] = ps[:url_variables].to_h { [_1[:key], _1[:value].presence] } if ps.key?(:url_variables) + + if action_name == 'update' && ps.key?(:url_variables) + supplied = ps[:url_variables] + ps[:url_variables] = hook.url_variables.merge(supplied).compact + end + + ps + end + + def hook_param_names + %i[enable_ssl_verification token url push_events_branch_filter] + end + def destroy_hook(hook) result = WebHooks::DestroyService.new(current_user).execute(hook) diff --git a/app/controllers/concerns/integrations/params.rb b/app/controllers/concerns/integrations/params.rb index d256b331174..c3ad9d3dff3 100644 --- a/app/controllers/concerns/integrations/params.rb +++ b/app/controllers/concerns/integrations/params.rb @@ -6,7 +6,6 @@ module Integrations ALLOWED_PARAMS_CE = [ :active, - :add_pusher, :alert_events, :api_key, :api_token, diff --git a/app/controllers/concerns/issuable_actions.rb b/app/controllers/concerns/issuable_actions.rb index 07850acd23d..a5e49b1b16a 100644 --- a/app/controllers/concerns/issuable_actions.rb +++ b/app/controllers/concerns/issuable_actions.rb @@ -184,7 +184,6 @@ module IssuableActions def paginated_discussions return if params[:per_page].blank? - return if issuable.instance_of?(Issue) && Feature.disabled?(:paginated_issue_discussions, project) return if issuable.instance_of?(MergeRequest) && Feature.disabled?(:paginated_mr_discussions, project) strong_memoize(:paginated_discussions) do diff --git a/app/controllers/concerns/issuable_collections.rb b/app/controllers/concerns/issuable_collections.rb index 4841225de08..de38d26e3fe 100644 --- a/app/controllers/concerns/issuable_collections.rb +++ b/app/controllers/concerns/issuable_collections.rb @@ -24,12 +24,9 @@ module IssuableCollections show_alert_if_search_is_disabled @issuables = issuables_collection + set_pagination - unless pagination_disabled? - set_pagination - - return if redirect_out_of_range(@issuables, @total_pages) - end + return if redirect_out_of_range(@issuables, @total_pages) if params[:label_name].present? && @project labels_params = { project_id: @project.id, title: params[:label_name] } @@ -59,10 +56,6 @@ module IssuableCollections end # rubocop:enable Gitlab/ModuleWithInstanceVariables - def pagination_disabled? - false - end - # rubocop: disable CodeReuse/ActiveRecord def issuables_collection finder.execute.preload(preload_for_collection) diff --git a/app/controllers/concerns/product_analytics_tracking.rb b/app/controllers/concerns/product_analytics_tracking.rb index 0b51b3dd380..dc7ba8295b9 100644 --- a/app/controllers/concerns/product_analytics_tracking.rb +++ b/app/controllers/concerns/product_analytics_tracking.rb @@ -28,7 +28,10 @@ module ProductAnalyticsTracking def event_enabled?(event) events_to_ff = { g_analytics_valuestream: :route_hll_to_snowplow, - i_search_paid: :route_hll_to_snowplow_phase2 + + i_search_paid: :route_hll_to_snowplow_phase2, + i_search_total: :route_hll_to_snowplow_phase2, + i_search_advanced: :route_hll_to_snowplow_phase2 } Feature.enabled?(events_to_ff[event.to_sym], tracking_namespace_source) diff --git a/app/controllers/concerns/verifies_with_email.rb b/app/controllers/concerns/verifies_with_email.rb new file mode 100644 index 00000000000..1a3e7136481 --- /dev/null +++ b/app/controllers/concerns/verifies_with_email.rb @@ -0,0 +1,194 @@ +# frozen_string_literal: true + +# == VerifiesWithEmail +# +# Controller concern to handle verification by email +module VerifiesWithEmail + extend ActiveSupport::Concern + include ActionView::Helpers::DateHelper + + TOKEN_LENGTH = 6 + TOKEN_VALID_FOR_MINUTES = 60 + + included do + prepend_before_action :verify_with_email, only: :create, unless: -> { two_factor_enabled? } + end + + def verify_with_email + return unless user = find_user || find_verification_user + + if session[:verification_user_id] && token = verification_params[:verification_token].presence + # The verification token is submitted, verify it + verify_token(user, token) + elsif require_email_verification_enabled?(user) + # Limit the amount of password guesses, since we now display the email verification page + # when the password is correct, which could be a giveaway when brute-forced. + return render_sign_in_rate_limited if check_rate_limit!(:user_sign_in, scope: user) { true } + + if user.valid_password?(user_params[:password]) + # The user has logged in successfully. + if user.unlock_token + # Prompt for the token if it already has been set + prompt_for_email_verification(user) + elsif user.access_locked? || !AuthenticationEvent.initial_login_or_known_ip_address?(user, request.ip) + # require email verification if: + # - their account has been locked because of too many failed login attempts, or + # - they have logged in before, but never from the current ip address + send_verification_instructions(user) + prompt_for_email_verification(user) + end + end + end + end + + def resend_verification_code + return unless user = find_verification_user + + send_verification_instructions(user) + prompt_for_email_verification(user) + end + + def successful_verification + session.delete(:verification_user_id) + @redirect_url = after_sign_in_path_for(current_user) # rubocop:disable Gitlab/ModuleWithInstanceVariables + + render layout: 'minimal' + end + + private + + def find_verification_user + return unless session[:verification_user_id] + + User.find_by_id(session[:verification_user_id]) + end + + # After successful verification and calling sign_in, devise redirects the + # user to this path. Override it to show the successful verified page. + def after_sign_in_path_for(resource) + if action_name == 'create' && session[:verification_user_id] + return users_successful_verification_path + end + + super + end + + def send_verification_instructions(user) + return if send_rate_limited?(user) + + raw_token, encrypted_token = generate_token + user.unlock_token = encrypted_token + user.lock_access!({ send_instructions: false }) + send_verification_instructions_email(user, raw_token) + end + + def send_verification_instructions_email(user, token) + return unless user.can?(:receive_notifications) + + Notify.verification_instructions_email( + user.id, + token: token, + expires_in: TOKEN_VALID_FOR_MINUTES).deliver_later + + log_verification(user, :instructions_sent) + end + + def verify_token(user, token) + return handle_verification_failure(user, :rate_limited) if verification_rate_limited?(user) + return handle_verification_failure(user, :invalid) unless valid_token?(user, token) + return handle_verification_failure(user, :expired) if expired_token?(user) + + handle_verification_success(user) + end + + def generate_token + raw_token = SecureRandom.random_number(10**TOKEN_LENGTH).to_s.rjust(TOKEN_LENGTH, '0') + encrypted_token = digest_token(raw_token) + [raw_token, encrypted_token] + end + + def digest_token(token) + Devise.token_generator.digest(User, :unlock_token, token) + end + + def render_sign_in_rate_limited + message = s_('IdentityVerification|Maximum login attempts exceeded. '\ + 'Wait %{interval} and try again.') % { interval: user_sign_in_interval } + redirect_to new_user_session_path, alert: message + end + + def user_sign_in_interval + interval_in_seconds = Gitlab::ApplicationRateLimiter.rate_limits[:user_sign_in][:interval] + distance_of_time_in_words(interval_in_seconds) + end + + def verification_rate_limited?(user) + Gitlab::ApplicationRateLimiter.throttled?(:email_verification, scope: user.unlock_token) + end + + def send_rate_limited?(user) + Gitlab::ApplicationRateLimiter.throttled?(:email_verification_code_send, scope: user) + end + + def expired_token?(user) + user.locked_at < (Time.current - TOKEN_VALID_FOR_MINUTES.minutes) + end + + def valid_token?(user, token) + user.unlock_token == digest_token(token) + end + + def handle_verification_failure(user, reason) + message = case reason + when :rate_limited + s_("IdentityVerification|You've reached the maximum amount of tries. "\ + 'Wait %{interval} or resend a new code and try again.') % { interval: email_verification_interval } + when :expired + s_('IdentityVerification|The code has expired. Resend a new code and try again.') + when :invalid + s_('IdentityVerification|The code is incorrect. Enter it again, or resend a new code.') + end + + user.errors.add(:base, message) + log_verification(user, :failed_attempt, reason) + + prompt_for_email_verification(user) + end + + def email_verification_interval + interval_in_seconds = Gitlab::ApplicationRateLimiter.rate_limits[:email_verification][:interval] + distance_of_time_in_words(interval_in_seconds) + end + + def handle_verification_success(user) + user.unlock_access! + log_verification(user, :successful) + + sign_in(user) + end + + def prompt_for_email_verification(user) + session[:verification_user_id] = user.id + self.resource = user + + render 'devise/sessions/email_verification' + end + + def verification_params + params.require(:user).permit(:verification_token) + end + + def log_verification(user, event, reason = nil) + Gitlab::AppLogger.info( + message: 'Email Verification', + event: event.to_s.titlecase, + username: user.username, + ip: request.ip, + reason: reason.to_s + ) + end + + def require_email_verification_enabled?(user) + Feature.enabled?(:require_email_verification, user) + end +end diff --git a/app/controllers/confirmations_controller.rb b/app/controllers/confirmations_controller.rb index 704453fbf44..713231cbc6f 100644 --- a/app/controllers/confirmations_controller.rb +++ b/app/controllers/confirmations_controller.rb @@ -4,6 +4,7 @@ class ConfirmationsController < Devise::ConfirmationsController include AcceptsPendingInvitations include GitlabRecaptcha include OneTrustCSP + include GoogleAnalyticsCSP prepend_before_action :check_recaptcha, only: :create before_action :load_recaptcha, only: :new diff --git a/app/controllers/graphql_controller.rb b/app/controllers/graphql_controller.rb index c71c101b434..67eeb43d5a2 100644 --- a/app/controllers/graphql_controller.rb +++ b/app/controllers/graphql_controller.rb @@ -82,6 +82,13 @@ class GraphqlController < ApplicationController render_error(exception.message, status: :unprocessable_entity) end + rescue_from ActiveRecord::QueryAborted do |exception| + log_exception(exception) + + error = "Request timed out. Please try a less complex query or a smaller set of records." + render_error(error, status: :service_unavailable) + end + override :feature_category def feature_category ::Gitlab::FeatureCategories.default.from_request(request) || super diff --git a/app/controllers/groups/harbor/application_controller.rb b/app/controllers/groups/harbor/application_controller.rb new file mode 100644 index 00000000000..cff767c8efd --- /dev/null +++ b/app/controllers/groups/harbor/application_controller.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +module Groups + module Harbor + class ApplicationController < Groups::ApplicationController + layout 'group' + include ::Harbor::Access + + private + + def authorize_read_harbor_registry! + render_404 unless can?(current_user, :read_harbor_registry, @group) + end + end + end +end diff --git a/app/controllers/groups/harbor/artifacts_controller.rb b/app/controllers/groups/harbor/artifacts_controller.rb new file mode 100644 index 00000000000..b7570b44a2c --- /dev/null +++ b/app/controllers/groups/harbor/artifacts_controller.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +module Groups + module Harbor + class ArtifactsController < ::Groups::Harbor::ApplicationController + include ::Harbor::Artifact + + private + + def container + @group + end + end + end +end diff --git a/app/controllers/groups/harbor/repositories_controller.rb b/app/controllers/groups/harbor/repositories_controller.rb index 364607f9b20..1ad38bd7103 100644 --- a/app/controllers/groups/harbor/repositories_controller.rb +++ b/app/controllers/groups/harbor/repositories_controller.rb @@ -2,22 +2,13 @@ module Groups module Harbor - class RepositoriesController < Groups::ApplicationController - feature_category :integrations - - before_action :harbor_registry_enabled! - before_action do - push_frontend_feature_flag(:harbor_registry_integration) - end - - def show - render :index - end + class RepositoriesController < ::Groups::Harbor::ApplicationController + include ::Harbor::Repository private - def harbor_registry_enabled! - render_404 unless Feature.enabled?(:harbor_registry_integration) + def container + @group end end end diff --git a/app/controllers/groups/harbor/tags_controller.rb b/app/controllers/groups/harbor/tags_controller.rb new file mode 100644 index 00000000000..da43cb3f64c --- /dev/null +++ b/app/controllers/groups/harbor/tags_controller.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +module Groups + module Harbor + class TagsController < ::Groups::Harbor::ApplicationController + include ::Harbor::Tag + + private + + def container + @group + end + end + end +end diff --git a/app/controllers/groups/registry/repositories_controller.rb b/app/controllers/groups/registry/repositories_controller.rb index cb7bf001918..bb2d08e487a 100644 --- a/app/controllers/groups/registry/repositories_controller.rb +++ b/app/controllers/groups/registry/repositories_controller.rb @@ -8,6 +8,10 @@ module Groups before_action :verify_container_registry_enabled! before_action :authorize_read_container_image! + before_action do + push_frontend_feature_flag(:container_registry_show_shortened_path, group) + end + feature_category :container_registry urgency :low diff --git a/app/controllers/import/bitbucket_controller.rb b/app/controllers/import/bitbucket_controller.rb index 55707000cf8..75193309a4e 100644 --- a/app/controllers/import/bitbucket_controller.rb +++ b/app/controllers/import/bitbucket_controller.rb @@ -18,14 +18,14 @@ class Import::BitbucketController < Import::BaseController if auth_state.blank? || !ActiveSupport::SecurityUtils.secure_compare(auth_state, params[:state]) go_to_bitbucket_for_permissions else - response = oauth_client.auth_code.get_token(params[:code], redirect_uri: users_import_bitbucket_callback_url) + response = oauth_client.auth_code.get_token(params[:code], redirect_uri: users_import_bitbucket_callback_url(namespace_id: params[:namespace_id])) session[:bitbucket_token] = response.token session[:bitbucket_expires_at] = response.expires_at session[:bitbucket_expires_in] = response.expires_in session[:bitbucket_refresh_token] = response.refresh_token - redirect_to status_import_bitbucket_url + redirect_to status_import_bitbucket_url(namespace_id: params[:namespace_id]) end end @@ -78,16 +78,15 @@ class Import::BitbucketController < Import::BaseController bitbucket_repos.reject { |repo| repo.valid? } end + def provider_url + nil + end + override :provider_name def provider_name :bitbucket end - override :provider_url - def provider_url - provider.url - end - private def oauth_client @@ -121,7 +120,7 @@ class Import::BitbucketController < Import::BaseController def go_to_bitbucket_for_permissions state = SecureRandom.base64(64) session[:bitbucket_auth_state] = state - redirect_to oauth_client.auth_code.authorize_url(redirect_uri: users_import_bitbucket_callback_url, state: state) + redirect_to oauth_client.auth_code.authorize_url(redirect_uri: users_import_bitbucket_callback_url(namespace_id: params[:namespace_id]), state: state) end def bitbucket_unauthorized(exception) diff --git a/app/controllers/import/bitbucket_server_controller.rb b/app/controllers/import/bitbucket_server_controller.rb index 00f3f0b08b2..12147196749 100644 --- a/app/controllers/import/bitbucket_server_controller.rb +++ b/app/controllers/import/bitbucket_server_controller.rb @@ -49,7 +49,7 @@ class Import::BitbucketServerController < Import::BaseController session[bitbucket_server_username_key] = params[:bitbucket_server_username] session[bitbucket_server_url_key] = params[:bitbucket_server_url] - redirect_to status_import_bitbucket_server_path + redirect_to status_import_bitbucket_server_path(namespace_id: params[:namespace_id]) end # We need to re-expose controller's internal method 'status' as action. @@ -115,7 +115,7 @@ class Import::BitbucketServerController < Import::BaseController unless session[bitbucket_server_url_key].present? && session[bitbucket_server_username_key].present? && session[personal_access_token_key].present? - redirect_to new_import_bitbucket_server_path + redirect_to new_import_bitbucket_server_path(namespace_id: params[:namespace_id]) end end @@ -170,9 +170,6 @@ class Import::BitbucketServerController < Import::BaseController } }, status: :unprocessable_entity end - format.html do - redirect_to new_import_bitbucket_server_path - end end end end diff --git a/app/controllers/import/bulk_imports_controller.rb b/app/controllers/import/bulk_imports_controller.rb index 34f12aebb91..2d607fb7ff7 100644 --- a/app/controllers/import/bulk_imports_controller.rb +++ b/app/controllers/import/bulk_imports_controller.rb @@ -17,7 +17,7 @@ class Import::BulkImportsController < ApplicationController session[access_token_key] = configure_params[access_token_key]&.strip session[url_key] = configure_params[url_key] - redirect_to status_import_bulk_imports_url + redirect_to status_import_bulk_imports_url(namespace_id: params[:namespace_id]) end def status @@ -35,6 +35,12 @@ class Import::BulkImportsController < ApplicationController render json: json_response end format.html do + if params[:namespace_id] + @namespace = Namespace.find_by_id(params[:namespace_id]) + + render_404 unless current_user.can?(:create_subgroup, @namespace) + end + @source_url = session[url_key] end end diff --git a/app/controllers/import/fogbugz_controller.rb b/app/controllers/import/fogbugz_controller.rb index b949a99c250..7b580234227 100644 --- a/app/controllers/import/fogbugz_controller.rb +++ b/app/controllers/import/fogbugz_controller.rb @@ -17,12 +17,12 @@ class Import::FogbugzController < Import::BaseController res = Gitlab::FogbugzImport::Client.new(import_params.to_h.symbolize_keys) rescue StandardError # If the URI is invalid various errors can occur - return redirect_to new_import_fogbugz_path, alert: _('Could not connect to FogBugz, check your URL') + return redirect_to new_import_fogbugz_path(namespace_id: params[:namespace_id]), alert: _('Could not connect to FogBugz, check your URL') end session[:fogbugz_token] = res.get_token session[:fogbugz_uri] = params[:uri] - redirect_to new_user_map_import_fogbugz_path + redirect_to new_user_map_import_fogbugz_path(namespace_id: params[:namespace_id]) end def new_user_map @@ -41,12 +41,12 @@ class Import::FogbugzController < Import::BaseController flash[:notice] = _('The user map has been saved. Continue by selecting the projects you want to import.') - redirect_to status_import_fogbugz_path + redirect_to status_import_fogbugz_path(namespace_id: params[:namespace_id]) end def status unless client.valid? - return redirect_to new_import_fogbugz_path + return redirect_to new_import_fogbugz_path(namespace_id: params[:namespace_id]) end super @@ -106,7 +106,7 @@ class Import::FogbugzController < Import::BaseController end def fogbugz_unauthorized(exception) - redirect_to new_import_fogbugz_path, alert: exception.message + redirect_to new_import_fogbugz_path(namespace_id: params[:namespace_id]), alert: exception.message end def import_params diff --git a/app/controllers/import/gitea_controller.rb b/app/controllers/import/gitea_controller.rb index 399a92c59e0..4b4ac07b389 100644 --- a/app/controllers/import/gitea_controller.rb +++ b/app/controllers/import/gitea_controller.rb @@ -7,7 +7,7 @@ class Import::GiteaController < Import::GithubController def new if session[access_token_key].present? && provider_url.present? - redirect_to status_import_url(namespace_id: params[:namespace_id]) + redirect_to status_import_url end end diff --git a/app/controllers/import/github_controller.rb b/app/controllers/import/github_controller.rb index 8dd40b6254e..9cc58ce542c 100644 --- a/app/controllers/import/github_controller.rb +++ b/app/controllers/import/github_controller.rb @@ -23,25 +23,24 @@ class Import::GithubController < Import::BaseController if !ci_cd_only? && github_import_configured? && logged_in_with_provider? go_to_provider_for_permissions elsif session[access_token_key] - redirect_to status_import_url(namespace_id: params[:namespace_id]) + redirect_to status_import_url end end def callback auth_state = session.delete(auth_state_key) - namespace_id = session.delete(:namespace_id) if auth_state.blank? || !ActiveSupport::SecurityUtils.secure_compare(auth_state, params[:state]) provider_unauthorized else session[access_token_key] = get_token(params[:code]) - redirect_to status_import_url(namespace_id: namespace_id) + redirect_to status_import_url end end def personal_access_token session[access_token_key] = params[:personal_access_token]&.strip - redirect_to status_import_url(namespace_id: params[:namespace_id].presence) + redirect_to status_import_url end def status @@ -205,15 +204,15 @@ class Import::GithubController < Import::BaseController end def new_import_url - public_send("new_import_#{provider_name}_url", extra_import_params) # rubocop:disable GitlabSecurity/PublicSend + public_send("new_import_#{provider_name}_url", extra_import_params.merge({ namespace_id: params[:namespace_id] })) # rubocop:disable GitlabSecurity/PublicSend end - def status_import_url(namespace_id: nil) - public_send("status_import_#{provider_name}_url", extra_import_params.merge({ namespace_id: namespace_id })) # rubocop:disable GitlabSecurity/PublicSend + def status_import_url + public_send("status_import_#{provider_name}_url", extra_import_params.merge({ namespace_id: params[:namespace_id].presence })) # rubocop:disable GitlabSecurity/PublicSend end def callback_import_url - public_send("users_import_#{provider_name}_callback_url", extra_import_params) # rubocop:disable GitlabSecurity/PublicSend + public_send("users_import_#{provider_name}_callback_url", extra_import_params.merge({ namespace_id: params[:namespace_id] })) # rubocop:disable GitlabSecurity/PublicSend end def provider_unauthorized @@ -255,7 +254,6 @@ class Import::GithubController < Import::BaseController def provider_auth if !ci_cd_only? && session[access_token_key].blank? - session[:namespace_id] = params[:namespace_id] go_to_provider_for_permissions end end diff --git a/app/controllers/import/gitlab_controller.rb b/app/controllers/import/gitlab_controller.rb index c846d9d225a..dd25698d0a9 100644 --- a/app/controllers/import/gitlab_controller.rb +++ b/app/controllers/import/gitlab_controller.rb @@ -12,8 +12,8 @@ class Import::GitlabController < Import::BaseController rescue_from OAuth2::Error, with: :gitlab_unauthorized def callback - session[:gitlab_access_token] = client.get_token(params[:code], callback_import_gitlab_url) - redirect_to status_import_gitlab_url + session[:gitlab_access_token] = client.get_token(params[:code], callback_import_gitlab_url(namespace_id: params[:namespace_id])) + redirect_to status_import_gitlab_url(namespace_id: params[:namespace_id]) end # We need to re-expose controller's internal method 'status' as action. @@ -79,7 +79,7 @@ class Import::GitlabController < Import::BaseController end def go_to_gitlab_for_permissions - redirect_to client.authorize_url(callback_import_gitlab_url) + redirect_to client.authorize_url(callback_import_gitlab_url(namespace_id: params[:namespace_id])) end def gitlab_unauthorized diff --git a/app/controllers/jira_connect/oauth_application_ids_controller.rb b/app/controllers/jira_connect/oauth_application_ids_controller.rb index 05c23210da2..a84b47f4c8b 100644 --- a/app/controllers/jira_connect/oauth_application_ids_controller.rb +++ b/app/controllers/jira_connect/oauth_application_ids_controller.rb @@ -5,9 +5,10 @@ module JiraConnect feature_category :integrations skip_before_action :authenticate_user! + skip_before_action :verify_authenticity_token def show - if Feature.enabled?(:jira_connect_oauth_self_managed) && jira_connect_application_key.present? + if show_application_id? render json: { application_id: jira_connect_application_key } else head :not_found @@ -16,6 +17,12 @@ module JiraConnect private + def show_application_id? + return if Gitlab.com? + + Feature.enabled?(:jira_connect_oauth_self_managed) && jira_connect_application_key.present? + end + def jira_connect_application_key Gitlab::CurrentSettings.jira_connect_application_key.presence end diff --git a/app/controllers/jira_connect/subscriptions_controller.rb b/app/controllers/jira_connect/subscriptions_controller.rb index 2ba9f8264e1..623113f8413 100644 --- a/app/controllers/jira_connect/subscriptions_controller.rb +++ b/app/controllers/jira_connect/subscriptions_controller.rb @@ -25,6 +25,7 @@ class JiraConnect::SubscriptionsController < JiraConnect::ApplicationController before_action :allow_rendering_in_iframe, only: :index before_action :verify_qsh_claim!, only: :index + before_action :allow_self_managed_content_security_policy, only: :index before_action :authenticate_user!, only: :create def index @@ -62,6 +63,13 @@ class JiraConnect::SubscriptionsController < JiraConnect::ApplicationController private + def allow_self_managed_content_security_policy + return unless current_jira_installation.instance_url? + + request.content_security_policy.directives['connect-src'] ||= [] + request.content_security_policy.directives['connect-src'] << Gitlab::Utils.append_path(current_jira_installation.instance_url, '/-/jira_connect/oauth_application_ids') + end + def create_service JiraConnectSubscriptions::CreateService.new(current_jira_installation, current_user, namespace_path: params['namespace_path'], jira_user: jira_user) end diff --git a/app/controllers/ldap/omniauth_callbacks_controller.rb b/app/controllers/ldap/omniauth_callbacks_controller.rb index 6aa46b8e4c3..955dfe58449 100644 --- a/app/controllers/ldap/omniauth_callbacks_controller.rb +++ b/app/controllers/ldap/omniauth_callbacks_controller.rb @@ -3,10 +3,12 @@ class Ldap::OmniauthCallbacksController < OmniauthCallbacksController extend ::Gitlab::Utils::Override + before_action :check_action_name_in_available_providers + def self.define_providers! return unless Gitlab::Auth::Ldap::Config.sign_in_enabled? - Gitlab::Auth::Ldap::Config.available_servers.each do |server| + Gitlab::Auth::Ldap::Config.servers.each do |server| alias_method server['provider_name'], :ldap end end @@ -36,6 +38,18 @@ class Ldap::OmniauthCallbacksController < OmniauthCallbacksController redirect_to new_user_session_path end + + private + + def check_action_name_in_available_providers + render_404 unless available_providers.include?(action_name) + end + + def available_providers + Gitlab::Auth::Ldap::Config.available_servers.map do |server| + server['provider_name'] + end + end end Ldap::OmniauthCallbacksController.prepend_mod_with('Ldap::OmniauthCallbacksController') diff --git a/app/controllers/oauth/applications_controller.rb b/app/controllers/oauth/applications_controller.rb index 3724bb0d925..a996bad3fac 100644 --- a/app/controllers/oauth/applications_controller.rb +++ b/app/controllers/oauth/applications_controller.rb @@ -52,10 +52,10 @@ class Oauth::ApplicationsController < Doorkeeper::ApplicationsController end def set_index_vars - @applications = current_user.oauth_applications + @applications = current_user.oauth_applications.load @authorized_tokens = current_user.oauth_authorized_tokens - @authorized_anonymous_tokens = @authorized_tokens.reject(&:application) - @authorized_apps = @authorized_tokens.map(&:application).uniq.reject(&:nil?) + .latest_per_application + .preload_application # Don't overwrite a value possibly set by `create` @application ||= Doorkeeper::Application.new diff --git a/app/controllers/oauth/authorizations_controller.rb b/app/controllers/oauth/authorizations_controller.rb index c9c51289d3a..2e9fbb1d0d9 100644 --- a/app/controllers/oauth/authorizations_controller.rb +++ b/app/controllers/oauth/authorizations_controller.rb @@ -54,8 +54,6 @@ class Oauth::AuthorizationsController < Doorkeeper::AuthorizationsController # limit scopes when signing in with GitLab def downgrade_scopes! - return unless Feature.enabled?(:omniauth_login_minimal_scopes, current_user) - auth_type = params.delete('gl_auth_type') return unless auth_type == 'login' diff --git a/app/controllers/profiles/personal_access_tokens_controller.rb b/app/controllers/profiles/personal_access_tokens_controller.rb index 265fa505b2a..1a8908e8571 100644 --- a/app/controllers/profiles/personal_access_tokens_controller.rb +++ b/app/controllers/profiles/personal_access_tokens_controller.rb @@ -14,6 +14,13 @@ class Profiles::PersonalAccessTokensController < Profiles::ApplicationController name: params[:name], scopes: scopes ) + + respond_to do |format| + format.html + format.json do + render json: @active_personal_access_tokens + end + end end def create @@ -56,6 +63,28 @@ class Profiles::PersonalAccessTokensController < Profiles::ApplicationController def active_personal_access_tokens tokens = finder(state: 'active', sort: 'expires_at_asc').execute + + if Feature.enabled?('access_token_pagination') + tokens = tokens.page(page) + add_pagination_headers(tokens) + end + ::API::Entities::PersonalAccessTokenWithDetails.represent(tokens) end + + def add_pagination_headers(relation) + Gitlab::Pagination::OffsetHeaderBuilder.new( + request_context: self, + per_page: relation.limit_value, + page: relation.current_page, + next_page: relation.next_page, + prev_page: relation.prev_page, + total: relation.total_count, + params: params.permit(:page) + ).execute + end + + def page + (params[:page] || 1).to_i + end end diff --git a/app/controllers/projects/blame_controller.rb b/app/controllers/projects/blame_controller.rb index 64ced43311a..5bfda526fb0 100644 --- a/app/controllers/projects/blame_controller.rb +++ b/app/controllers/projects/blame_controller.rb @@ -25,7 +25,7 @@ class Projects::BlameController < Projects::ApplicationController blame_service = Projects::BlameService.new(@blob, @commit, params.permit(:page)) - @blame = Gitlab::View::Presenter::Factory.new(blame_service.blame, project: @project, path: @path).fabricate! + @blame = Gitlab::View::Presenter::Factory.new(blame_service.blame, project: @project, path: @path, page: blame_service.page).fabricate! render locals: { blame_pagination: blame_service.pagination } end diff --git a/app/controllers/projects/blob_controller.rb b/app/controllers/projects/blob_controller.rb index a9561fb9312..97aae56c4ec 100644 --- a/app/controllers/projects/blob_controller.rb +++ b/app/controllers/projects/blob_controller.rb @@ -42,7 +42,6 @@ class Projects::BlobController < Projects::ApplicationController urgency :low, [:create, :show, :edit, :update, :diff] before_action do - push_frontend_feature_flag(:refactor_blob_viewer, @project) push_frontend_feature_flag(:highlight_js, @project) push_licensed_feature(:file_locks) if @project.licensed_feature_available?(:file_locks) end diff --git a/app/controllers/projects/environments_controller.rb b/app/controllers/projects/environments_controller.rb index ac3c85f3b40..7ef9fd9daed 100644 --- a/app/controllers/projects/environments_controller.rb +++ b/app/controllers/projects/environments_controller.rb @@ -24,9 +24,6 @@ class Projects::EnvironmentsController < Projects::ApplicationController before_action :environment, only: [:show, :edit, :update, :stop, :terminal, :terminal_websocket_authorize, :metrics, :cancel_auto_stop] before_action :verify_api_request!, only: :terminal_websocket_authorize before_action :expire_etag_cache, only: [:index], unless: -> { request.format.json? } - before_action do - push_frontend_feature_flag(:monitor_logging, project) - end after_action :expire_etag_cache, only: [:cancel_auto_stop] feature_category :continuous_delivery diff --git a/app/controllers/projects/google_cloud/base_controller.rb b/app/controllers/projects/google_cloud/base_controller.rb index 980e9bdcdad..050b26a40c7 100644 --- a/app/controllers/projects/google_cloud/base_controller.rb +++ b/app/controllers/projects/google_cloud/base_controller.rb @@ -12,7 +12,7 @@ class Projects::GoogleCloud::BaseController < Projects::ApplicationController def admin_project_google_cloud! unless can?(current_user, :admin_project_google_cloud, project) - track_event('admin_project_google_cloud!', 'access_denied', 'invalid_user') + track_event('admin_project_google_cloud!', 'error_access_denied', 'invalid_user') access_denied! end end @@ -20,7 +20,11 @@ class Projects::GoogleCloud::BaseController < Projects::ApplicationController def google_oauth2_enabled! config = Gitlab::Auth::OAuth::Provider.config_for('google_oauth2') if config.app_id.blank? || config.app_secret.blank? - track_event('google_oauth2_enabled!', 'access_denied', { reason: 'google_oauth2_not_configured', config: config }) + track_event( + 'google_oauth2_enabled!', + 'error_access_denied', + { reason: 'google_oauth2_not_configured', config: config } + ) access_denied! 'This GitLab instance not configured for Google Oauth2.' end end @@ -31,7 +35,7 @@ class Projects::GoogleCloud::BaseController < Projects::ApplicationController enabled_for_project = Feature.enabled?(:incubation_5mp_google_cloud, project) feature_is_enabled = enabled_for_user || enabled_for_group || enabled_for_project unless feature_is_enabled - track_event('feature_flag_enabled!', 'access_denied', 'feature_flag_not_enabled') + track_event('feature_flag_enabled!', 'error_access_denied', 'feature_flag_not_enabled') access_denied! end end @@ -42,7 +46,7 @@ class Projects::GoogleCloud::BaseController < Projects::ApplicationController return if is_token_valid - return_url = project_google_cloud_index_path(project) + return_url = project_google_cloud_configuration_path(project) state = generate_session_key_redirect(request.url, return_url) @authorize_url = GoogleApi::CloudPlatform::Client.new(nil, callback_google_api_auth_url, @@ -65,12 +69,6 @@ class Projects::GoogleCloud::BaseController < Projects::ApplicationController session[GoogleApi::CloudPlatform::Client.session_key_for_expires_at] end - def handle_gcp_error(action, error) - track_event(action, 'gcp_error', error) - @js_data = { screen: 'gcp_error', error: error.to_s }.to_json - render status: :unauthorized, template: 'projects/google_cloud/errors/gcp_error' - end - def track_event(action, label, property) options = { label: label, project: project, user: current_user } diff --git a/app/controllers/projects/google_cloud/configuration_controller.rb b/app/controllers/projects/google_cloud/configuration_controller.rb new file mode 100644 index 00000000000..fa672058247 --- /dev/null +++ b/app/controllers/projects/google_cloud/configuration_controller.rb @@ -0,0 +1,38 @@ +# frozen_string_literal: true + +module Projects + module GoogleCloud + class ConfigurationController < Projects::GoogleCloud::BaseController + def index + @google_cloud_path = project_google_cloud_configuration_path(project) + js_data = { + configurationUrl: project_google_cloud_configuration_path(project), + deploymentsUrl: project_google_cloud_deployments_path(project), + databasesUrl: project_google_cloud_databases_path(project), + serviceAccounts: ::GoogleCloud::ServiceAccountsService.new(project).find_for_project, + createServiceAccountUrl: project_google_cloud_service_accounts_path(project), + emptyIllustrationUrl: ActionController::Base.helpers.image_path('illustrations/pipelines_empty.svg'), + configureGcpRegionsUrl: project_google_cloud_gcp_regions_path(project), + gcpRegions: gcp_regions, + revokeOauthUrl: revoke_oauth_url + } + @js_data = js_data.to_json + track_event('configuration#index', 'success', js_data) + end + + private + + def gcp_regions + params = { key: Projects::GoogleCloud::GcpRegionsController::GCP_REGION_CI_VAR_KEY } + list = ::Ci::VariablesFinder.new(project, params).execute + list.map { |variable| { gcp_region: variable.value, environment: variable.environment_scope } } + end + + def revoke_oauth_url + google_token_valid = GoogleApi::CloudPlatform::Client.new(token_in_session, nil) + .validate_token(expires_at_in_session) + google_token_valid ? project_google_cloud_revoke_oauth_index_path(project) : nil + end + end + end +end diff --git a/app/controllers/projects/google_cloud/databases_controller.rb b/app/controllers/projects/google_cloud/databases_controller.rb new file mode 100644 index 00000000000..711409e7550 --- /dev/null +++ b/app/controllers/projects/google_cloud/databases_controller.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +module Projects + module GoogleCloud + class DatabasesController < Projects::GoogleCloud::BaseController + def index + @google_cloud_path = project_google_cloud_configuration_path(project) + js_data = { + configurationUrl: project_google_cloud_configuration_path(project), + deploymentsUrl: project_google_cloud_deployments_path(project), + databasesUrl: project_google_cloud_databases_path(project) + } + @js_data = js_data.to_json + track_event('databases#index', 'success', js_data) + end + end + end +end diff --git a/app/controllers/projects/google_cloud/deployments_controller.rb b/app/controllers/projects/google_cloud/deployments_controller.rb index 4867d344c5a..4aa17b36fad 100644 --- a/app/controllers/projects/google_cloud/deployments_controller.rb +++ b/app/controllers/projects/google_cloud/deployments_controller.rb @@ -3,32 +3,47 @@ class Projects::GoogleCloud::DeploymentsController < Projects::GoogleCloud::BaseController before_action :validate_gcp_token! + def index + @google_cloud_path = project_google_cloud_configuration_path(project) + js_data = { + configurationUrl: project_google_cloud_configuration_path(project), + deploymentsUrl: project_google_cloud_deployments_path(project), + databasesUrl: project_google_cloud_databases_path(project), + enableCloudRunUrl: project_google_cloud_deployments_cloud_run_path(project), + enableCloudStorageUrl: project_google_cloud_deployments_cloud_storage_path(project) + } + @js_data = js_data.to_json + track_event('deployments#index', 'success', js_data) + end + def cloud_run - params = { token_in_session: token_in_session } + params = { google_oauth2_token: token_in_session } enable_cloud_run_response = GoogleCloud::EnableCloudRunService .new(project, current_user, params).execute if enable_cloud_run_response[:status] == :error - track_event('deployments#cloud_run', 'enable_cloud_run_error', enable_cloud_run_response) + track_event('deployments#cloud_run', 'error_enable_cloud_run', enable_cloud_run_response) flash[:error] = enable_cloud_run_response[:message] - redirect_to project_google_cloud_index_path(project) + redirect_to project_google_cloud_deployments_path(project) else params = { action: GoogleCloud::GeneratePipelineService::ACTION_DEPLOY_TO_CLOUD_RUN } generate_pipeline_response = GoogleCloud::GeneratePipelineService .new(project, current_user, params).execute if generate_pipeline_response[:status] == :error - track_event('deployments#cloud_run', 'generate_pipeline_error', generate_pipeline_response) + track_event('deployments#cloud_run', 'error_generate_pipeline', generate_pipeline_response) flash[:error] = 'Failed to generate pipeline' - redirect_to project_google_cloud_index_path(project) + redirect_to project_google_cloud_deployments_path(project) else cloud_run_mr_params = cloud_run_mr_params(generate_pipeline_response[:branch_name]) - track_event('deployments#cloud_run', 'cloud_run_success', cloud_run_mr_params) + track_event('deployments#cloud_run', 'success', cloud_run_mr_params) redirect_to project_new_merge_request_path(project, merge_request: cloud_run_mr_params) end end - rescue Google::Apis::ClientError => error - handle_gcp_error('deployments#cloud_run', error) + rescue Google::Apis::ClientError, Google::Apis::ServerError, Google::Apis::AuthorizationError => error + track_event('deployments#cloud_run', 'error_gcp', error) + flash[:warning] = _('Google Cloud Error - %{error}') % { error: error } + redirect_to project_google_cloud_deployments_path(project) end def cloud_storage diff --git a/app/controllers/projects/google_cloud/gcp_regions_controller.rb b/app/controllers/projects/google_cloud/gcp_regions_controller.rb index beeb91cfd80..3fbe9a96284 100644 --- a/app/controllers/projects/google_cloud/gcp_regions_controller.rb +++ b/app/controllers/projects/google_cloud/gcp_regions_controller.rb @@ -6,8 +6,10 @@ class Projects::GoogleCloud::GcpRegionsController < Projects::GoogleCloud::BaseC # Source https://cloud.google.com/run/docs/locations 2022-01-30 AVAILABLE_REGIONS = %w[asia-east1 asia-northeast1 asia-southeast1 europe-north1 europe-west1 europe-west4 us-central1 us-east1 us-east4 us-west1].freeze + GCP_REGION_CI_VAR_KEY = 'GCP_REGION' + def index - @google_cloud_path = project_google_cloud_index_path(project) + @google_cloud_path = project_google_cloud_configuration_path(project) params = { per_page: 50 } branches = BranchesFinder.new(project.repository, params).execute(gitaly_pagination: true) tags = TagsFinder.new(project.repository, params).execute(gitaly_pagination: true) @@ -16,16 +18,16 @@ class Projects::GoogleCloud::GcpRegionsController < Projects::GoogleCloud::BaseC screen: 'gcp_regions_form', availableRegions: AVAILABLE_REGIONS, refs: refs, - cancelPath: project_google_cloud_index_path(project) + cancelPath: project_google_cloud_configuration_path(project) } @js_data = js_data.to_json - track_event('gcp_regions#index', 'form_render', js_data) + track_event('gcp_regions#index', 'success', js_data) end def create permitted_params = params.permit(:ref, :gcp_region) response = GoogleCloud::GcpRegionAddOrReplaceService.new(project).execute(permitted_params[:ref], permitted_params[:gcp_region]) - track_event('gcp_regions#create', 'form_submit', response) - redirect_to project_google_cloud_index_path(project), notice: _('GCP region configured') + track_event('gcp_regions#create', 'success', response) + redirect_to project_google_cloud_configuration_path(project), notice: _('GCP region configured') end end diff --git a/app/controllers/projects/google_cloud/revoke_oauth_controller.rb b/app/controllers/projects/google_cloud/revoke_oauth_controller.rb index 03d1474707b..1a9a2daf4f2 100644 --- a/app/controllers/projects/google_cloud/revoke_oauth_controller.rb +++ b/app/controllers/projects/google_cloud/revoke_oauth_controller.rb @@ -8,16 +8,15 @@ class Projects::GoogleCloud::RevokeOauthController < Projects::GoogleCloud::Base response = google_api_client.revoke_authorizations if response.success? - status = 'success' redirect_message = { notice: s_('GoogleCloud|Google OAuth2 token revocation requested') } + track_event('revoke_oauth#create', 'success', response.to_json) else - status = 'failed' redirect_message = { alert: s_('GoogleCloud|Google OAuth2 token revocation request failed') } + track_event('revoke_oauth#create', 'error', response.to_json) end session.delete(GoogleApi::CloudPlatform::Client.session_key_for_token) - track_event('revoke_oauth#create', 'create', status) - redirect_to project_google_cloud_index_path(project), redirect_message + redirect_to project_google_cloud_configuration_path(project), redirect_message end end diff --git a/app/controllers/projects/google_cloud/service_accounts_controller.rb b/app/controllers/projects/google_cloud/service_accounts_controller.rb index 5d8b2030d5c..dbd83be19db 100644 --- a/app/controllers/projects/google_cloud/service_accounts_controller.rb +++ b/app/controllers/projects/google_cloud/service_accounts_controller.rb @@ -4,14 +4,15 @@ class Projects::GoogleCloud::ServiceAccountsController < Projects::GoogleCloud:: before_action :validate_gcp_token! def index - @google_cloud_path = project_google_cloud_index_path(project) + @google_cloud_path = project_google_cloud_configuration_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 - track_event('service_accounts#index', 'form_error', 'no_gcp_projects') - render status: :unauthorized, template: 'projects/google_cloud/errors/no_gcp_projects' + track_event('service_accounts#index', 'error_form', 'no_gcp_projects') + flash[:warning] = _('No Google Cloud projects - You need at least one Google Cloud project') + redirect_to project_google_cloud_configuration_path(project) else params = { per_page: 50 } branches = BranchesFinder.new(project.repository, params).execute(gitaly_pagination: true) @@ -21,14 +22,16 @@ class Projects::GoogleCloud::ServiceAccountsController < Projects::GoogleCloud:: screen: 'service_accounts_form', gcpProjects: gcp_projects, refs: refs, - cancelPath: project_google_cloud_index_path(project) + cancelPath: project_google_cloud_configuration_path(project) } @js_data = js_data.to_json - track_event('service_accounts#index', 'form_success', js_data) + track_event('service_accounts#index', 'success', js_data) end - rescue Google::Apis::ClientError => error - handle_gcp_error('service_accounts#index', error) + rescue Google::Apis::ClientError, Google::Apis::ServerError, Google::Apis::AuthorizationError => error + track_event('service_accounts#index', 'error_gcp', error) + flash[:warning] = _('Google Cloud Error - %{error}') % { error: error } + redirect_to project_google_cloud_configuration_path(project) end def create @@ -42,9 +45,11 @@ class Projects::GoogleCloud::ServiceAccountsController < Projects::GoogleCloud:: environment_name: permitted_params[:ref] ).execute - track_event('service_accounts#create', 'form_submit', response) - redirect_to project_google_cloud_index_path(project), notice: response.message + track_event('service_accounts#create', 'success', response) + redirect_to project_google_cloud_configuration_path(project), notice: response.message rescue Google::Apis::ClientError, Google::Apis::ServerError, Google::Apis::AuthorizationError => error - handle_gcp_error('service_accounts#create', error) + track_event('service_accounts#create', 'error_gcp', error) + flash[:warning] = _('Google Cloud Error - %{error}') % { error: error } + redirect_to project_google_cloud_configuration_path(project) end end diff --git a/app/controllers/projects/google_cloud_controller.rb b/app/controllers/projects/google_cloud_controller.rb deleted file mode 100644 index 49bb4bec859..00000000000 --- a/app/controllers/projects/google_cloud_controller.rb +++ /dev/null @@ -1,34 +0,0 @@ -# frozen_string_literal: true - -class Projects::GoogleCloudController < Projects::GoogleCloud::BaseController - GCP_REGION_CI_VAR_KEY = 'GCP_REGION' - - def index - js_data = { - screen: 'home', - serviceAccounts: GoogleCloud::ServiceAccountsService.new(project).find_for_project, - createServiceAccountUrl: project_google_cloud_service_accounts_path(project), - enableCloudRunUrl: project_google_cloud_deployments_cloud_run_path(project), - enableCloudStorageUrl: project_google_cloud_deployments_cloud_storage_path(project), - emptyIllustrationUrl: ActionController::Base.helpers.image_path('illustrations/pipelines_empty.svg'), - configureGcpRegionsUrl: project_google_cloud_gcp_regions_path(project), - gcpRegions: gcp_regions, - revokeOauthUrl: revoke_oauth_url - } - @js_data = js_data.to_json - track_event('google_cloud#index', 'index', js_data) - end - - private - - def gcp_regions - list = ::Ci::VariablesFinder.new(project, { key: GCP_REGION_CI_VAR_KEY }).execute - list.map { |variable| { gcp_region: variable.value, environment: variable.environment_scope } } - end - - def revoke_oauth_url - google_token_valid = GoogleApi::CloudPlatform::Client.new(token_in_session, nil) - .validate_token(expires_at_in_session) - google_token_valid ? project_google_cloud_revoke_oauth_index_path(project) : nil - end -end diff --git a/app/controllers/projects/group_links_controller.rb b/app/controllers/projects/group_links_controller.rb index 6007e09f109..08eebfa0e4b 100644 --- a/app/controllers/projects/group_links_controller.rb +++ b/app/controllers/projects/group_links_controller.rb @@ -9,7 +9,7 @@ class Projects::GroupLinksController < Projects::ApplicationController def update group_link = @project.project_group_links.find(params[:id]) - Projects::GroupLinks::UpdateService.new(group_link).execute(group_link_params) + Projects::GroupLinks::UpdateService.new(group_link, current_user).execute(group_link_params) if group_link.expires? render json: { diff --git a/app/controllers/projects/harbor/application_controller.rb b/app/controllers/projects/harbor/application_controller.rb index e6e694783fa..9271ec560dc 100644 --- a/app/controllers/projects/harbor/application_controller.rb +++ b/app/controllers/projects/harbor/application_controller.rb @@ -4,18 +4,12 @@ module Projects module Harbor class ApplicationController < Projects::ApplicationController layout 'project' - - before_action :harbor_registry_enabled! - before_action do - push_frontend_feature_flag(:harbor_registry_integration) - end - - feature_category :integrations + include ::Harbor::Access private - def harbor_registry_enabled! - render_404 unless Feature.enabled?(:harbor_registry_integration) + def authorize_read_harbor_registry! + render_404 unless can?(current_user, :read_harbor_registry, @project) end end end diff --git a/app/controllers/projects/harbor/artifacts_controller.rb b/app/controllers/projects/harbor/artifacts_controller.rb new file mode 100644 index 00000000000..ce36f181b42 --- /dev/null +++ b/app/controllers/projects/harbor/artifacts_controller.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +module Projects + module Harbor + class ArtifactsController < ::Projects::Harbor::ApplicationController + include ::Harbor::Artifact + + private + + def container + @project + end + end + end +end diff --git a/app/controllers/projects/harbor/repositories_controller.rb b/app/controllers/projects/harbor/repositories_controller.rb index dd3e3dc1978..4db13331bf0 100644 --- a/app/controllers/projects/harbor/repositories_controller.rb +++ b/app/controllers/projects/harbor/repositories_controller.rb @@ -3,8 +3,12 @@ module Projects module Harbor class RepositoriesController < ::Projects::Harbor::ApplicationController - def show - render :index + include ::Harbor::Repository + + private + + def container + @project end end end diff --git a/app/controllers/projects/harbor/tags_controller.rb b/app/controllers/projects/harbor/tags_controller.rb new file mode 100644 index 00000000000..f49c5ac7768 --- /dev/null +++ b/app/controllers/projects/harbor/tags_controller.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +module Projects + module Harbor + class TagsController < ::Projects::Harbor::ApplicationController + include ::Harbor::Tag + + private + + def container + @project + end + end + end +end diff --git a/app/controllers/projects/hooks_controller.rb b/app/controllers/projects/hooks_controller.rb index 99eba32e00f..50f388324f1 100644 --- a/app/controllers/projects/hooks_controller.rb +++ b/app/controllers/projects/hooks_controller.rb @@ -15,52 +15,21 @@ class Projects::HooksController < Projects::ApplicationController feature_category :integrations urgency :low, [:test] - def index - @hooks = @project.hooks.load - @hook = ProjectHook.new - end - - def create - @hook = @project.hooks.new(hook_params) - @hook.save - - unless @hook.valid? - @hooks = @project.hooks.select(&:persisted?) - flash[:alert] = @hook.errors.full_messages.join.html_safe - end - - redirect_to action: :index - end - - def edit - redirect_to(action: :index) unless hook - end - - def update - if hook.update(hook_params) - flash[:notice] = _('Hook was successfully updated.') - redirect_to action: :index - else - render 'edit' - end - end - def test - result = TestHooks::ProjectService.new(hook, current_user, params[:trigger]).execute + trigger = params.fetch(:trigger, ::ProjectHook.triggers.each_value.first.to_s) + result = TestHooks::ProjectService.new(hook, current_user, trigger).execute set_hook_execution_notice(result) redirect_back_or_default(default: { action: :index }) end - def destroy - destroy_hook(hook) + private - redirect_to action: :index, status: :found + def relation + @project.hooks end - private - def hook @hook ||= @project.hooks.find(params[:id]) end @@ -69,13 +38,7 @@ class Projects::HooksController < Projects::ApplicationController @hook_logs ||= hook.web_hook_logs.recent.page(params[:page]) end - def hook_params - params.require(:hook).permit( - :enable_ssl_verification, - :token, - :url, - :push_events_branch_filter, - *ProjectHook.triggers.values - ) + def trigger_values + ProjectHook.triggers.values end end diff --git a/app/controllers/projects/incidents_controller.rb b/app/controllers/projects/incidents_controller.rb index 70eab792b40..f9fa8046962 100644 --- a/app/controllers/projects/incidents_controller.rb +++ b/app/controllers/projects/incidents_controller.rb @@ -8,6 +8,9 @@ class Projects::IncidentsController < Projects::ApplicationController before_action :load_incident, only: [:show] before_action do push_frontend_feature_flag(:incident_timeline, @project) + push_force_frontend_feature_flag(:work_items, @project&.work_items_feature_flag_enabled?) + push_frontend_feature_flag(:work_items_mvc_2) + push_frontend_feature_flag(:work_items_hierarchy, @project) end feature_category :incident_management diff --git a/app/controllers/projects/issues_controller.rb b/app/controllers/projects/issues_controller.rb index f974b16468c..f1c9e2b2653 100644 --- a/app/controllers/projects/issues_controller.rb +++ b/app/controllers/projects/issues_controller.rb @@ -22,7 +22,7 @@ class Projects::IssuesController < Projects::ApplicationController before_action :issue, unless: ->(c) { ISSUES_EXCEPT_ACTIONS.include?(c.action_name.to_sym) } before_action :redirect_if_task, 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) } + after_action :log_issue_show, only: :show before_action :set_issuables_index, if: ->(c) { SET_ISSUABLES_INDEX_ONLY_ACTIONS.include?(c.action_name.to_sym) && !index_html_request? @@ -41,14 +41,11 @@ class Projects::IssuesController < Projects::ApplicationController before_action :authorize_download_code!, only: [:related_branches] before_action do - push_frontend_feature_flag(:contacts_autocomplete, project&.group) push_frontend_feature_flag(:incident_timeline, project) end before_action only: :show do - push_frontend_feature_flag(:confidential_notes, project&.group) push_frontend_feature_flag(:issue_assignees_widget, project) - push_frontend_feature_flag(:paginated_issue_discussions, project) push_frontend_feature_flag(:realtime_labels, project) push_force_frontend_feature_flag(:work_items, project&.work_items_feature_flag_enabled?) push_frontend_feature_flag(:work_items_mvc_2) diff --git a/app/controllers/projects/jobs_controller.rb b/app/controllers/projects/jobs_controller.rb index 9574c5d5849..ad59f421c06 100644 --- a/app/controllers/projects/jobs_controller.rb +++ b/app/controllers/projects/jobs_controller.rb @@ -5,28 +5,22 @@ class Projects::JobsController < Projects::ApplicationController include ContinueParams include ProjectStatsRefreshConflictsGuard - urgency :low, [:index, :show, :trace, :retry, :play, :cancel, :unschedule, :status, :erase, :raw] + urgency :low, [:index, :show, :trace, :retry, :play, :cancel, :unschedule, :erase, :raw] 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!, - except: [:index, :show, :status, :raw, :trace, :erase, :cancel, :unschedule] + except: [:index, :show, :raw, :trace, :erase, :cancel, :unschedule] before_action :authorize_erase_build!, only: [:erase] before_action :authorize_use_build_terminal!, only: [:terminal, :terminal_websocket_authorize] before_action :verify_api_request!, only: :terminal_websocket_authorize before_action :authorize_create_proxy_build!, only: :proxy_websocket_authorize before_action :verify_proxy_request!, only: :proxy_websocket_authorize - before_action :push_jobs_table_vue, only: [:index] - before_action :push_jobs_table_vue_search, only: [:index] + before_action :push_job_log_search, only: [:show] before_action :reject_if_build_artifacts_size_refreshing!, only: [:erase] - before_action do - push_frontend_feature_flag(:infinitely_collapsible_sections, @project) - push_frontend_feature_flag(:trigger_job_retry_action, @project) - end - layout 'project' feature_category :continuous_integration @@ -125,12 +119,6 @@ class Projects::JobsController < Projects::ApplicationController end end - def status - render json: Ci::JobSerializer - .new(project: @project, current_user: @current_user) - .represent_status(@build.present(current_user: current_user)) - end - def erase if @build.erase(erased_by: current_user) redirect_to project_job_path(project, @build), @@ -261,11 +249,7 @@ class Projects::JobsController < Projects::ApplicationController ::Gitlab::Workhorse.channel_websocket(service) end - def push_jobs_table_vue - push_frontend_feature_flag(:jobs_table_vue, @project) - end - - def push_jobs_table_vue_search - push_frontend_feature_flag(:jobs_table_vue_search, @project) + def push_job_log_search + push_frontend_feature_flag(:job_log_search, @project) end end diff --git a/app/controllers/projects/logs_controller.rb b/app/controllers/projects/logs_controller.rb deleted file mode 100644 index 0f751db2064..00000000000 --- a/app/controllers/projects/logs_controller.rb +++ /dev/null @@ -1,103 +0,0 @@ -# frozen_string_literal: true - -module Projects - class LogsController < Projects::ApplicationController - include ::Gitlab::Utils::StrongMemoize - - before_action :authorize_read_pod_logs! - before_action :ensure_deployments, only: %i(k8s elasticsearch) - - feature_category :logging - urgency :low - - def index - return render_404 unless Feature.enabled?(:monitor_logging, project) - - if environment || cluster - render :index - else - render :empty_logs - end - end - - def k8s - render_logs(::PodLogs::KubernetesService, k8s_params) - end - - def elasticsearch - render_logs(::PodLogs::ElasticsearchService, elasticsearch_params) - end - - private - - def render_logs(service, permitted_params) - ::Gitlab::PollingInterval.set_header(response, interval: 3_000) - - result = service.new(cluster, namespace, params: permitted_params).execute - - if result.nil? - head :accepted - elsif result[:status] == :success - render json: result - else - render status: :bad_request, json: result - end - end - - # cluster is selected either via environment or directly by id - def cluster_params - params.permit(:environment_name, :cluster_id) - end - - def k8s_params - params.permit(:container_name, :pod_name) - end - - def elasticsearch_params - params.permit(:container_name, :pod_name, :search, :start_time, :end_time, :cursor) - end - - def environment - strong_memoize(:environment) do - if cluster_params.key?(:environment_name) - ::Environments::EnvironmentsFinder.new(project, current_user, name: cluster_params[:environment_name]).execute.first - else - project.default_environment - end - end - end - - def cluster - strong_memoize(:cluster) do - if gitlab_managed_apps_logs? - clusters = ClusterAncestorsFinder.new(project, current_user).execute - clusters.find { |cluster| cluster.id == cluster_params[:cluster_id].to_i } - else - environment&.deployment_platform&.cluster - end - end - end - - def namespace - if gitlab_managed_apps_logs? - Gitlab::Kubernetes::Helm::NAMESPACE - else - environment.deployment_namespace - end - end - - def ensure_deployments - return if gitlab_managed_apps_logs? - return if cluster && namespace.present? - - render status: :bad_request, json: { - status: :error, - message: _('Environment does not have deployments') - } - end - - def gitlab_managed_apps_logs? - cluster_params.key?(:cluster_id) - end - end -end diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb index d420e136316..a2f018c013b 100644 --- a/app/controllers/projects/merge_requests_controller.rb +++ b/app/controllers/projects/merge_requests_controller.rb @@ -32,10 +32,8 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo before_action :check_user_can_push_to_source_branch!, only: [:rebase] before_action only: [:show] do - push_frontend_feature_flag(:file_identifier_hash) push_frontend_feature_flag(:merge_request_widget_graphql, project) push_frontend_feature_flag(:core_security_mr_widget_counts, project) - push_frontend_feature_flag(:confidential_notes, project) push_frontend_feature_flag(:restructured_mr_widget, project) push_frontend_feature_flag(:refactor_mr_widgets_extensions, project) push_frontend_feature_flag(:refactor_code_quality_extension, project) @@ -44,10 +42,12 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo push_frontend_feature_flag(:issue_assignees_widget, @project) push_frontend_feature_flag(:realtime_labels, project) push_frontend_feature_flag(:refactor_security_extension, @project) + push_frontend_feature_flag(:refactor_code_quality_inline_findings, project) push_frontend_feature_flag(:mr_attention_requests, current_user) push_frontend_feature_flag(:moved_mr_sidebar, project) push_frontend_feature_flag(:paginated_mr_discussions, project) push_frontend_feature_flag(:mr_review_submit_comment, project) + push_frontend_feature_flag(:mr_experience_survey, project) end before_action do @@ -86,6 +86,7 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo :rebase, :discussions, :pipelines, + :coverage_reports, :test_reports, :codequality_mr_diff_reports, :codequality_reports, diff --git a/app/controllers/projects/metrics_dashboard_controller.rb b/app/controllers/projects/metrics_dashboard_controller.rb index f2f276071a0..b78ee6ca917 100644 --- a/app/controllers/projects/metrics_dashboard_controller.rb +++ b/app/controllers/projects/metrics_dashboard_controller.rb @@ -12,7 +12,6 @@ module Projects before_action do push_frontend_feature_flag(:prometheus_computed_alerts) push_frontend_feature_flag(:disable_metric_dashboard_refresh_rate) - push_frontend_feature_flag(:monitor_logging, project) end feature_category :metrics diff --git a/app/controllers/projects/pipelines/tests_controller.rb b/app/controllers/projects/pipelines/tests_controller.rb index e5b2dd14f69..8ac370b1bd4 100644 --- a/app/controllers/projects/pipelines/tests_controller.rb +++ b/app/controllers/projects/pipelines/tests_controller.rb @@ -7,6 +7,7 @@ module Projects before_action :authorize_read_build! before_action :builds, only: [:show] + before_action :validate_test_reports!, only: [:show] feature_category :code_testing @@ -23,19 +24,21 @@ module Projects def show respond_to do |format| format.json do - if pipeline.has_expired_test_reports? - render json: { errors: 'Test report artifacts have expired' }, status: :not_found - else - render json: TestSuiteSerializer - .new(project: project, current_user: @current_user) - .represent(test_suite, details: true) - end + render json: TestSuiteSerializer + .new(project: project, current_user: @current_user) + .represent(test_suite, details: true) end end end private + def validate_test_reports! + unless pipeline.has_test_reports? + render json: { errors: 'Test report artifacts not found' }, status: :not_found + end + end + def builds @builds ||= pipeline.latest_builds.id_in(build_ids).presence || render_404 end @@ -48,7 +51,7 @@ module Projects def test_suite suite = builds.sum do |build| - build.collect_test_reports!(Gitlab::Ci::Reports::TestReports.new) + build.collect_test_reports!(Gitlab::Ci::Reports::TestReport.new) end Gitlab::Ci::Reports::TestFailureHistory.new(suite.failed.values, project).load! diff --git a/app/controllers/projects/pipelines_controller.rb b/app/controllers/projects/pipelines_controller.rb index adc3a912a91..b2aa1d9f4ca 100644 --- a/app/controllers/projects/pipelines_controller.rb +++ b/app/controllers/projects/pipelines_controller.rb @@ -38,6 +38,8 @@ class Projects::PipelinesController < Projects::ApplicationController 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? } + track_redis_hll_event :charts, name: 'p_analytics_ci_cd_time_to_restore_service', if: -> { should_track_ci_cd_time_to_restore_service? } + track_redis_hll_event :charts, name: 'p_analytics_ci_cd_change_failure_rate', if: -> { should_track_ci_cd_change_failure_rate? } wrap_parameters Ci::Pipeline @@ -174,7 +176,7 @@ class Projects::PipelinesController < Projects::ApplicationController end def stage - @stage = pipeline.legacy_stage(params[:stage]) + @stage = pipeline.stage(params[:stage]) return not_found unless @stage render json: StageSerializer @@ -361,6 +363,14 @@ class Projects::PipelinesController < Projects::ApplicationController def should_track_ci_cd_lead_time? params[:chart] == 'lead-time' end + + def should_track_ci_cd_time_to_restore_service? + params[:chart] == 'time-to-restore-service' + end + + def should_track_ci_cd_change_failure_rate? + params[:chart] == 'change-failure-rate' + end end Projects::PipelinesController.prepend_mod_with('Projects::PipelinesController') diff --git a/app/controllers/projects/project_members_controller.rb b/app/controllers/projects/project_members_controller.rb index 168e703c87d..cd9c6efb106 100644 --- a/app/controllers/projects/project_members_controller.rb +++ b/app/controllers/projects/project_members_controller.rb @@ -13,9 +13,7 @@ class Projects::ProjectMembersController < Projects::ApplicationController def index @sort = params[:sort].presence || sort_value_name - - @group_links = @project.project_group_links - @group_links = @group_links.search(params[:search_groups]) if params[:search_groups].present? + @include_relations ||= requested_relations(:groups_with_inherited_permissions) if can?(current_user, :admin_project_member, @project) @invited_members = present_members(invited_members) diff --git a/app/controllers/projects/registry/repositories_controller.rb b/app/controllers/projects/registry/repositories_controller.rb index ad3b2bc98e7..87cb8e4781f 100644 --- a/app/controllers/projects/registry/repositories_controller.rb +++ b/app/controllers/projects/registry/repositories_controller.rb @@ -8,6 +8,10 @@ module Projects before_action :authorize_update_container_image!, only: [:destroy] + before_action do + push_frontend_feature_flag(:container_registry_show_shortened_path, project) + end + def index respond_to do |format| format.html { ensure_root_container_repository! } diff --git a/app/controllers/projects/service_ping_controller.rb b/app/controllers/projects/service_ping_controller.rb index d8f1785d95e..43c249afd8e 100644 --- a/app/controllers/projects/service_ping_controller.rb +++ b/app/controllers/projects/service_ping_controller.rb @@ -17,7 +17,8 @@ class Projects::ServicePingController < Projects::ApplicationController return render_404 unless Gitlab::CurrentSettings.web_ide_clientside_preview_enabled? Gitlab::UsageDataCounters::WebIdeCounter.increment_previews_success_count - Gitlab::UsageDataCounters::EditorUniqueCounter.track_live_preview_edit_action(author: current_user) + Gitlab::UsageDataCounters::EditorUniqueCounter.track_live_preview_edit_action(author: current_user, + project: project) head(200) end diff --git a/app/controllers/projects/settings/integrations_controller.rb b/app/controllers/projects/settings/integrations_controller.rb index 3365da65de8..cee9e9feb7b 100644 --- a/app/controllers/projects/settings/integrations_controller.rb +++ b/app/controllers/projects/settings/integrations_controller.rb @@ -11,6 +11,7 @@ module Projects before_action :integration, only: [:edit, :update, :test] before_action :default_integration, only: [:edit, :update] before_action :web_hook_logs, only: [:edit, :update] + before_action -> { check_rate_limit!(:project_testing_integration, scope: [@project, current_user]) }, only: :test respond_to :html @@ -88,7 +89,7 @@ module Projects unless result[:success] return { error: true, - message: s_('Integrations|Connection failed. Please check your settings.'), + message: s_('Integrations|Connection failed. Check your integration settings.'), service_response: result[:message].to_s, test_failed: true } @@ -98,7 +99,7 @@ module Projects rescue *Gitlab::HTTP::HTTP_ERRORS => e { error: true, - message: s_('Integrations|Connection failed. Please check your settings.'), + message: s_('Integrations|Connection failed. Check your integration settings.'), service_response: e.message, test_failed: true } diff --git a/app/controllers/projects/settings/operations_controller.rb b/app/controllers/projects/settings/operations_controller.rb index 77d7f3570f3..478d9f0b38e 100644 --- a/app/controllers/projects/settings/operations_controller.rb +++ b/app/controllers/projects/settings/operations_controller.rb @@ -14,7 +14,6 @@ module Projects respond_to :json, only: [:reset_alerting_token, :reset_pagerduty_token] helper_method :error_tracking_setting - helper_method :tracing_setting feature_category :incident_management urgency :low @@ -60,19 +59,9 @@ module Projects ::Gitlab::Tracking::IncidentManagement.track_from_params( update_params[:incident_management_setting_attributes] ) - track_tracing_external_url end end - def track_tracing_external_url - external_url_previous_change = project&.tracing_setting&.external_url_previous_change - - return unless external_url_previous_change - return unless external_url_previous_change[0].blank? && external_url_previous_change[1].present? - - ::Gitlab::Tracking.event('project:operations:tracing', 'external_url_populated', user: current_user, project: project, namespace: project.namespace) - end - def alerting_params { alerting_setting_attributes: { regenerate_token: true } } end @@ -124,10 +113,6 @@ module Projects project.build_error_tracking_setting end - def tracing_setting - @tracing_setting ||= project.tracing_setting || project.build_tracing_setting - end - def update_params params.require(:project).permit(permitted_project_params) end @@ -147,8 +132,7 @@ module Projects project: [:slug, :name, :organization_slug, :organization_name, :sentry_project_id] ], - grafana_integration_attributes: [:token, :grafana_url, :enabled], - tracing_setting_attributes: [:external_url] + grafana_integration_attributes: [:token, :grafana_url, :enabled] } end end diff --git a/app/controllers/projects/tags/releases_controller.rb b/app/controllers/projects/tags/releases_controller.rb index b852673d82a..adeadf2133e 100644 --- a/app/controllers/projects/tags/releases_controller.rb +++ b/app/controllers/projects/tags/releases_controller.rb @@ -1,5 +1,7 @@ # frozen_string_literal: true +# TODO: remove this file together with FF https://gitlab.com/gitlab-org/gitlab/-/issues/366244 +# also delete view/routes class Projects::Tags::ReleasesController < Projects::ApplicationController # Authorize before_action :require_non_empty_project diff --git a/app/controllers/projects/tags_controller.rb b/app/controllers/projects/tags_controller.rb index 432497850f2..847b1baca10 100644 --- a/app/controllers/projects/tags_controller.rb +++ b/app/controllers/projects/tags_controller.rb @@ -53,7 +53,7 @@ class Projects::TagsController < Projects::ApplicationController return render_404 unless @tag - @release = @project.releases.find_or_initialize_by(tag: @tag.name) + @release = @project.releases.find_by(tag: @tag.name) @commit = @repository.commit(@tag.dereferenced_target) end # rubocop: enable CodeReuse/ActiveRecord diff --git a/app/controllers/projects/tracings_controller.rb b/app/controllers/projects/tracings_controller.rb deleted file mode 100644 index b5c1354c4a9..00000000000 --- a/app/controllers/projects/tracings_controller.rb +++ /dev/null @@ -1,30 +0,0 @@ -# frozen_string_literal: true - -module Projects - class TracingsController < Projects::ApplicationController - content_security_policy do |p| - next if p.directives.blank? - - global_frame_src = p.frame_src - - p.frame_src -> { frame_src_csp_policy(global_frame_src) } - end - - before_action :authorize_update_environment! - - feature_category :tracing - urgency :low - - def show - render_404 unless Feature.enabled?(:monitor_tracing, @project) - end - - private - - def frame_src_csp_policy(global_frame_src) - external_url = @project&.tracing_setting&.external_url - - external_url.presence || global_frame_src - end - end -end diff --git a/app/controllers/projects/tree_controller.rb b/app/controllers/projects/tree_controller.rb index ed14f66847c..ce51cbb6677 100644 --- a/app/controllers/projects/tree_controller.rb +++ b/app/controllers/projects/tree_controller.rb @@ -18,7 +18,6 @@ class Projects::TreeController < Projects::ApplicationController before_action do push_frontend_feature_flag(:lazy_load_commits, @project) - push_frontend_feature_flag(:refactor_blob_viewer, @project) push_frontend_feature_flag(:highlight_js, @project) push_licensed_feature(:file_locks) if @project.licensed_feature_available?(:file_locks) end diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index 1e0ef1ad337..37e472050a0 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -36,7 +36,6 @@ class ProjectsController < Projects::ApplicationController before_action do push_frontend_feature_flag(:lazy_load_commits, @project) - push_frontend_feature_flag(:refactor_blob_viewer, @project) push_frontend_feature_flag(:highlight_js, @project) push_frontend_feature_flag(:increase_page_size_exponentially, @project) push_licensed_feature(:file_locks) if @project.present? && @project.licensed_feature_available?(:file_locks) diff --git a/app/controllers/registrations/welcome_controller.rb b/app/controllers/registrations/welcome_controller.rb index a2b25acae64..4e18e6a3b20 100644 --- a/app/controllers/registrations/welcome_controller.rb +++ b/app/controllers/registrations/welcome_controller.rb @@ -3,6 +3,7 @@ module Registrations class WelcomeController < ApplicationController include OneTrustCSP + include GoogleAnalyticsCSP layout 'minimal' skip_before_action :authenticate_user!, :required_signup_info, :check_two_factor_requirement, only: [:show, :update] diff --git a/app/controllers/registrations_controller.rb b/app/controllers/registrations_controller.rb index 206580d205a..bb16c2d2098 100644 --- a/app/controllers/registrations_controller.rb +++ b/app/controllers/registrations_controller.rb @@ -7,6 +7,7 @@ class RegistrationsController < Devise::RegistrationsController include InvisibleCaptchaOnSignup include OneTrustCSP include BizibleCSP + include GoogleAnalyticsCSP layout 'devise' @@ -220,7 +221,7 @@ class RegistrationsController < Devise::RegistrationsController return unless member - Gitlab::Tracking.event(self.class.name, 'accepted', label: 'invite_email', property: member.id.to_s) + Gitlab::Tracking.event(self.class.name, 'accepted', label: 'invite_email', property: member.id.to_s, user: resource) end def context_user diff --git a/app/controllers/search_controller.rb b/app/controllers/search_controller.rb index 7d251ba555c..7a7e63f5fc4 100644 --- a/app/controllers/search_controller.rb +++ b/app/controllers/search_controller.rb @@ -9,7 +9,7 @@ class SearchController < ApplicationController RESCUE_FROM_TIMEOUT_ACTIONS = [:count, :show, :autocomplete].freeze - track_redis_hll_event :show, name: 'i_search_total' + track_event :show, name: 'i_search_total', destinations: [:redis_hll, :snowplow] around_action :allow_gitaly_ref_name_caching @@ -42,13 +42,19 @@ class SearchController < ApplicationController @sort = params[:sort] || default_sort @search_service = Gitlab::View::Presenter::Factory.new(search_service, current_user: current_user).fabricate! - @scope = @search_service.scope - @without_count = @search_service.without_count? - @show_snippets = @search_service.show_snippets? - @search_results = @search_service.search_results - @search_objects = @search_service.search_objects - @search_highlight = @search_service.search_highlight - @aggregations = @search_service.search_aggregations + + @search_level = @search_service.level + @search_type = search_type + + @global_search_duration_s = Benchmark.realtime do + @scope = @search_service.scope + @without_count = @search_service.without_count? + @show_snippets = @search_service.show_snippets? + @search_results = @search_service.search_results + @search_objects = @search_service.search_objects + @search_highlight = @search_service.search_highlight + @aggregations = @search_service.search_aggregations + end increment_search_counters end @@ -144,7 +150,9 @@ class SearchController < ApplicationController payload[:metadata]['meta.search.filters.state'] = params[:state] payload[:metadata]['meta.search.force_search_results'] = params[:force_search_results] payload[:metadata]['meta.search.project_ids'] = params[:project_ids] - payload[:metadata]['meta.search.search_level'] = params[:search_level] + payload[:metadata]['meta.search.type'] = @search_type if @search_type.present? + payload[:metadata]['meta.search.level'] = @search_level if @search_level.present? + payload[:metadata][:global_search_duration_s] = @global_search_duration_s if @global_search_duration_s.present? if search_service.abuse_detected? payload[:metadata]['abuse.confidence'] = Gitlab::Abuse.confidence(:certain) @@ -203,6 +211,14 @@ class SearchController < ApplicationController render status: :request_timeout end end + + def tracking_namespace_source + search_service.project&.namespace || search_service.group + end + + def search_type + 'basic' + end end SearchController.prepend_mod_with('SearchController') diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb index 9000e9c39de..6195d152f00 100644 --- a/app/controllers/sessions_controller.rb +++ b/app/controllers/sessions_controller.rb @@ -11,6 +11,8 @@ class SessionsController < Devise::SessionsController include Gitlab::Utils::StrongMemoize include OneTrustCSP include BizibleCSP + include VerifiesWithEmail + include GoogleAnalyticsCSP skip_before_action :check_two_factor_requirement, only: [:destroy] skip_before_action :check_password_expiration, only: [:destroy] diff --git a/app/controllers/users/terms_controller.rb b/app/controllers/users/terms_controller.rb index f7eb2aad9dc..f36b140f3a2 100644 --- a/app/controllers/users/terms_controller.rb +++ b/app/controllers/users/terms_controller.rb @@ -4,6 +4,7 @@ module Users class TermsController < ApplicationController include InternalRedirect include OneTrustCSP + include GoogleAnalyticsCSP skip_before_action :authenticate_user!, only: [:index] skip_before_action :enforce_terms! @@ -13,6 +14,10 @@ module Users before_action :terms + before_action only: [:index] do + push_frontend_feature_flag(:gitlab_gtm_datalayer, type: :ops) + end + layout 'terms' feature_category :user_management diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 2799479d922..eaf08cd421b 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -58,7 +58,9 @@ class UsersController < ApplicationController # Get all keys of a user(params[:username]) in a text format # Helpful for sysadmins to put in respective servers def ssh_keys - render plain: user.all_ssh_keys.join("\n") + keys = user.all_ssh_keys.join("\n") + keys << "\n" unless keys.empty? + render plain: keys end def activity @@ -74,7 +76,9 @@ class UsersController < ApplicationController # Get all gpg keys of a user(params[:username]) in a text format def gpg_keys - render plain: user.gpg_keys.select(&:verified?).map(&:key).join("\n") + keys = user.gpg_keys.filter_map { |gpg_key| gpg_key.key if gpg_key.verified? }.join("\n") + keys << "\n" unless keys.empty? + render plain: keys end def groups |