summaryrefslogtreecommitdiff
path: root/app/controllers
diff options
context:
space:
mode:
Diffstat (limited to 'app/controllers')
-rw-r--r--app/controllers/admin/application_settings_controller.rb12
-rw-r--r--app/controllers/admin/dashboard_controller.rb1
-rw-r--r--app/controllers/admin/instance_statistics_controller.rb2
-rw-r--r--app/controllers/admin/integrations_controller.rb4
-rw-r--r--app/controllers/admin/users_controller.rb5
-rw-r--r--app/controllers/application_controller.rb10
-rw-r--r--app/controllers/autocomplete_controller.rb2
-rw-r--r--app/controllers/clusters/clusters_controller.rb2
-rw-r--r--app/controllers/concerns/controller_with_feature_category.rb48
-rw-r--r--app/controllers/concerns/dependency_proxy_access.rb24
-rw-r--r--app/controllers/concerns/integrations_actions.rb2
-rw-r--r--app/controllers/concerns/issuable_actions.rb3
-rw-r--r--app/controllers/concerns/lfs_request.rb24
-rw-r--r--app/controllers/concerns/notes_actions.rb6
-rw-r--r--app/controllers/concerns/routable_actions.rb2
-rw-r--r--app/controllers/concerns/send_file_upload.rb11
-rw-r--r--app/controllers/concerns/sends_blob.rb1
-rw-r--r--app/controllers/concerns/snippets_actions.rb5
-rw-r--r--app/controllers/concerns/wiki_actions.rb15
-rw-r--r--app/controllers/groups/boards_controller.rb3
-rw-r--r--app/controllers/groups/dependency_proxies_controller.rb34
-rw-r--r--app/controllers/groups/dependency_proxy_for_containers_controller.rb63
-rw-r--r--app/controllers/groups/milestones_controller.rb2
-rw-r--r--app/controllers/groups/settings/ci_cd_controller.rb3
-rw-r--r--app/controllers/groups/settings/integrations_controller.rb8
-rw-r--r--app/controllers/groups_controller.rb17
-rw-r--r--app/controllers/import/base_controller.rb8
-rw-r--r--app/controllers/import/bitbucket_controller.rb4
-rw-r--r--app/controllers/import/bitbucket_server_controller.rb4
-rw-r--r--app/controllers/import/bulk_imports_controller.rb40
-rw-r--r--app/controllers/import/github_controller.rb20
-rw-r--r--app/controllers/invites_controller.rb16
-rw-r--r--app/controllers/jwks_controller.rb26
-rw-r--r--app/controllers/profiles/personal_access_tokens_controller.rb8
-rw-r--r--app/controllers/profiles_controller.rb2
-rw-r--r--app/controllers/projects/alert_management_controller.rb1
-rw-r--r--app/controllers/projects/alerting/notifications_controller.rb14
-rw-r--r--app/controllers/projects/autocomplete_sources_controller.rb2
-rw-r--r--app/controllers/projects/avatars_controller.rb2
-rw-r--r--app/controllers/projects/blob_controller.rb2
-rw-r--r--app/controllers/projects/boards_controller.rb3
-rw-r--r--app/controllers/projects/branches_controller.rb13
-rw-r--r--app/controllers/projects/ci/lints_controller.rb20
-rw-r--r--app/controllers/projects/ci/pipeline_editor_controller.rb17
-rw-r--r--app/controllers/projects/imports_controller.rb2
-rw-r--r--app/controllers/projects/issues_controller.rb7
-rw-r--r--app/controllers/projects/jobs_controller.rb3
-rw-r--r--app/controllers/projects/merge_requests/diffs_controller.rb18
-rw-r--r--app/controllers/projects/merge_requests_controller.rb18
-rw-r--r--app/controllers/projects/milestones_controller.rb2
-rw-r--r--app/controllers/projects/notes_controller.rb2
-rw-r--r--app/controllers/projects/pipelines_controller.rb7
-rw-r--r--app/controllers/projects/raw_controller.rb3
-rw-r--r--app/controllers/projects/releases_controller.rb2
-rw-r--r--app/controllers/projects/repositories_controller.rb2
-rw-r--r--app/controllers/projects/runners_controller.rb2
-rw-r--r--app/controllers/projects/services_controller.rb4
-rw-r--r--app/controllers/projects/settings/access_tokens_controller.rb2
-rw-r--r--app/controllers/projects/settings/ci_cd_controller.rb9
-rw-r--r--app/controllers/projects/settings/operations_controller.rb5
-rw-r--r--app/controllers/projects/settings/repository_controller.rb7
-rw-r--r--app/controllers/projects/static_site_editor_controller.rb12
-rw-r--r--app/controllers/projects/tags_controller.rb1
-rw-r--r--app/controllers/projects/templates_controller.rb8
-rw-r--r--app/controllers/projects/terraform_controller.rb16
-rw-r--r--app/controllers/projects_controller.rb32
-rw-r--r--app/controllers/registrations/welcome_controller.rb73
-rw-r--r--app/controllers/registrations_controller.rb88
-rw-r--r--app/controllers/repositories/git_http_client_controller.rb8
-rw-r--r--app/controllers/repositories/lfs_api_controller.rb5
-rw-r--r--app/controllers/repositories/lfs_storage_controller.rb20
-rw-r--r--app/controllers/search_controller.rb37
-rw-r--r--app/controllers/sessions_controller.rb8
-rw-r--r--app/controllers/whats_new_controller.rb23
74 files changed, 601 insertions, 336 deletions
diff --git a/app/controllers/admin/application_settings_controller.rb b/app/controllers/admin/application_settings_controller.rb
index 786ba73a96f..56ec10fa43a 100644
--- a/app/controllers/admin/application_settings_controller.rb
+++ b/app/controllers/admin/application_settings_controller.rb
@@ -53,7 +53,7 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
def integrations
return not_found unless instance_level_integrations?
- @integrations = Service.find_or_initialize_all(Service.for_instance).sort_by(&:title)
+ @integrations = Service.find_or_initialize_all_non_project_specific(Service.for_instance).sort_by(&:title)
end
def update
@@ -216,10 +216,10 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
remove_blank_params_for!(:elasticsearch_aws_secret_access_key, :eks_secret_access_key)
- # TODO Remove domain_blacklist_raw in APIv5 (See https://gitlab.com/gitlab-org/gitlab-foss/issues/67204)
- params.delete(:domain_blacklist_raw) if params[:domain_blacklist_file]
- params.delete(:domain_blacklist_raw) if params[:domain_blacklist]
- params.delete(:domain_whitelist_raw) if params[:domain_whitelist]
+ # TODO Remove domain_denylist_raw in APIv5 (See https://gitlab.com/gitlab-org/gitlab-foss/issues/67204)
+ params.delete(:domain_denylist_raw) if params[:domain_denylist_file]
+ params.delete(:domain_denylist_raw) if params[:domain_denylist]
+ params.delete(:domain_allowlist_raw) if params[:domain_allowlist]
params.require(:application_setting).permit(
visible_application_setting_attributes
@@ -240,7 +240,7 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
*ApplicationSetting.repository_storages_weighted_attributes,
:lets_encrypt_notification_email,
:lets_encrypt_terms_of_service_accepted,
- :domain_blacklist_file,
+ :domain_denylist_file,
:raw_blob_request_limit,
:issues_create_limit,
:default_branch_name,
diff --git a/app/controllers/admin/dashboard_controller.rb b/app/controllers/admin/dashboard_controller.rb
index 7d981d67840..33a8cc4ae42 100644
--- a/app/controllers/admin/dashboard_controller.rb
+++ b/app/controllers/admin/dashboard_controller.rb
@@ -16,6 +16,7 @@ class Admin::DashboardController < Admin::ApplicationController
@groups = Group.order_id_desc.with_route.limit(10)
@notices = Gitlab::ConfigChecker::PumaRuggedChecker.check
@notices += Gitlab::ConfigChecker::ExternalDatabaseChecker.check
+ @redis_versions = [Gitlab::Redis::Queues, Gitlab::Redis::SharedState, Gitlab::Redis::Cache].map(&:version).uniq
end
# rubocop: enable CodeReuse/ActiveRecord
diff --git a/app/controllers/admin/instance_statistics_controller.rb b/app/controllers/admin/instance_statistics_controller.rb
index dfbd704cb0c..05a0a1ce314 100644
--- a/app/controllers/admin/instance_statistics_controller.rb
+++ b/app/controllers/admin/instance_statistics_controller.rb
@@ -13,6 +13,6 @@ class Admin::InstanceStatisticsController < Admin::ApplicationController
end
def check_feature_flag
- render_404 unless Feature.enabled?(:instance_statistics)
+ render_404 unless Feature.enabled?(:instance_statistics, default_enabled: true)
end
end
diff --git a/app/controllers/admin/integrations_controller.rb b/app/controllers/admin/integrations_controller.rb
index 9a1d5a11f7f..aab8705f5cb 100644
--- a/app/controllers/admin/integrations_controller.rb
+++ b/app/controllers/admin/integrations_controller.rb
@@ -8,8 +8,8 @@ class Admin::IntegrationsController < Admin::ApplicationController
private
- def find_or_initialize_integration(name)
- Service.find_or_initialize_integration(name, instance: true)
+ def find_or_initialize_non_project_specific_integration(name)
+ Service.find_or_initialize_non_project_specific_integration(name, instance: true)
end
def integrations_enabled?
diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb
index bd7b69384b2..2d0bb0bfebc 100644
--- a/app/controllers/admin/users_controller.rb
+++ b/app/controllers/admin/users_controller.rb
@@ -6,7 +6,6 @@ class Admin::UsersController < Admin::ApplicationController
before_action :user, except: [:index, :new, :create]
before_action :check_impersonation_availability, only: :impersonate
before_action :ensure_destroy_prerequisites_met, only: [:destroy]
- before_action :check_admin_approval_feature_available!, only: [:approve]
feature_category :users
@@ -298,10 +297,6 @@ class Admin::UsersController < Admin::ApplicationController
def log_impersonation_event
Gitlab::AppLogger.info(_("User %{current_user_username} has started impersonating %{username}") % { current_user_username: current_user.username, username: user.username })
end
-
- def check_admin_approval_feature_available!
- access_denied! unless Feature.enabled?(:admin_approval_for_new_user_signups, default_enabled: true)
- end
end
Admin::UsersController.prepend_if_ee('EE::Admin::UsersController')
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index 05f496c3b99..c38c6abddc1 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -22,7 +22,7 @@ class ApplicationController < ActionController::Base
include Impersonation
include Gitlab::Logging::CloudflareHelper
include Gitlab::Utils::StrongMemoize
- include ControllerWithFeatureCategory
+ include ::Gitlab::WithFeatureCategory
before_action :authenticate_user!, except: [:route_not_found]
before_action :enforce_terms!, if: :should_enforce_terms?
@@ -121,7 +121,7 @@ class ApplicationController < ActionController::Base
end
def route_not_found
- if current_user
+ if current_user || browser.bot.search_engine?
not_found
else
store_location_for(:user, request.fullpath) unless request.xhr?
@@ -266,6 +266,12 @@ class ApplicationController < ActionController::Base
end
end
+ def stream_headers
+ headers['Content-Length'] = nil
+ headers['X-Accel-Buffering'] = 'no' # Disable buffering on Nginx
+ headers['Last-Modified'] = '0' # Prevent buffering via Rack::ETag middleware
+ end
+
def default_headers
headers['X-Frame-Options'] = 'DENY'
headers['X-XSS-Protection'] = '1; mode=block'
diff --git a/app/controllers/autocomplete_controller.rb b/app/controllers/autocomplete_controller.rb
index ac4ee14c6a9..9ee69c7c07f 100644
--- a/app/controllers/autocomplete_controller.rb
+++ b/app/controllers/autocomplete_controller.rb
@@ -53,7 +53,7 @@ class AutocompleteController < ApplicationController
end
def deploy_keys_with_owners
- deploy_keys = DeployKeys::CollectKeysService.new(project, current_user).execute
+ deploy_keys = DeployKey.with_write_access_for_project(project)
render json: DeployKeySerializer.new.represent(deploy_keys, { with_owner: true, user: current_user })
end
diff --git a/app/controllers/clusters/clusters_controller.rb b/app/controllers/clusters/clusters_controller.rb
index 52719e90e04..9800d94964d 100644
--- a/app/controllers/clusters/clusters_controller.rb
+++ b/app/controllers/clusters/clusters_controller.rb
@@ -272,7 +272,7 @@ class Clusters::ClustersController < Clusters::BaseController
end
def aws_role_params
- params.require(:cluster).permit(:role_arn)
+ params.require(:cluster).permit(:role_arn, :region)
end
def generate_gcp_authorize_url
diff --git a/app/controllers/concerns/controller_with_feature_category.rb b/app/controllers/concerns/controller_with_feature_category.rb
deleted file mode 100644
index c1ff9ef2e69..00000000000
--- a/app/controllers/concerns/controller_with_feature_category.rb
+++ /dev/null
@@ -1,48 +0,0 @@
-# frozen_string_literal: true
-
-module ControllerWithFeatureCategory
- extend ActiveSupport::Concern
- include Gitlab::ClassAttributes
-
- class_methods do
- def feature_category(category, actions = [])
- feature_category_configuration[category] ||= []
- feature_category_configuration[category] += actions.map(&:to_s)
-
- validate_config!(feature_category_configuration)
- end
-
- def feature_category_for_action(action)
- category_config = feature_category_configuration.find do |_, actions|
- actions.empty? || actions.include?(action)
- end
-
- category_config&.first || superclass_feature_category_for_action(action)
- end
-
- private
-
- def validate_config!(config)
- empty = config.find { |_, actions| actions.empty? }
- duplicate_actions = config.values.flatten.group_by(&:itself).select { |_, v| v.count > 1 }.keys
-
- if config.length > 1 && empty
- raise ArgumentError, "#{empty.first} is defined for all actions, but other categories are set"
- end
-
- if duplicate_actions.any?
- raise ArgumentError, "Actions have multiple feature categories: #{duplicate_actions.join(', ')}"
- end
- end
-
- def feature_category_configuration
- class_attributes[:feature_category_config] ||= {}
- end
-
- def superclass_feature_category_for_action(action)
- return unless superclass.respond_to?(:feature_category_for_action)
-
- superclass.feature_category_for_action(action)
- end
- end
-end
diff --git a/app/controllers/concerns/dependency_proxy_access.rb b/app/controllers/concerns/dependency_proxy_access.rb
new file mode 100644
index 00000000000..5036d0cfce4
--- /dev/null
+++ b/app/controllers/concerns/dependency_proxy_access.rb
@@ -0,0 +1,24 @@
+# frozen_string_literal: true
+
+module DependencyProxyAccess
+ extend ActiveSupport::Concern
+
+ included do
+ before_action :verify_dependency_proxy_enabled!
+ before_action :authorize_read_dependency_proxy!
+ end
+
+ private
+
+ def verify_dependency_proxy_enabled!
+ render_404 unless group.dependency_proxy_feature_available?
+ end
+
+ def authorize_read_dependency_proxy!
+ access_denied! unless can?(current_user, :read_dependency_proxy, group)
+ end
+
+ def authorize_admin_dependency_proxy!
+ access_denied! unless can?(current_user, :admin_dependency_proxy, group)
+ end
+end
diff --git a/app/controllers/concerns/integrations_actions.rb b/app/controllers/concerns/integrations_actions.rb
index 39f63bbaaec..8e9b038437d 100644
--- a/app/controllers/concerns/integrations_actions.rb
+++ b/app/controllers/concerns/integrations_actions.rb
@@ -52,7 +52,7 @@ module IntegrationsActions
def integration
# Using instance variable `@service` still required as it's used in ServiceParams.
# Should be removed once that is refactored to use `@integration`.
- @integration = @service ||= find_or_initialize_integration(params[:id]) # rubocop:disable Gitlab/ModuleWithInstanceVariables
+ @integration = @service ||= find_or_initialize_non_project_specific_integration(params[:id]) # rubocop:disable Gitlab/ModuleWithInstanceVariables
end
def success_message
diff --git a/app/controllers/concerns/issuable_actions.rb b/app/controllers/concerns/issuable_actions.rb
index a1a2740cde2..3b46a547d47 100644
--- a/app/controllers/concerns/issuable_actions.rb
+++ b/app/controllers/concerns/issuable_actions.rb
@@ -8,9 +8,6 @@ module IssuableActions
before_action :authorize_destroy_issuable!, only: :destroy
before_action :check_destroy_confirmation!, only: :destroy
before_action :authorize_admin_issuable!, only: :bulk_update
- before_action only: :show do
- push_frontend_feature_flag(:scoped_labels, type: :licensed, default_enabled: true)
- end
before_action do
push_frontend_feature_flag(:not_issuable_queries, @project, default_enabled: true)
end
diff --git a/app/controllers/concerns/lfs_request.rb b/app/controllers/concerns/lfs_request.rb
index 2844acea271..bc3fd32759f 100644
--- a/app/controllers/concerns/lfs_request.rb
+++ b/app/controllers/concerns/lfs_request.rb
@@ -1,6 +1,7 @@
# frozen_string_literal: true
# This concern assumes:
+# - a `#container` accessor
# - a `#project` accessor
# - a `#user` accessor
# - a `#authentication_result` accessor
@@ -11,6 +12,7 @@
# - a `#has_authentication_ability?(ability)` method
module LfsRequest
extend ActiveSupport::Concern
+ include Gitlab::Utils::StrongMemoize
CONTENT_TYPE = 'application/vnd.git-lfs+json'
@@ -29,16 +31,19 @@ module LfsRequest
message: _('Git LFS is not enabled on this GitLab server, contact your admin.'),
documentation_url: help_url
},
+ content_type: CONTENT_TYPE,
status: :not_implemented
)
end
def lfs_check_access!
- return render_lfs_not_found unless project
+ return render_lfs_not_found unless container&.lfs_enabled?
return if download_request? && lfs_download_access?
return if upload_request? && lfs_upload_access?
- if project.public? || can?(user, :read_project, project)
+ # Only return a 403 response if the user has download access permission,
+ # otherwise return a 404 to avoid exposing the existence of the container.
+ if lfs_download_access?
lfs_forbidden!
else
render_lfs_not_found
@@ -72,9 +77,9 @@ module LfsRequest
end
def lfs_download_access?
- return false unless project.lfs_enabled?
-
- ci? || lfs_deploy_token? || user_can_download_code? || build_can_download_code? || deploy_token_can_download_code?
+ strong_memoize(:lfs_download_access) do
+ ci? || lfs_deploy_token? || user_can_download_code? || build_can_download_code? || deploy_token_can_download_code?
+ end
end
def deploy_token_can_download_code?
@@ -93,11 +98,12 @@ module LfsRequest
end
def lfs_upload_access?
- return false unless project.lfs_enabled?
- return false unless has_authentication_ability?(:push_code)
- return false if limit_exceeded?
+ strong_memoize(:lfs_upload_access) do
+ next false unless has_authentication_ability?(:push_code)
+ next false if limit_exceeded?
- lfs_deploy_token? || can?(user, :push_code, project)
+ lfs_deploy_token? || can?(user, :push_code, project)
+ end
end
def lfs_deploy_token?
diff --git a/app/controllers/concerns/notes_actions.rb b/app/controllers/concerns/notes_actions.rb
index 7a5b470f366..bfa7a30bc65 100644
--- a/app/controllers/concerns/notes_actions.rb
+++ b/app/controllers/concerns/notes_actions.rb
@@ -31,6 +31,10 @@ module NotesActions
# We know there's more data, so tell the frontend to poll again after 1ms
set_polling_interval_header(interval: 1) if meta[:more]
+ # Only present an ETag for the empty response to ensure pagination works
+ # as expected
+ ::Gitlab::EtagCaching::Middleware.skip!(response) if notes.present?
+
render json: meta.merge(notes: notes)
end
@@ -115,7 +119,7 @@ module NotesActions
end
def gather_some_notes
- paginator = Gitlab::UpdatedNotesPaginator.new(
+ paginator = ::Gitlab::UpdatedNotesPaginator.new(
notes_finder.execute.inc_relations_for_view,
last_fetched_at: last_fetched_at
)
diff --git a/app/controllers/concerns/routable_actions.rb b/app/controllers/concerns/routable_actions.rb
index 1b2e6461dee..bc2e7fba288 100644
--- a/app/controllers/concerns/routable_actions.rb
+++ b/app/controllers/concerns/routable_actions.rb
@@ -51,7 +51,7 @@ module RoutableActions
flash[:notice] = "#{routable.class.to_s.titleize} '#{requested_full_path}' was moved to '#{canonical_path}'. Please update any links and bookmarks that may still have the old path."
end
- redirect_to build_canonical_path(routable)
+ redirect_to build_canonical_path(routable), status: :moved_permanently
end
end
end
diff --git a/app/controllers/concerns/send_file_upload.rb b/app/controllers/concerns/send_file_upload.rb
index 2f06cd84ee5..8b053ef7c59 100644
--- a/app/controllers/concerns/send_file_upload.rb
+++ b/app/controllers/concerns/send_file_upload.rb
@@ -70,16 +70,7 @@ module SendFileUpload
Avatarable::ALLOWED_IMAGE_SCALER_WIDTHS.include?(params[:width]&.to_i)
end
- # We use two separate feature gates to allow image resizing.
- # The first, `:dynamic_image_resizing_requester`, based on the content requester.
- # Enabling it for the user would allow that user to send resizing requests for any avatar.
- # The second, `:dynamic_image_resizing_owner`, based on the content owner.
- # Enabling it for the user would allow anyone to send resizing requests against the mentioned user avatar only.
- # This flag allows us to operate on trusted data only, more in https://gitlab.com/gitlab-org/gitlab/-/issues/241533.
- # Because of this, you need to enable BOTH to serve resized image,
- # as you would need at least one allowed requester and at least one allowed avatar.
def scaling_allowed_by_feature_flags?(file_upload)
- Feature.enabled?(:dynamic_image_resizing_requester, current_user) &&
- Feature.enabled?(:dynamic_image_resizing_owner, file_upload.model)
+ Feature.enabled?(:dynamic_image_resizing, default_enabled: true, type: :ops)
end
end
diff --git a/app/controllers/concerns/sends_blob.rb b/app/controllers/concerns/sends_blob.rb
index 9bba61fda84..381f2eba352 100644
--- a/app/controllers/concerns/sends_blob.rb
+++ b/app/controllers/concerns/sends_blob.rb
@@ -44,7 +44,6 @@ module SendsBlob
Blob::CACHE_TIME
end
- response.etag = blob.id
!stale
end
diff --git a/app/controllers/concerns/snippets_actions.rb b/app/controllers/concerns/snippets_actions.rb
index e4c3df6ccc3..0153ede2821 100644
--- a/app/controllers/concerns/snippets_actions.rb
+++ b/app/controllers/concerns/snippets_actions.rb
@@ -57,11 +57,6 @@ module SnippetsActions
render 'show'
end
- format.json do
- conditionally_expand_blob(blob)
- render_blob_json(blob)
- end
-
format.js do
if @snippet.embeddable?
conditionally_expand_blobs(blobs)
diff --git a/app/controllers/concerns/wiki_actions.rb b/app/controllers/concerns/wiki_actions.rb
index aed109309e3..6abb2e16226 100644
--- a/app/controllers/concerns/wiki_actions.rb
+++ b/app/controllers/concerns/wiki_actions.rb
@@ -103,9 +103,10 @@ module WikiActions
@page = response.payload[:page]
if response.success?
+ flash[:toast] = _('Wiki page was successfully updated.')
+
redirect_to(
- wiki_page_path(wiki, page),
- notice: _('Wiki was successfully updated.')
+ wiki_page_path(wiki, page)
)
else
render 'shared/wikis/edit'
@@ -122,9 +123,10 @@ module WikiActions
@page = response.payload[:page]
if response.success?
+ flash[:toast] = _('Wiki page was successfully created.')
+
redirect_to(
- wiki_page_path(wiki, page),
- notice: _('Wiki was successfully updated.')
+ wiki_page_path(wiki, page)
)
else
render 'shared/wikis/edit'
@@ -169,9 +171,10 @@ module WikiActions
response = WikiPages::DestroyService.new(container: container, current_user: current_user).execute(page)
if response.success?
+ flash[:toast] = _("Wiki page was successfully deleted.")
+
redirect_to wiki_path(wiki),
- status: :found,
- notice: _("Page was successfully deleted")
+ status: :found
else
@error = response
render 'shared/wikis/edit'
diff --git a/app/controllers/groups/boards_controller.rb b/app/controllers/groups/boards_controller.rb
index b971c5783a8..c2d72610c66 100644
--- a/app/controllers/groups/boards_controller.rb
+++ b/app/controllers/groups/boards_controller.rb
@@ -7,9 +7,8 @@ class Groups::BoardsController < Groups::ApplicationController
before_action :authorize_read_board!, only: [:index, :show]
before_action :assign_endpoint_vars
before_action do
- push_frontend_feature_flag(:multi_select_board, default_enabled: true)
push_frontend_feature_flag(:graphql_board_lists, group, default_enabled: false)
- push_frontend_feature_flag(:boards_with_swimlanes, group, default_enabled: false)
+ push_frontend_feature_flag(:boards_with_swimlanes, group, default_enabled: true)
end
feature_category :boards
diff --git a/app/controllers/groups/dependency_proxies_controller.rb b/app/controllers/groups/dependency_proxies_controller.rb
new file mode 100644
index 00000000000..367dbafdd59
--- /dev/null
+++ b/app/controllers/groups/dependency_proxies_controller.rb
@@ -0,0 +1,34 @@
+# frozen_string_literal: true
+
+module Groups
+ class DependencyProxiesController < Groups::ApplicationController
+ include DependencyProxyAccess
+
+ before_action :authorize_admin_dependency_proxy!, only: :update
+ before_action :dependency_proxy
+
+ feature_category :package_registry
+
+ def show
+ @blobs_count = group.dependency_proxy_blobs.count
+ @blobs_total_size = group.dependency_proxy_blobs.total_size
+ end
+
+ def update
+ dependency_proxy.update(dependency_proxy_params)
+
+ redirect_to group_dependency_proxy_path(group)
+ end
+
+ private
+
+ def dependency_proxy
+ @dependency_proxy ||=
+ group.dependency_proxy_setting || group.create_dependency_proxy_setting
+ end
+
+ def dependency_proxy_params
+ params.require(:dependency_proxy_group_setting).permit(:enabled)
+ end
+ end
+end
diff --git a/app/controllers/groups/dependency_proxy_for_containers_controller.rb b/app/controllers/groups/dependency_proxy_for_containers_controller.rb
new file mode 100644
index 00000000000..f46902ef90f
--- /dev/null
+++ b/app/controllers/groups/dependency_proxy_for_containers_controller.rb
@@ -0,0 +1,63 @@
+# frozen_string_literal: true
+
+class Groups::DependencyProxyForContainersController < Groups::ApplicationController
+ include DependencyProxyAccess
+ include SendFileUpload
+
+ before_action :ensure_token_granted!
+ before_action :ensure_feature_enabled!
+
+ attr_reader :token
+
+ feature_category :package_registry
+
+ def manifest
+ result = DependencyProxy::PullManifestService.new(image, tag, token).execute
+
+ if result[:status] == :success
+ render json: result[:manifest]
+ else
+ render status: result[:http_status], json: result[:message]
+ end
+ end
+
+ def blob
+ result = DependencyProxy::FindOrCreateBlobService
+ .new(group, image, token, params[:sha]).execute
+
+ if result[:status] == :success
+ send_upload(result[:blob].file)
+ else
+ head result[:http_status]
+ end
+ end
+
+ private
+
+ def image
+ params[:image]
+ end
+
+ def tag
+ params[:tag]
+ end
+
+ def dependency_proxy
+ @dependency_proxy ||=
+ group.dependency_proxy_setting || group.create_dependency_proxy_setting
+ end
+
+ def ensure_feature_enabled!
+ render_404 unless dependency_proxy.enabled
+ end
+
+ def ensure_token_granted!
+ result = DependencyProxy::RequestTokenService.new(image).execute
+
+ if result[:status] == :success
+ @token = result[:token]
+ else
+ render status: result[:http_status], json: result[:message]
+ end
+ end
+end
diff --git a/app/controllers/groups/milestones_controller.rb b/app/controllers/groups/milestones_controller.rb
index 173a24ceb74..03d41f1dd6d 100644
--- a/app/controllers/groups/milestones_controller.rb
+++ b/app/controllers/groups/milestones_controller.rb
@@ -6,7 +6,7 @@ class Groups::MilestonesController < Groups::ApplicationController
before_action :milestone, only: [:edit, :show, :update, :issues, :merge_requests, :participants, :labels, :destroy]
before_action :authorize_admin_milestones!, only: [:edit, :new, :create, :update, :destroy]
before_action do
- push_frontend_feature_flag(:burnup_charts, @group)
+ push_frontend_feature_flag(:burnup_charts, @group, default_enabled: true)
end
feature_category :issue_tracking
diff --git a/app/controllers/groups/settings/ci_cd_controller.rb b/app/controllers/groups/settings/ci_cd_controller.rb
index 0c72c8a037b..723edc4b7e9 100644
--- a/app/controllers/groups/settings/ci_cd_controller.rb
+++ b/app/controllers/groups/settings/ci_cd_controller.rb
@@ -8,9 +8,6 @@ module Groups
skip_cross_project_access_check :show
before_action :authorize_admin_group!
before_action :authorize_update_max_artifacts_size!, only: [:update]
- before_action do
- push_frontend_feature_flag(:new_variables_ui, @group, default_enabled: true)
- end
before_action :define_variables, only: [:show]
feature_category :continuous_integration
diff --git a/app/controllers/groups/settings/integrations_controller.rb b/app/controllers/groups/settings/integrations_controller.rb
index b089cfdf341..a66372b3571 100644
--- a/app/controllers/groups/settings/integrations_controller.rb
+++ b/app/controllers/groups/settings/integrations_controller.rb
@@ -10,7 +10,7 @@ module Groups
feature_category :integrations
def index
- @integrations = Service.find_or_initialize_all(Service.for_group(group)).sort_by(&:title)
+ @integrations = Service.find_or_initialize_all_non_project_specific(Service.for_group(group)).sort_by(&:title)
end
def edit
@@ -21,12 +21,12 @@ module Groups
private
- def find_or_initialize_integration(name)
- Service.find_or_initialize_integration(name, group_id: group.id)
+ def find_or_initialize_non_project_specific_integration(name)
+ Service.find_or_initialize_non_project_specific_integration(name, group_id: group.id)
end
def integrations_enabled?
- Feature.enabled?(:group_level_integrations, group)
+ Feature.enabled?(:group_level_integrations, group, default_enabled: true)
end
def scoped_edit_integration_path(integration)
diff --git a/app/controllers/groups_controller.rb b/app/controllers/groups_controller.rb
index 6f8dc75f6bd..8d528e123e1 100644
--- a/app/controllers/groups_controller.rb
+++ b/app/controllers/groups_controller.rb
@@ -30,7 +30,6 @@ class GroupsController < Groups::ApplicationController
before_action do
push_frontend_feature_flag(:vue_issuables_list, @group)
- push_frontend_feature_flag(:deployment_filters)
end
before_action do
@@ -133,13 +132,23 @@ class GroupsController < Groups::ApplicationController
def update
if Groups::UpdateService.new(@group, current_user, group_params).execute
- redirect_to edit_group_path(@group, anchor: params[:update_section]), notice: "Group '#{@group.name}' was successfully updated."
+ notice = "Group '#{@group.name}' was successfully updated."
+
+ redirect_to edit_group_origin_location, notice: notice
else
@group.reset
render action: "edit"
end
end
+ def edit_group_origin_location
+ if params.dig(:group, :redirect_target) == 'repository_settings'
+ group_settings_repository_path(@group, anchor: 'js-default-branch-name')
+ else
+ edit_group_path(@group, anchor: params[:update_section])
+ end
+ end
+
def destroy
Groups::DestroyService.new(@group, current_user).async_execute
@@ -181,8 +190,6 @@ class GroupsController < Groups::ApplicationController
end
def unfoldered_environment_names
- return render_404 unless Feature.enabled?(:deployment_filters)
-
respond_to do |format|
format.json do
render json: EnvironmentNamesFinder.new(@group, current_user).execute
@@ -193,6 +200,8 @@ class GroupsController < Groups::ApplicationController
protected
def render_show_html
+ record_experiment_user(:invite_members_empty_group_version_a) if ::Gitlab.com?
+
render 'groups/show', locals: { trial: params[:trial] }
end
diff --git a/app/controllers/import/base_controller.rb b/app/controllers/import/base_controller.rb
index 151ba46e629..87cda723895 100644
--- a/app/controllers/import/base_controller.rb
+++ b/app/controllers/import/base_controller.rb
@@ -48,18 +48,14 @@ class Import::BaseController < ApplicationController
private
- def filter_attribute
- :name
- end
-
def sanitized_filter_param
- @filter ||= sanitize(params[:filter])
+ @filter ||= sanitize(params[:filter])&.downcase
end
def filtered(collection)
return collection unless sanitized_filter_param
- collection.select { |item| item[filter_attribute].include?(sanitized_filter_param) }
+ collection.select { |item| item[:name].to_s.downcase.include?(sanitized_filter_param) }
end
def serialized_provider_repos
diff --git a/app/controllers/import/bitbucket_controller.rb b/app/controllers/import/bitbucket_controller.rb
index 0ffd9ef8bdd..57bd39bbe06 100644
--- a/app/controllers/import/bitbucket_controller.rb
+++ b/app/controllers/import/bitbucket_controller.rb
@@ -132,8 +132,4 @@ class Import::BitbucketController < Import::BaseController
refresh_token: session[:bitbucket_refresh_token]
}
end
-
- def sanitized_filter_param
- @filter ||= sanitize(params[:filter])
- end
end
diff --git a/app/controllers/import/bitbucket_server_controller.rb b/app/controllers/import/bitbucket_server_controller.rb
index bee78cb3283..1846b1e0cec 100644
--- a/app/controllers/import/bitbucket_server_controller.rb
+++ b/app/controllers/import/bitbucket_server_controller.rb
@@ -170,10 +170,6 @@ class Import::BitbucketServerController < Import::BaseController
BitbucketServer::Paginator::PAGE_LENGTH
end
- def sanitized_filter_param
- sanitize(params[:filter])
- end
-
def bitbucket_connection_error(error)
flash[:alert] = _("Unable to connect to server: %{error}") % { error: error }
clear_session_data
diff --git a/app/controllers/import/bulk_imports_controller.rb b/app/controllers/import/bulk_imports_controller.rb
index cb2922c2d47..78f4a0cffca 100644
--- a/app/controllers/import/bulk_imports_controller.rb
+++ b/app/controllers/import/bulk_imports_controller.rb
@@ -6,13 +6,13 @@ class Import::BulkImportsController < ApplicationController
feature_category :importers
- rescue_from Gitlab::BulkImport::Client::ConnectionError, with: :bulk_import_connection_error
+ rescue_from BulkImports::Clients::Http::ConnectionError, with: :bulk_import_connection_error
def configure
- session[access_token_key] = params[access_token_key]&.strip
- session[url_key] = params[url_key]
+ session[access_token_key] = configure_params[access_token_key]&.strip
+ session[url_key] = configure_params[url_key]
- redirect_to status_import_bulk_import_url
+ redirect_to status_import_bulk_imports_url
end
def status
@@ -25,6 +25,12 @@ class Import::BulkImportsController < ApplicationController
end
end
+ def create
+ BulkImportService.new(current_user, create_params, credentials).execute
+
+ render json: :ok
+ end
+
private
def serialized_importable_data
@@ -36,20 +42,33 @@ class Import::BulkImportsController < ApplicationController
end
def importable_data
- client.get('groups', top_level_only: true)
+ client.get('groups', top_level_only: true).parsed_response
end
def client
- @client ||= Gitlab::BulkImport::Client.new(
+ @client ||= BulkImports::Clients::Http.new(
uri: session[url_key],
token: session[access_token_key]
)
end
- def import_params
+ def configure_params
params.permit(access_token_key, url_key)
end
+ def create_params
+ params.permit(:bulk_import, [*bulk_import_params])
+ end
+
+ def bulk_import_params
+ %i[
+ source_type
+ source_full_path
+ destination_name
+ destination_namespace
+ ]
+ end
+
def ensure_group_import_enabled
render_404 unless Feature.enabled?(:bulk_import)
end
@@ -106,4 +125,11 @@ class Import::BulkImportsController < ApplicationController
session[url_key] = nil
session[access_token_key] = nil
end
+
+ def credentials
+ {
+ url: session[url_key],
+ access_token: [access_token_key]
+ }
+ end
end
diff --git a/app/controllers/import/github_controller.rb b/app/controllers/import/github_controller.rb
index a1adc6e062a..8ac93aeb9c0 100644
--- a/app/controllers/import/github_controller.rb
+++ b/app/controllers/import/github_controller.rb
@@ -15,6 +15,7 @@ class Import::GithubController < Import::BaseController
rescue_from OAuthConfigMissingError, with: :missing_oauth_config
rescue_from Octokit::Unauthorized, with: :provider_unauthorized
rescue_from Octokit::TooManyRequests, with: :provider_rate_limit
+ rescue_from Gitlab::GithubImport::RateLimitError, with: :rate_limit_threshold_exceeded
def new
if !ci_cd_only? && github_import_configured? && logged_in_with_provider?
@@ -114,7 +115,7 @@ class Import::GithubController < Import::BaseController
def client_repos
@client_repos ||= if Feature.enabled?(:remove_legacy_github_client)
- filtered(concatenated_repos)
+ concatenated_repos
else
filtered(client.repos)
end
@@ -122,8 +123,15 @@ class Import::GithubController < Import::BaseController
def concatenated_repos
return [] unless client.respond_to?(:each_page)
+ return client.each_page(:repos).flat_map(&:objects) unless sanitized_filter_param
- client.each_page(:repos).flat_map(&:objects)
+ client.search_repos_by_name(sanitized_filter_param).flat_map(&:objects).flat_map(&:items)
+ end
+
+ def sanitized_filter_param
+ super
+
+ @filter = @filter&.tr(' ', '')&.tr(':', '')
end
def oauth_client
@@ -246,12 +254,8 @@ class Import::GithubController < Import::BaseController
{}
end
- def sanitized_filter_param
- @filter ||= sanitize(params[:filter])
- end
-
- def filter_attribute
- :name
+ def rate_limit_threshold_exceeded
+ head :too_many_requests
end
end
diff --git a/app/controllers/invites_controller.rb b/app/controllers/invites_controller.rb
index c7b8486d1c9..26fc1c11f6d 100644
--- a/app/controllers/invites_controller.rb
+++ b/app/controllers/invites_controller.rb
@@ -15,13 +15,11 @@ class InvitesController < ApplicationController
feature_category :authentication_and_authorization
def show
- track_new_user_invite_experiment('opened')
accept if skip_invitation_prompt?
end
def accept
if member.accept_invite!(current_user)
- track_new_user_invite_experiment('accepted')
track_invitation_reminders_experiment('accepted')
redirect_to invite_details[:path], notice: _("You have been granted %{member_human_access} access to %{title} %{name}.") %
{ member_human_access: member.human_access, title: invite_details[:title], name: invite_details[:name] }
@@ -110,25 +108,13 @@ class InvitesController < ApplicationController
end
end
- def track_new_user_invite_experiment(action)
- return unless params[:new_user_invite]
-
- property = params[:new_user_invite] == 'experiment' ? 'experiment_group' : 'control_group'
-
- track_experiment(:invite_email, action, property)
- end
-
def track_invitation_reminders_experiment(action)
return unless Gitlab::Experimentation.enabled?(:invitation_reminders)
property = Gitlab::Experimentation.enabled_for_attribute?(:invitation_reminders, member.invite_email) ? 'experimental_group' : 'control_group'
- track_experiment(:invitation_reminders, action, property)
- end
-
- def track_experiment(experiment_key, action, property)
Gitlab::Tracking.event(
- Gitlab::Experimentation.experiment(experiment_key).tracking_category,
+ Gitlab::Experimentation.experiment(:invitation_reminders).tracking_category,
action,
property: property,
label: Digest::MD5.hexdigest(member.to_global_id.to_s)
diff --git a/app/controllers/jwks_controller.rb b/app/controllers/jwks_controller.rb
new file mode 100644
index 00000000000..e7b839f5590
--- /dev/null
+++ b/app/controllers/jwks_controller.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+class JwksController < ActionController::Base # rubocop:disable Rails/ApplicationController
+ def index
+ render json: { keys: keys }
+ end
+
+ private
+
+ def keys
+ [
+ # We keep openid_connect_signing_key so that we can seamlessly
+ # replace it with ci_jwt_signing_key and remove it on the next release.
+ # TODO: Remove openid_connect_signing_key in 13.7
+ # https://gitlab.com/gitlab-org/gitlab/-/issues/221031
+ Rails.application.secrets.openid_connect_signing_key,
+ Gitlab::CurrentSettings.ci_jwt_signing_key
+ ].compact.map do |key_data|
+ OpenSSL::PKey::RSA.new(key_data)
+ .public_key
+ .to_jwk
+ .slice(:kty, :kid, :e, :n)
+ .merge(use: 'sig', alg: 'RS256')
+ end
+ end
+end
diff --git a/app/controllers/profiles/personal_access_tokens_controller.rb b/app/controllers/profiles/personal_access_tokens_controller.rb
index b005347c43a..a45205c5da7 100644
--- a/app/controllers/profiles/personal_access_tokens_controller.rb
+++ b/app/controllers/profiles/personal_access_tokens_controller.rb
@@ -9,9 +9,13 @@ class Profiles::PersonalAccessTokensController < Profiles::ApplicationController
end
def create
- @personal_access_token = finder.build(personal_access_token_params)
+ result = ::PersonalAccessTokens::CreateService.new(
+ current_user: current_user, target_user: current_user, params: personal_access_token_params
+ ).execute
- if @personal_access_token.save
+ @personal_access_token = result.payload[:personal_access_token]
+
+ if result.success?
PersonalAccessToken.redis_store!(current_user.id, @personal_access_token.token)
redirect_to profile_personal_access_tokens_path, notice: _("Your new personal access token has been created.")
else
diff --git a/app/controllers/profiles_controller.rb b/app/controllers/profiles_controller.rb
index c85c83688a4..afebeafff7c 100644
--- a/app/controllers/profiles_controller.rb
+++ b/app/controllers/profiles_controller.rb
@@ -127,7 +127,7 @@ class ProfilesController < Profiles::ApplicationController
:include_private_contributions,
:timezone,
:job_title,
- status: [:emoji, :message]
+ status: [:emoji, :message, :availability]
)
end
end
diff --git a/app/controllers/projects/alert_management_controller.rb b/app/controllers/projects/alert_management_controller.rb
index 0d0ef9b05cb..8ecf8fadefd 100644
--- a/app/controllers/projects/alert_management_controller.rb
+++ b/app/controllers/projects/alert_management_controller.rb
@@ -10,6 +10,5 @@ class Projects::AlertManagementController < Projects::ApplicationController
def details
@alert_id = params[:id]
- push_frontend_feature_flag(:expose_environment_path_in_alert_details, @project)
end
end
diff --git a/app/controllers/projects/alerting/notifications_controller.rb b/app/controllers/projects/alerting/notifications_controller.rb
index 2241ded2db8..a3f4d784f25 100644
--- a/app/controllers/projects/alerting/notifications_controller.rb
+++ b/app/controllers/projects/alerting/notifications_controller.rb
@@ -14,7 +14,7 @@ module Projects
def create
token = extract_alert_manager_token(request)
- result = notify_service.execute(token)
+ result = notify_service.execute(token, integration)
head result.http_status
end
@@ -45,6 +45,18 @@ module Projects
end
end
+ def integration
+ AlertManagement::HttpIntegrationsFinder.new(
+ project,
+ endpoint_identifier: endpoint_identifier,
+ active: true
+ ).execute.first
+ end
+
+ def endpoint_identifier
+ params[:endpoint_identifier] || AlertManagement::HttpIntegration::LEGACY_IDENTIFIER
+ end
+
def notification_payload
@notification_payload ||= params.permit![:notification]
end
diff --git a/app/controllers/projects/autocomplete_sources_controller.rb b/app/controllers/projects/autocomplete_sources_controller.rb
index e9c533daa80..001967b8bb4 100644
--- a/app/controllers/projects/autocomplete_sources_controller.rb
+++ b/app/controllers/projects/autocomplete_sources_controller.rb
@@ -39,7 +39,7 @@ class Projects::AutocompleteSourcesController < Projects::ApplicationController
private
def autocomplete_service
- @autocomplete_service ||= ::Projects::AutocompleteService.new(@project, current_user)
+ @autocomplete_service ||= ::Projects::AutocompleteService.new(@project, current_user, params)
end
def target
diff --git a/app/controllers/projects/avatars_controller.rb b/app/controllers/projects/avatars_controller.rb
index f228206032d..fb113df137f 100644
--- a/app/controllers/projects/avatars_controller.rb
+++ b/app/controllers/projects/avatars_controller.rb
@@ -3,6 +3,8 @@
class Projects::AvatarsController < Projects::ApplicationController
include SendsBlob
+ skip_before_action :default_cache_headers, only: :show
+
before_action :authorize_admin_project!, only: [:destroy]
feature_category :projects
diff --git a/app/controllers/projects/blob_controller.rb b/app/controllers/projects/blob_controller.rb
index c6251d27b05..02e941db636 100644
--- a/app/controllers/projects/blob_controller.rb
+++ b/app/controllers/projects/blob_controller.rb
@@ -33,7 +33,7 @@ class Projects::BlobController < Projects::ApplicationController
before_action :set_last_commit_sha, only: [:edit, :update]
before_action only: :show do
- push_frontend_experiment(:suggest_pipeline)
+ push_frontend_feature_flag(:suggest_pipeline, default_enabled: true)
push_frontend_feature_flag(:gitlab_ci_yml_preview, @project, default_enabled: false)
end
diff --git a/app/controllers/projects/boards_controller.rb b/app/controllers/projects/boards_controller.rb
index 193352ffa70..fe4502a0e06 100644
--- a/app/controllers/projects/boards_controller.rb
+++ b/app/controllers/projects/boards_controller.rb
@@ -8,8 +8,7 @@ class Projects::BoardsController < Projects::ApplicationController
before_action :authorize_read_board!, only: [:index, :show]
before_action :assign_endpoint_vars
before_action do
- push_frontend_feature_flag(:multi_select_board, default_enabled: true)
- push_frontend_feature_flag(:boards_with_swimlanes, project, default_enabled: false)
+ push_frontend_feature_flag(:boards_with_swimlanes, project, default_enabled: true)
end
feature_category :boards
diff --git a/app/controllers/projects/branches_controller.rb b/app/controllers/projects/branches_controller.rb
index 9124728ee25..cf1efda5d13 100644
--- a/app/controllers/projects/branches_controller.rb
+++ b/app/controllers/projects/branches_controller.rb
@@ -27,7 +27,7 @@ class Projects::BranchesController < Projects::ApplicationController
@refs_pipelines = @project.ci_pipelines.latest_successful_for_refs(@branches.map(&:name))
@merged_branch_names = repository.merged_branch_names(@branches.map(&:name))
- @branch_pipeline_statuses = branch_pipeline_statuses
+ @branch_pipeline_statuses = Ci::CommitStatusesFinder.new(@project, repository, current_user, @branches).execute
# https://gitlab.com/gitlab-org/gitlab/-/issues/22851
Gitlab::GitalyClient.allow_n_plus_1_calls do
@@ -197,15 +197,4 @@ class Projects::BranchesController < Projects::ApplicationController
confidential_issue_project
end
-
- def branch_pipeline_statuses
- latest_commits = @branches.map do |branch|
- [branch.name, repository.commit(branch.dereferenced_target).sha]
- end.to_h
-
- latest_pipelines = project.ci_pipelines.latest_pipeline_per_commit(latest_commits.values)
- latest_commits.transform_values do |commit_sha|
- latest_pipelines[commit_sha]&.detailed_status(current_user)
- end.compact
- end
end
diff --git a/app/controllers/projects/ci/lints_controller.rb b/app/controllers/projects/ci/lints_controller.rb
index 7e900fc6051..9dc3194df85 100644
--- a/app/controllers/projects/ci/lints_controller.rb
+++ b/app/controllers/projects/ci/lints_controller.rb
@@ -2,28 +2,22 @@
class Projects::Ci::LintsController < Projects::ApplicationController
before_action :authorize_create_pipeline!
- before_action do
- push_frontend_feature_flag(:ci_lint_vue, project)
- end
feature_category :pipeline_authoring
+ respond_to :json, only: [:create]
+
def show
end
def create
- @content = params[:content]
- @dry_run = params[:dry_run]
+ content = params[:content]
+ dry_run = params[:dry_run]
- @result = Gitlab::Ci::Lint
+ result = Gitlab::Ci::Lint
.new(project: @project, current_user: current_user)
- .validate(@content, dry_run: @dry_run)
+ .validate(content, dry_run: dry_run)
- respond_to do |format|
- format.html { render :show }
- format.json do
- render json: ::Ci::Lint::ResultSerializer.new.represent(@result)
- end
- end
+ render json: ::Ci::Lint::ResultSerializer.new.represent(result)
end
end
diff --git a/app/controllers/projects/ci/pipeline_editor_controller.rb b/app/controllers/projects/ci/pipeline_editor_controller.rb
new file mode 100644
index 00000000000..c2428270fa6
--- /dev/null
+++ b/app/controllers/projects/ci/pipeline_editor_controller.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+class Projects::Ci::PipelineEditorController < Projects::ApplicationController
+ before_action :check_can_collaborate!
+
+ feature_category :pipeline_authoring
+
+ def show
+ render_404 unless ::Gitlab::Ci::Features.ci_pipeline_editor_page_enabled?(@project)
+ end
+
+ private
+
+ def check_can_collaborate!
+ render_404 unless can_collaborate_with_project?(@project)
+ end
+end
diff --git a/app/controllers/projects/imports_controller.rb b/app/controllers/projects/imports_controller.rb
index 6cdd1c0bc8c..c8528ad6d28 100644
--- a/app/controllers/projects/imports_controller.rb
+++ b/app/controllers/projects/imports_controller.rb
@@ -55,7 +55,7 @@ class Projects::ImportsController < Projects::ApplicationController
end
def require_namespace_project_creation_permission
- render_404 unless current_user.can?(:admin_project, @project) || current_user.can?(:create_projects, @project.namespace)
+ render_404 unless can?(current_user, :admin_project, @project) || can?(current_user, :create_projects, @project.namespace)
end
def redirect_if_progress
diff --git a/app/controllers/projects/issues_controller.rb b/app/controllers/projects/issues_controller.rb
index 9a8965dbeb6..3a1b4f380a2 100644
--- a/app/controllers/projects/issues_controller.rb
+++ b/app/controllers/projects/issues_controller.rb
@@ -44,22 +44,19 @@ class Projects::IssuesController < Projects::ApplicationController
push_frontend_feature_flag(:vue_issuable_sidebar, project.group)
push_frontend_feature_flag(:tribute_autocomplete, @project)
push_frontend_feature_flag(:vue_issuables_list, project)
+ push_frontend_feature_flag(:vue_issue_header, @project, default_enabled: true)
end
before_action only: :show do
real_time_feature_flag = :real_time_issue_sidebar
real_time_enabled = Gitlab::ActionCable::Config.in_app? || Feature.enabled?(real_time_feature_flag, @project)
- gon.push({ features: { real_time_feature_flag.to_s.camelize(:lower) => real_time_enabled } }, true)
+ push_to_gon_features(real_time_feature_flag, real_time_enabled)
record_experiment_user(:invite_members_version_a)
record_experiment_user(:invite_members_version_b)
end
- before_action only: :index do
- push_frontend_feature_flag(:scoped_labels, @project, type: :licensed)
- end
-
around_action :allow_gitaly_ref_name_caching, only: [:discussions]
respond_to :html
diff --git a/app/controllers/projects/jobs_controller.rb b/app/controllers/projects/jobs_controller.rb
index 3ceb60a6aef..07e38c80291 100644
--- a/app/controllers/projects/jobs_controller.rb
+++ b/app/controllers/projects/jobs_controller.rb
@@ -14,6 +14,9 @@ class Projects::JobsController < Projects::ApplicationController
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 do
+ push_frontend_feature_flag(:ci_job_line_links, @project)
+ end
layout 'project'
diff --git a/app/controllers/projects/merge_requests/diffs_controller.rb b/app/controllers/projects/merge_requests/diffs_controller.rb
index 07c38431f0f..7fbeac12644 100644
--- a/app/controllers/projects/merge_requests/diffs_controller.rb
+++ b/app/controllers/projects/merge_requests/diffs_controller.rb
@@ -20,7 +20,10 @@ class Projects::MergeRequests::DiffsController < Projects::MergeRequests::Applic
end
def diffs_batch
- diffs = @compare.diffs_in_batch(params[:page], params[:per_page], diff_options: diff_options)
+ diff_options_hash = diff_options
+ diff_options_hash[:paths] = params[:paths] if params[:paths]
+
+ diffs = @compare.diffs_in_batch(params[:page], params[:per_page], diff_options: diff_options_hash)
positions = @merge_request.note_positions_for_paths(diffs.diff_file_paths, current_user)
environment = @merge_request.environments_for(current_user, latest: true).last
@@ -31,6 +34,7 @@ class Projects::MergeRequests::DiffsController < Projects::MergeRequests::Applic
environment: environment,
merge_request: @merge_request,
diff_view: diff_view,
+ merge_ref_head_diff: render_merge_ref_head_diff?,
pagination_data: diffs.pagination_data
}
@@ -64,7 +68,10 @@ class Projects::MergeRequests::DiffsController < Projects::MergeRequests::Applic
render: ->(partial, locals) { view_to_html_string(partial, locals) }
}
- options = additional_attributes.merge(diff_view: Feature.enabled?(:unified_diff_lines, @merge_request.project, default_enabled: true) ? "inline" : diff_view)
+ options = additional_attributes.merge(
+ diff_view: unified_diff_lines_view_type(@merge_request.project),
+ merge_ref_head_diff: render_merge_ref_head_diff?
+ )
if @merge_request.project.context_commits_enabled?
options[:context_commits] = @merge_request.recent_context_commits
@@ -113,7 +120,7 @@ class Projects::MergeRequests::DiffsController < Projects::MergeRequests::Applic
end
end
- if Gitlab::Utils.to_boolean(params[:diff_head]) && @merge_request.diffable_merge_ref?
+ if render_merge_ref_head_diff?
return CompareService.new(@project, @merge_request.merge_ref_head.sha)
.execute(@project, @merge_request.target_branch)
end
@@ -155,6 +162,10 @@ class Projects::MergeRequests::DiffsController < Projects::MergeRequests::Applic
@notes = prepare_notes_for_rendering(@grouped_diff_discussions.values.flatten.flat_map(&:notes), @merge_request)
end
+ def render_merge_ref_head_diff?
+ Gitlab::Utils.to_boolean(params[:diff_head]) && @merge_request.diffable_merge_ref?
+ end
+
def note_positions
@note_positions ||= Gitlab::Diff::PositionCollection.new(renderable_notes.map(&:position))
end
@@ -173,7 +184,6 @@ class Projects::MergeRequests::DiffsController < Projects::MergeRequests::Applic
end
def update_diff_discussion_positions!
- return unless Feature.enabled?(:merge_red_head_comments_position_on_demand, @merge_request.target_project, default_enabled: true)
return if @merge_request.has_any_diff_note_positions?
Discussions::CaptureDiffNotePositionsService.new(@merge_request).execute
diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb
index 91a041bb35b..f2b41294a85 100644
--- a/app/controllers/projects/merge_requests_controller.rb
+++ b/app/controllers/projects/merge_requests_controller.rb
@@ -12,7 +12,7 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
include SourcegraphDecorator
include DiffHelper
- skip_before_action :merge_request, only: [:index, :bulk_update]
+ skip_before_action :merge_request, only: [:index, :bulk_update, :export_csv]
before_action :apply_diff_view_cookie!, only: [:show]
before_action :whitelist_query_limiting, only: [:assign_related_issues, :update]
before_action :authorize_update_issuable!, only: [:close, :edit, :update, :remove_wip, :sort]
@@ -27,7 +27,7 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
before_action :authenticate_user!, only: [:assign_related_issues]
before_action :check_user_can_push_to_source_branch!, only: [:rebase]
before_action only: [:show] do
- push_frontend_experiment(:suggest_pipeline)
+ push_frontend_feature_flag(:suggest_pipeline, default_enabled: true)
push_frontend_feature_flag(:widget_visibility_polling, @project, default_enabled: true)
push_frontend_feature_flag(:mr_commit_neighbor_nav, @project, default_enabled: true)
push_frontend_feature_flag(:multiline_comments, @project, default_enabled: true)
@@ -37,9 +37,12 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
push_frontend_feature_flag(:hide_jump_to_next_unresolved_in_threads, default_enabled: true)
push_frontend_feature_flag(:merge_request_widget_graphql, @project)
push_frontend_feature_flag(:unified_diff_lines, @project, default_enabled: true)
+ push_frontend_feature_flag(:unified_diff_components, @project)
push_frontend_feature_flag(:highlight_current_diff_row, @project)
push_frontend_feature_flag(:default_merge_ref_for_diffs, @project)
push_frontend_feature_flag(:core_security_mr_widget, @project, default_enabled: true)
+ push_frontend_feature_flag(:remove_resolve_note, @project, default_enabled: true)
+ push_frontend_feature_flag(:test_failure_history, @project)
record_experiment_user(:invite_members_version_a)
record_experiment_user(:invite_members_version_b)
@@ -47,7 +50,6 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
before_action do
push_frontend_feature_flag(:vue_issuable_sidebar, @project.group)
- push_frontend_feature_flag(:deployment_filters)
end
around_action :allow_gitaly_ref_name_caching, only: [:index, :show, :discussions]
@@ -317,6 +319,14 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
super
end
+ def export_csv
+ IssuableExportCsvWorker.perform_async(:merge_request, current_user.id, project.id, finder_options.to_h) # rubocop:disable CodeReuse/Worker
+
+ index_path = project_merge_requests_path(project)
+ message = _('Your CSV export has started. It will be emailed to %{email} when complete.') % { email: current_user.notification_email }
+ redirect_to(index_path, notice: message)
+ end
+
protected
alias_method :subscribable_resource, :merge_request
@@ -471,7 +481,7 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
def endpoint_metadata_url(project, merge_request)
params = request.query_parameters
- params[:view] = cookies[:diff_view] if params[:view].blank? && cookies[:diff_view].present?
+ params[:view] = unified_diff_lines_view_type(project)
if Feature.enabled?(:default_merge_ref_for_diffs, project)
params = params.merge(diff_head: true)
diff --git a/app/controllers/projects/milestones_controller.rb b/app/controllers/projects/milestones_controller.rb
index e6c4af00b29..31189c888b7 100644
--- a/app/controllers/projects/milestones_controller.rb
+++ b/app/controllers/projects/milestones_controller.rb
@@ -7,7 +7,7 @@ class Projects::MilestonesController < Projects::ApplicationController
before_action :check_issuables_available!
before_action :milestone, only: [:edit, :update, :destroy, :show, :issues, :merge_requests, :participants, :labels, :promote]
before_action do
- push_frontend_feature_flag(:burnup_charts, @project)
+ push_frontend_feature_flag(:burnup_charts, @project, default_enabled: true)
end
# Allow read any milestone
diff --git a/app/controllers/projects/notes_controller.rb b/app/controllers/projects/notes_controller.rb
index e50e293a103..77fd7688caf 100644
--- a/app/controllers/projects/notes_controller.rb
+++ b/app/controllers/projects/notes_controller.rb
@@ -60,7 +60,7 @@ class Projects::NotesController < Projects::ApplicationController
def render_json_with_notes_serializer
prepare_notes_for_rendering([note])
- render json: note_serializer.represent(note)
+ render json: note_serializer.represent(note, render_truncated_diff_lines: true)
end
def note
diff --git a/app/controllers/projects/pipelines_controller.rb b/app/controllers/projects/pipelines_controller.rb
index 953dce4d63c..f71a92ee874 100644
--- a/app/controllers/projects/pipelines_controller.rb
+++ b/app/controllers/projects/pipelines_controller.rb
@@ -12,11 +12,11 @@ class Projects::PipelinesController < Projects::ApplicationController
before_action :authorize_create_pipeline!, only: [:new, :create, :config_variables]
before_action :authorize_update_pipeline!, only: [:retry, :cancel]
before_action do
- push_frontend_feature_flag(:filter_pipelines_search, project, default_enabled: true)
push_frontend_feature_flag(:dag_pipeline_tab, project, default_enabled: true)
push_frontend_feature_flag(:pipelines_security_report_summary, project)
- push_frontend_feature_flag(:new_pipeline_form, project)
+ push_frontend_feature_flag(:new_pipeline_form, project, default_enabled: true)
push_frontend_feature_flag(:graphql_pipeline_header, project, type: :development, default_enabled: false)
+ push_frontend_feature_flag(:graphql_pipeline_details, project, type: :development, default_enabled: false)
push_frontend_feature_flag(:new_pipeline_form_prefilled_vars, project, type: :development)
end
before_action :ensure_pipeline, only: [:show]
@@ -194,6 +194,7 @@ class Projects::PipelinesController < Projects::ApplicationController
@counts[:total] = @project.all_pipelines.count(:all)
@counts[:success] = @project.all_pipelines.success.count(:all)
@counts[:failed] = @project.all_pipelines.failed.count(:all)
+ @counts[:total_duration] = @project.all_pipelines.total_duration
end
def test_report
@@ -213,7 +214,7 @@ class Projects::PipelinesController < Projects::ApplicationController
def config_variables
respond_to do |format|
format.json do
- render json: Ci::ListConfigVariablesService.new(@project).execute(params[:sha])
+ render json: Ci::ListConfigVariablesService.new(@project, current_user).execute(params[:sha])
end
end
end
diff --git a/app/controllers/projects/raw_controller.rb b/app/controllers/projects/raw_controller.rb
index a9490c106d4..d8ba7e4f235 100644
--- a/app/controllers/projects/raw_controller.rb
+++ b/app/controllers/projects/raw_controller.rb
@@ -6,13 +6,14 @@ class Projects::RawController < Projects::ApplicationController
include SendsBlob
include StaticObjectExternalStorage
+ skip_before_action :default_cache_headers, only: :show
+
prepend_before_action(only: [:show]) { authenticate_sessionless_user!(:blob) }
before_action :require_non_empty_project
before_action :authorize_download_code!
before_action :show_rate_limit, only: [:show], unless: :external_storage_request?
before_action :assign_ref_vars
- before_action :no_cache_headers, only: [:show]
before_action :redirect_to_external_storage, only: :show, if: :static_objects_external_storage_enabled?
feature_category :source_code_management
diff --git a/app/controllers/projects/releases_controller.rb b/app/controllers/projects/releases_controller.rb
index 4e8260d9e53..a6e795a2b91 100644
--- a/app/controllers/projects/releases_controller.rb
+++ b/app/controllers/projects/releases_controller.rb
@@ -54,7 +54,7 @@ class Projects::ReleasesController < Projects::ApplicationController
end
def sanitized_filepath
- CGI.unescape(params[:filepath])
+ "/#{CGI.unescape(params[:filepath])}"
end
def sanitized_tag_name
diff --git a/app/controllers/projects/repositories_controller.rb b/app/controllers/projects/repositories_controller.rb
index ba3ab52e3af..fb6a09cff65 100644
--- a/app/controllers/projects/repositories_controller.rb
+++ b/app/controllers/projects/repositories_controller.rb
@@ -8,6 +8,8 @@ class Projects::RepositoriesController < Projects::ApplicationController
prepend_before_action(only: [:archive]) { authenticate_sessionless_user!(:archive) }
+ skip_before_action :default_cache_headers, only: :archive
+
# Authorize
before_action :require_non_empty_project, except: :create
before_action :archive_rate_limit!, only: :archive
diff --git a/app/controllers/projects/runners_controller.rb b/app/controllers/projects/runners_controller.rb
index 544074f9840..24fa0894a9c 100644
--- a/app/controllers/projects/runners_controller.rb
+++ b/app/controllers/projects/runners_controller.rb
@@ -52,7 +52,7 @@ class Projects::RunnersController < Projects::ApplicationController
end
def toggle_shared_runners
- if Feature.enabled?(:disable_shared_runners_on_group, default_enabled: true) && !project.shared_runners_enabled && project.group && project.group.shared_runners_setting == 'disabled_and_unoverridable'
+ if !project.shared_runners_enabled && project.group && project.group.shared_runners_setting == 'disabled_and_unoverridable'
return redirect_to project_runners_path(@project), alert: _("Cannot enable shared runners because parent group does not allow it")
end
diff --git a/app/controllers/projects/services_controller.rb b/app/controllers/projects/services_controller.rb
index 93ad549bc50..6ed9f74297d 100644
--- a/app/controllers/projects/services_controller.rb
+++ b/app/controllers/projects/services_controller.rb
@@ -13,6 +13,8 @@ class Projects::ServicesController < Projects::ApplicationController
before_action :redirect_deprecated_prometheus_service, only: [:update]
before_action only: :edit do
push_frontend_feature_flag(:jira_issues_integration, @project, type: :licensed, default_enabled: true)
+ push_frontend_feature_flag(:jira_vulnerabilities_integration, @project, type: :licensed, default_enabled: true)
+ push_frontend_feature_flag(:jira_for_vulnerabilities, @project, type: :development, default_enabled: false)
end
respond_to :html
@@ -70,7 +72,7 @@ class Projects::ServicesController < Projects::ApplicationController
return { error: true, message: s_('Integrations|Connection failed. Please check your settings.'), service_response: result[:message].to_s, test_failed: true }
end
- {}
+ result[:data].presence || {}
rescue Gitlab::HTTP::BlockedUrlError => e
{ error: true, message: s_('Integrations|Connection failed. Please check your settings.'), service_response: e.message, test_failed: true }
end
diff --git a/app/controllers/projects/settings/access_tokens_controller.rb b/app/controllers/projects/settings/access_tokens_controller.rb
index cbd6716fdf7..74350147825 100644
--- a/app/controllers/projects/settings/access_tokens_controller.rb
+++ b/app/controllers/projects/settings/access_tokens_controller.rb
@@ -23,7 +23,7 @@ module Projects
redirect_to namespace_project_settings_access_tokens_path, notice: _("Your new project access token has been created.")
else
- render :index
+ redirect_to namespace_project_settings_access_tokens_path, alert: _("Failed to create new project access token: %{token_response_message}") % { token_response_message: token_response.message }
end
end
diff --git a/app/controllers/projects/settings/ci_cd_controller.rb b/app/controllers/projects/settings/ci_cd_controller.rb
index 2963321f803..f76278a12a4 100644
--- a/app/controllers/projects/settings/ci_cd_controller.rb
+++ b/app/controllers/projects/settings/ci_cd_controller.rb
@@ -5,10 +5,11 @@ module Projects
class CiCdController < Projects::ApplicationController
include RunnerSetupScripts
+ NUMBER_OF_RUNNERS_PER_PAGE = 20
+
before_action :authorize_admin_pipeline!
before_action :define_variables
before_action do
- push_frontend_feature_flag(:new_variables_ui, @project, default_enabled: true)
push_frontend_feature_flag(:ajax_new_deploy_token, @project)
end
@@ -76,7 +77,7 @@ module Projects
[
:runners_token, :builds_enabled, :build_allow_git_fetch,
:build_timeout_human_readable, :build_coverage_regex, :public_builds,
- :auto_cancel_pending_pipelines, :ci_config_path,
+ :auto_cancel_pending_pipelines, :ci_config_path, :auto_rollback_enabled,
auto_devops_attributes: [:id, :domain, :enabled, :deploy_strategy],
ci_cd_settings_attributes: [:default_git_depth, :forward_deployment_enabled]
].tap do |list|
@@ -109,13 +110,13 @@ module Projects
end
def define_runners_variables
- @project_runners = @project.runners.ordered
+ @project_runners = @project.runners.ordered.page(params[:project_page]).per(NUMBER_OF_RUNNERS_PER_PAGE).with_tags
@assignable_runners = current_user
.ci_owned_runners
.assignable_for(project)
.ordered
- .page(params[:page]).per(20)
+ .page(params[:specific_page]).per(NUMBER_OF_RUNNERS_PER_PAGE)
@shared_runners = ::Ci::Runner.instance_type.active
diff --git a/app/controllers/projects/settings/operations_controller.rb b/app/controllers/projects/settings/operations_controller.rb
index c407b15e29f..c9386a2edec 100644
--- a/app/controllers/projects/settings/operations_controller.rb
+++ b/app/controllers/projects/settings/operations_controller.rb
@@ -6,6 +6,11 @@ module Projects
before_action :authorize_admin_operations!
before_action :authorize_read_prometheus_alerts!, only: [:reset_alerting_token]
+ before_action do
+ push_frontend_feature_flag(:http_integrations_list, @project)
+ push_frontend_feature_flag(:multiple_http_integrations_custom_mapping, @project)
+ end
+
respond_to :json, only: [:reset_alerting_token, :reset_pagerduty_token]
helper_method :error_tracking_setting
diff --git a/app/controllers/projects/settings/repository_controller.rb b/app/controllers/projects/settings/repository_controller.rb
index 0994bebb1d0..dd50ab1bc7a 100644
--- a/app/controllers/projects/settings/repository_controller.rb
+++ b/app/controllers/projects/settings/repository_controller.rb
@@ -18,14 +18,13 @@ module Projects
end
def cleanup
- cleanup_params = params.require(:project).permit(:bfg_object_map)
- result = Projects::UpdateService.new(project, current_user, cleanup_params).execute
+ bfg_object_map = params.require(:project).require(:bfg_object_map)
+ result = Projects::CleanupService.enqueue(project, current_user, bfg_object_map)
if result[:status] == :success
- RepositoryCleanupWorker.perform_async(project.id, current_user.id) # rubocop:disable CodeReuse/Worker
flash[:notice] = _('Repository cleanup has started. You will receive an email once the cleanup operation is complete.')
else
- flash[:alert] = _('Failed to upload object map file')
+ flash[:alert] = status.fetch(:message, _('Failed to upload object map file'))
end
redirect_to project_settings_repository_path(project)
diff --git a/app/controllers/projects/static_site_editor_controller.rb b/app/controllers/projects/static_site_editor_controller.rb
index 7e2e32a843f..5c3d9b60877 100644
--- a/app/controllers/projects/static_site_editor_controller.rb
+++ b/app/controllers/projects/static_site_editor_controller.rb
@@ -6,12 +6,16 @@ class Projects::StaticSiteEditorController < Projects::ApplicationController
layout 'fullscreen'
+ content_security_policy do |policy|
+ next if policy.directives.blank?
+
+ frame_src_values = Array.wrap(policy.directives['frame-src']) | ['https://www.youtube.com']
+ policy.frame_src(*frame_src_values)
+ end
+
prepend_before_action :authenticate_user!, only: [:show]
before_action :assign_ref_and_path, only: [:show]
before_action :authorize_edit_tree!, only: [:show]
- before_action do
- push_frontend_feature_flag(:sse_image_uploads)
- end
feature_category :static_site_editor
@@ -47,6 +51,8 @@ class Projects::StaticSiteEditorController < Projects::ApplicationController
payload.transform_values do |value|
if value.is_a?(String) || value.is_a?(Integer)
value
+ elsif value.nil?
+ ''
else
value.to_json
end
diff --git a/app/controllers/projects/tags_controller.rb b/app/controllers/projects/tags_controller.rb
index 1d783241196..94b0473e1f3 100644
--- a/app/controllers/projects/tags_controller.rb
+++ b/app/controllers/projects/tags_controller.rb
@@ -24,6 +24,7 @@ class Projects::TagsController < Projects::ApplicationController
tag_names = @tags.map(&:name)
@tags_pipelines = @project.ci_pipelines.latest_successful_for_refs(tag_names)
@releases = project.releases.where(tag: tag_names)
+ @tag_pipeline_statuses = Ci::CommitStatusesFinder.new(@project, @repository, current_user, @tags).execute
respond_to do |format|
format.html
diff --git a/app/controllers/projects/templates_controller.rb b/app/controllers/projects/templates_controller.rb
index 7ab23e39cf0..f4726638777 100644
--- a/app/controllers/projects/templates_controller.rb
+++ b/app/controllers/projects/templates_controller.rb
@@ -7,6 +7,14 @@ class Projects::TemplatesController < Projects::ApplicationController
feature_category :templates
+ def index
+ templates = @template_type.template_subsets(project)
+
+ respond_to do |format|
+ format.json { render json: templates.to_json }
+ end
+ end
+
def show
template = @template_type.find(params[:key], project)
diff --git a/app/controllers/projects/terraform_controller.rb b/app/controllers/projects/terraform_controller.rb
new file mode 100644
index 00000000000..aef163c98c5
--- /dev/null
+++ b/app/controllers/projects/terraform_controller.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+class Projects::TerraformController < Projects::ApplicationController
+ before_action :authorize_can_read_terraform_state!
+
+ feature_category :infrastructure_as_code
+
+ def index
+ end
+
+ private
+
+ def authorize_can_read_terraform_state!
+ access_denied! unless can?(current_user, :read_terraform_state, project)
+ end
+end
diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb
index 09e7563cefd..c03a820b384 100644
--- a/app/controllers/projects_controller.rb
+++ b/app/controllers/projects_controller.rb
@@ -15,7 +15,7 @@ class ProjectsController < Projects::ApplicationController
around_action :allow_gitaly_ref_name_caching, only: [:index, :show]
before_action :whitelist_query_limiting, only: [:create]
- before_action :authenticate_user!, except: [:index, :show, :activity, :refs, :resolve]
+ before_action :authenticate_user!, except: [:index, :show, :activity, :refs, :resolve, :unfoldered_environment_names]
before_action :redirect_git_extension, only: [:show]
before_action :project, except: [:index, :new, :create, :resolve]
before_action :repository, except: [:index, :new, :create, :resolve]
@@ -317,8 +317,6 @@ class ProjectsController < Projects::ApplicationController
end
def unfoldered_environment_names
- return render_404 unless Feature.enabled?(:deployment_filters)
-
respond_to do |format|
format.json do
render json: EnvironmentNamesFinder.new(@project, current_user).execute
@@ -383,6 +381,20 @@ class ProjectsController < Projects::ApplicationController
.merge(import_url_params)
end
+ def project_feature_attributes
+ %i[
+ builds_access_level
+ issues_access_level
+ forking_access_level
+ merge_requests_access_level
+ repository_access_level
+ snippets_access_level
+ wiki_access_level
+ pages_access_level
+ metrics_dashboard_access_level
+ ]
+ end
+
def project_params_attributes
[
:allow_merge_on_skipped_pipeline,
@@ -420,23 +432,11 @@ class ProjectsController < Projects::ApplicationController
:suggestion_commit_message,
:packages_enabled,
:service_desk_enabled,
-
- project_feature_attributes: %i[
- builds_access_level
- issues_access_level
- forking_access_level
- merge_requests_access_level
- repository_access_level
- snippets_access_level
- wiki_access_level
- pages_access_level
- metrics_dashboard_access_level
- ],
project_setting_attributes: %i[
show_default_award_emojis
squash_option
]
- ]
+ ] + [project_feature_attributes: project_feature_attributes]
end
def project_params_create_attributes
diff --git a/app/controllers/registrations/welcome_controller.rb b/app/controllers/registrations/welcome_controller.rb
new file mode 100644
index 00000000000..5b3f78a92ad
--- /dev/null
+++ b/app/controllers/registrations/welcome_controller.rb
@@ -0,0 +1,73 @@
+# frozen_string_literal: true
+
+module Registrations
+ class WelcomeController < ApplicationController
+ layout 'welcome'
+ skip_before_action :authenticate_user!, :required_signup_info, :check_two_factor_requirement, only: [:show, :update]
+ before_action :require_current_user
+
+ feature_category :authentication_and_authorization
+
+ def show
+ return redirect_to path_for_signed_in_user(current_user) if completed_welcome_step?
+ end
+
+ def update
+ result = ::Users::SignupService.new(current_user, update_params).execute
+
+ if result[:status] == :success
+ process_gitlab_com_tracking
+
+ return redirect_to new_users_sign_up_group_path if experiment_enabled?(:onboarding_issues) && show_onboarding_issues_experiment?
+
+ redirect_to path_for_signed_in_user(current_user)
+ else
+ render :show
+ end
+ end
+
+ private
+
+ def require_current_user
+ return redirect_to new_user_registration_path unless current_user
+ end
+
+ def completed_welcome_step?
+ current_user.role.present? && !current_user.setup_for_company.nil?
+ end
+
+ def process_gitlab_com_tracking
+ return false unless ::Gitlab.com?
+ return false unless show_onboarding_issues_experiment?
+
+ track_experiment_event(:onboarding_issues, 'signed_up')
+ record_experiment_user(:onboarding_issues)
+ end
+
+ def update_params
+ params.require(:user).permit(:role, :setup_for_company)
+ end
+
+ def requires_confirmation?(user)
+ return false if user.confirmed?
+ return false if Feature.enabled?(:soft_email_confirmation)
+
+ true
+ end
+
+ def path_for_signed_in_user(user)
+ return users_almost_there_path if requires_confirmation?(user)
+
+ stored_location_for(user) || dashboard_projects_path
+ end
+
+ def show_onboarding_issues_experiment?
+ !helpers.in_subscription_flow? &&
+ !helpers.in_invitation_flow? &&
+ !helpers.in_oauth_flow? &&
+ !helpers.in_trial_flow?
+ end
+ end
+end
+
+Registrations::WelcomeController.prepend_if_ee('EE::Registrations::WelcomeController')
diff --git a/app/controllers/registrations_controller.rb b/app/controllers/registrations_controller.rb
index b3dc0e986f4..04cb9616cf6 100644
--- a/app/controllers/registrations_controller.rb
+++ b/app/controllers/registrations_controller.rb
@@ -3,26 +3,22 @@
class RegistrationsController < Devise::RegistrationsController
include Recaptcha::Verify
include AcceptsPendingInvitations
- include RecaptchaExperimentHelper
+ include RecaptchaHelper
include InvisibleCaptchaOnSignup
BLOCKED_PENDING_APPROVAL_STATE = 'blocked_pending_approval'.freeze
- layout :choose_layout
+ layout 'devise'
- skip_before_action :required_signup_info, :check_two_factor_requirement, only: [:welcome, :update_registration]
prepend_before_action :check_captcha, only: :create
before_action :whitelist_query_limiting, :ensure_destroy_prerequisites_met, only: [:destroy]
before_action :load_recaptcha, only: :new
+ before_action :set_invite_params, only: :new
feature_category :authentication_and_authorization
def new
- if experiment_enabled?(:signup_flow)
- @resource = build_resource
- else
- redirect_to new_user_session_path(anchor: 'register-pane')
- end
+ @resource = build_resource
end
def create
@@ -32,6 +28,11 @@ class RegistrationsController < Devise::RegistrationsController
super do |new_user|
persist_accepted_terms_if_required(new_user)
set_role_required(new_user)
+
+ if pending_approval?
+ NotificationService.new.new_instance_access_request(new_user)
+ end
+
yield new_user if block_given?
end
@@ -52,31 +53,6 @@ class RegistrationsController < Devise::RegistrationsController
end
end
- def welcome
- return redirect_to new_user_registration_path unless current_user
- return redirect_to path_for_signed_in_user(current_user) if current_user.role.present? && !current_user.setup_for_company.nil?
- end
-
- def update_registration
- return redirect_to new_user_registration_path unless current_user
-
- user_params = params.require(:user).permit(:role, :setup_for_company)
- result = ::Users::SignupService.new(current_user, user_params).execute
-
- if result[:status] == :success
- if ::Gitlab.com? && show_onboarding_issues_experiment?
- track_experiment_event(:onboarding_issues, 'signed_up')
- record_experiment_user(:onboarding_issues)
- end
-
- return redirect_to new_users_sign_up_group_path if experiment_enabled?(:onboarding_issues) && show_onboarding_issues_experiment?
-
- redirect_to path_for_signed_in_user(current_user)
- else
- render :welcome
- end
- end
-
protected
def persist_accepted_terms_if_required(new_user)
@@ -160,6 +136,12 @@ class RegistrationsController < Devise::RegistrationsController
render action: 'new'
end
+ def pending_approval?
+ return false unless Gitlab::CurrentSettings.require_admin_approval_after_user_signup
+
+ resource.persisted? && resource.blocked_pending_approval?
+ end
+
def sign_up_params
params.require(:user).permit(:username, :email, :name, :first_name, :last_name, :password)
end
@@ -180,49 +162,17 @@ class RegistrationsController < Devise::RegistrationsController
Gitlab::QueryLimiting.whitelist('https://gitlab.com/gitlab-org/gitlab-foss/issues/42380')
end
- def path_for_signed_in_user(user)
- if requires_confirmation?(user)
- users_almost_there_path
- else
- stored_location_for(user) || dashboard_projects_path
- end
- end
-
- def requires_confirmation?(user)
- return false if user.confirmed?
- return false if Feature.enabled?(:soft_email_confirmation)
- return false if experiment_enabled?(:signup_flow)
-
- true
- end
-
def load_recaptcha
Gitlab::Recaptcha.load_configurations!
end
- # Part of an experiment to build a new sign up flow. Will be resolved
- # with https://gitlab.com/gitlab-org/growth/engineering/issues/64
- def choose_layout
- if %w(welcome update_registration).include?(action_name) || experiment_enabled?(:signup_flow)
- 'devise_experimental_separate_sign_up_flow'
- else
- 'devise'
- end
- end
-
- def show_onboarding_issues_experiment?
- !helpers.in_subscription_flow? &&
- !helpers.in_invitation_flow? &&
- !helpers.in_oauth_flow? &&
- !helpers.in_trial_flow?
- end
-
def set_user_state
- return unless Feature.enabled?(:admin_approval_for_new_user_signups, default_enabled: true)
return unless Gitlab::CurrentSettings.require_admin_approval_after_user_signup
resource.state = BLOCKED_PENDING_APPROVAL_STATE
end
-end
-RegistrationsController.prepend_if_ee('EE::RegistrationsController')
+ def set_invite_params
+ @invite_email = ActionController::Base.helpers.sanitize(params[:invite_email])
+ end
+end
diff --git a/app/controllers/repositories/git_http_client_controller.rb b/app/controllers/repositories/git_http_client_controller.rb
index de452aa69b7..ec854bd0dde 100644
--- a/app/controllers/repositories/git_http_client_controller.rb
+++ b/app/controllers/repositories/git_http_client_controller.rb
@@ -6,7 +6,7 @@ module Repositories
include KerberosSpnegoHelper
include Gitlab::Utils::StrongMemoize
- attr_reader :authentication_result, :redirected_path, :container
+ attr_reader :authentication_result, :redirected_path
delegate :actor, :authentication_abilities, to: :authentication_result, allow_nil: true
delegate :type, to: :authentication_result, allow_nil: true, prefix: :auth_result
@@ -75,6 +75,12 @@ module Repositories
headers['Www-Authenticate'] = challenges.join("\n") if challenges.any?
end
+ def container
+ parse_repo_path unless defined?(@container)
+
+ @container
+ end
+
def project
parse_repo_path unless defined?(@project)
diff --git a/app/controllers/repositories/lfs_api_controller.rb b/app/controllers/repositories/lfs_api_controller.rb
index 35751a2578f..96185608c09 100644
--- a/app/controllers/repositories/lfs_api_controller.rb
+++ b/app/controllers/repositories/lfs_api_controller.rb
@@ -17,9 +17,9 @@ module Repositories
end
if download_request?
- render json: { objects: download_objects! }
+ render json: { objects: download_objects! }, content_type: LfsRequest::CONTENT_TYPE
elsif upload_request?
- render json: { objects: upload_objects! }
+ render json: { objects: upload_objects! }, content_type: LfsRequest::CONTENT_TYPE
else
raise "Never reached"
end
@@ -31,6 +31,7 @@ module Repositories
message: _('Server supports batch API only, please update your Git LFS client to version 1.0.1 and up.'),
documentation_url: "#{Gitlab.config.gitlab.url}/help"
},
+ content_type: LfsRequest::CONTENT_TYPE,
status: :not_implemented
)
end
diff --git a/app/controllers/repositories/lfs_storage_controller.rb b/app/controllers/repositories/lfs_storage_controller.rb
index 0436b740979..48784842d48 100644
--- a/app/controllers/repositories/lfs_storage_controller.rb
+++ b/app/controllers/repositories/lfs_storage_controller.rb
@@ -29,7 +29,7 @@ module Repositories
def upload_finalize
if store_file!(oid, size)
- head 200
+ head 200, content_type: LfsRequest::CONTENT_TYPE
else
render plain: 'Unprocessable entity', status: :unprocessable_entity
end
@@ -59,10 +59,17 @@ module Repositories
params[:size].to_i
end
+ def uploaded_file
+ params[:file]
+ end
+
# rubocop: disable CodeReuse/ActiveRecord
def store_file!(oid, size)
object = LfsObject.find_by(oid: oid, size: size)
- unless object&.file&.exists?
+
+ if object
+ replace_file!(object) unless object.file&.exists?
+ else
object = create_file!(oid, size)
end
@@ -73,12 +80,19 @@ module Repositories
# rubocop: enable CodeReuse/ActiveRecord
def create_file!(oid, size)
- uploaded_file = params[:file]
return unless uploaded_file.is_a?(UploadedFile)
LfsObject.create!(oid: oid, size: size, file: uploaded_file)
end
+ def replace_file!(lfs_object)
+ raise UploadedFile::InvalidPathError unless uploaded_file.is_a?(UploadedFile)
+
+ Gitlab::AppJsonLogger.info(message: "LFS file replaced because it did not exist", oid: oid, size: size)
+ lfs_object.file = uploaded_file
+ lfs_object.save!
+ end
+
def link_to_project!(object)
return unless object
diff --git a/app/controllers/search_controller.rb b/app/controllers/search_controller.rb
index 0380bc1c548..4b21edc98d5 100644
--- a/app/controllers/search_controller.rb
+++ b/app/controllers/search_controller.rb
@@ -9,6 +9,7 @@ class SearchController < ApplicationController
SCOPE_PRELOAD_METHOD = {
projects: :with_web_entity_associations,
issues: :with_web_entity_associations,
+ merge_requests: :with_web_entity_associations,
epics: :with_web_entity_associations
}.freeze
@@ -35,7 +36,10 @@ class SearchController < ApplicationController
return unless search_term_valid?
+ return if check_single_commit_result?
+
@search_term = params[:search]
+ @sort = params[:sort] || default_sort
@scope = search_service.scope
@show_snippets = search_service.show_snippets?
@@ -47,8 +51,6 @@ class SearchController < ApplicationController
eager_load_user_status if @scope == 'users'
increment_search_counters
-
- check_single_commit_result
end
def count
@@ -81,6 +83,11 @@ class SearchController < ApplicationController
SCOPE_PRELOAD_METHOD[@scope.to_sym]
end
+ # overridden in EE
+ def default_sort
+ 'created_desc'
+ end
+
def search_term_valid?
unless search_service.valid_query_length?
flash[:alert] = t('errors.messages.search_chars_too_long', count: SearchService::SEARCH_CHAR_LIMIT)
@@ -103,14 +110,23 @@ class SearchController < ApplicationController
@search_objects = @search_objects.eager_load(:status) # rubocop:disable CodeReuse/ActiveRecord
end
- def check_single_commit_result
- if @search_results.single_commit_result?
- only_commit = @search_results.objects('commits').first
- query = params[:search].strip.downcase
- found_by_commit_sha = Commit.valid_hash?(query) && only_commit.sha.start_with?(query)
+ def check_single_commit_result?
+ return false if params[:force_search_results]
+ return false unless @project.present?
+ # download_code project policy grants user the read_commit ability
+ return false unless Ability.allowed?(current_user, :download_code, @project)
- redirect_to project_commit_path(@project, only_commit) if found_by_commit_sha
- end
+ query = params[:search].strip.downcase
+ return false unless Commit.valid_hash?(query)
+
+ commit = @project.commit_by(oid: query)
+ return false unless commit.present?
+
+ link = search_path(safe_params.merge(force_search_results: true))
+ flash[:notice] = html_escape(_("You have been redirected to the only result; see the %{a_start}search results%{a_end} instead.")) % { a_start: "<a href=\"#{link}\"><u>".html_safe, a_end: '</u></a>'.html_safe }
+ redirect_to project_commit_path(@project, commit)
+
+ true
end
def increment_search_counters
@@ -130,6 +146,9 @@ class SearchController < ApplicationController
payload[:metadata]['meta.search.project_id'] = params[:project_id]
payload[:metadata]['meta.search.search'] = params[:search]
payload[:metadata]['meta.search.scope'] = params[:scope]
+ payload[:metadata]['meta.search.filters.confidential'] = params[:confidential]
+ payload[:metadata]['meta.search.filters.state'] = params[:state]
+ payload[:metadata]['meta.search.force_search_results'] = params[:force_search_results]
end
def block_anonymous_global_searches
diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb
index 61120c5b7d1..b8842b2efdb 100644
--- a/app/controllers/sessions_controller.rb
+++ b/app/controllers/sessions_controller.rb
@@ -300,13 +300,13 @@ class SessionsController < Devise::SessionsController
def authentication_method
if user_params[:otp_attempt]
- "two-factor"
+ AuthenticationEvent::TWO_FACTOR
elsif user_params[:device_response] && Feature.enabled?(:webauthn)
- "two-factor-via-webauthn-device"
+ AuthenticationEvent::TWO_FACTOR_WEBAUTHN
elsif user_params[:device_response] && !Feature.enabled?(:webauthn)
- "two-factor-via-u2f-device"
+ AuthenticationEvent::TWO_FACTOR_U2F
else
- "standard"
+ AuthenticationEvent::STANDARD
end
end
diff --git a/app/controllers/whats_new_controller.rb b/app/controllers/whats_new_controller.rb
index 7156faa4e49..384c984089a 100644
--- a/app/controllers/whats_new_controller.rb
+++ b/app/controllers/whats_new_controller.rb
@@ -5,14 +5,14 @@ class WhatsNewController < ApplicationController
skip_before_action :authenticate_user!
- before_action :check_feature_flag
+ before_action :check_feature_flag, :check_valid_page_param, :set_pagination_headers
feature_category :navigation
def index
respond_to do |format|
format.js do
- render json: whats_new_most_recent_release_items
+ render json: whats_new_release_items(page: current_page)
end
end
end
@@ -22,4 +22,23 @@ class WhatsNewController < ApplicationController
def check_feature_flag
render_404 unless Feature.enabled?(:whats_new_drawer, current_user)
end
+
+ def check_valid_page_param
+ render_404 if current_page < 1
+ end
+
+ def set_pagination_headers
+ response.set_header('X-Next-Page', next_page)
+ end
+
+ def current_page
+ params[:page]&.to_i || 1
+ end
+
+ def next_page
+ next_page = current_page + 1
+ next_index = next_page - 1
+
+ next_page if whats_new_file_paths[next_index]
+ end
end