diff options
Diffstat (limited to 'lib/api')
118 files changed, 667 insertions, 233 deletions
diff --git a/lib/api/admin/instance_clusters.rb b/lib/api/admin/instance_clusters.rb index d6c212a9886..7163225777a 100644 --- a/lib/api/admin/instance_clusters.rb +++ b/lib/api/admin/instance_clusters.rb @@ -6,6 +6,7 @@ module API include PaginationParams feature_category :kubernetes_management + urgency :low before do authenticated_as_admin! @@ -136,7 +137,7 @@ module API end def ensure_feature_enabled! - not_found! unless Feature.enabled?(:certificate_based_clusters, clusterable_instance, default_enabled: :yaml, type: :ops) + not_found! unless clusterable_instance.certificate_based_clusters_enabled? end end end diff --git a/lib/api/admin/plan_limits.rb b/lib/api/admin/plan_limits.rb index 99be30809d2..7ce70d85d46 100644 --- a/lib/api/admin/plan_limits.rb +++ b/lib/api/admin/plan_limits.rb @@ -35,6 +35,14 @@ module API params do requires :plan_name, type: String, values: Plan.all_plans, desc: 'Name of the plan' + optional :ci_pipeline_size, type: Integer, desc: 'Maximum number of jobs in a single pipeline' + optional :ci_active_jobs, type: Integer, desc: 'Total number of jobs in currently active pipelines' + optional :ci_active_pipelines, type: Integer, desc: 'Maximum number of active pipelines per project' + optional :ci_project_subscriptions, type: Integer, desc: 'Maximum number of pipeline subscriptions to and from a project' + optional :ci_pipeline_schedules, type: Integer, desc: 'Maximum number of pipeline schedules' + optional :ci_needs_size_limit, type: Integer, desc: 'Maximum number of DAG dependencies that a job can have' + optional :ci_registered_group_runners, type: Integer, desc: 'Maximum number of runners registered per group' + optional :ci_registered_project_runners, type: Integer, desc: 'Maximum number of runners registered per project' optional :conan_max_file_size, type: Integer, desc: 'Maximum Conan package file size in bytes' optional :generic_packages_max_file_size, type: Integer, desc: 'Maximum generic package file size in bytes' optional :helm_max_file_size, type: Integer, desc: 'Maximum Helm chart file size in bytes' @@ -43,6 +51,7 @@ module API optional :nuget_max_file_size, type: Integer, desc: 'Maximum NuGet package file size in bytes' optional :pypi_max_file_size, type: Integer, desc: 'Maximum PyPI package file size in bytes' optional :terraform_module_max_file_size, type: Integer, desc: 'Maximum Terraform Module package file size in bytes' + optional :storage_size_limit, type: Integer, desc: 'Maximum storage size for the root namespace in megabytes' end put "application/plan_limits" do params = declared_params(include_missing: false) diff --git a/lib/api/alert_management_alerts.rb b/lib/api/alert_management_alerts.rb index 88230c86247..bbb7e7280c9 100644 --- a/lib/api/alert_management_alerts.rb +++ b/lib/api/alert_management_alerts.rb @@ -3,6 +3,7 @@ module API class AlertManagementAlerts < ::API::Base feature_category :incident_management + urgency :low params do requires :id, type: String, desc: 'The ID of a project' @@ -83,8 +84,6 @@ module API authorize!(:update_alert_management_metric_image, alert) - render_api_error!('Feature not available', 403) unless alert.metric_images_available? - metric_image = alert.metric_images.find_by_id(params[:metric_image_id]) render_api_error!('Metric image not found', 404) unless metric_image @@ -107,8 +106,6 @@ module API authorize!(:destroy_alert_management_metric_image, alert) - render_api_error!('Feature not available', 403) unless alert.metric_images_available? - metric_image = alert.metric_images.find_by_id(params[:metric_image_id]) render_api_error!('Metric image not found', 404) unless metric_image diff --git a/lib/api/api.rb b/lib/api/api.rb index 4dca47efdf2..0d74bc841b1 100644 --- a/lib/api/api.rb +++ b/lib/api/api.rb @@ -175,8 +175,8 @@ module API mount ::API::BulkImports mount ::API::Ci::JobArtifacts mount ::API::Ci::Jobs - mount ::API::Ci::Pipelines mount ::API::Ci::PipelineSchedules + mount ::API::Ci::Pipelines mount ::API::Ci::ResourceGroups mount ::API::Ci::Runner mount ::API::Ci::Runners @@ -184,14 +184,21 @@ module API mount ::API::Ci::Triggers mount ::API::Ci::Variables mount ::API::Clusters::Agents - mount ::API::Commits + mount ::API::Clusters::AgentTokens mount ::API::CommitStatuses + mount ::API::Commits + mount ::API::ComposerPackages + mount ::API::ConanInstancePackages + mount ::API::ConanProjectPackages mount ::API::ContainerRegistryEvent mount ::API::ContainerRepositories + mount ::API::DebianGroupPackages + mount ::API::DebianProjectPackages mount ::API::DependencyProxy mount ::API::DeployKeys mount ::API::DeployTokens mount ::API::Deployments + mount ::API::Discussions mount ::API::Environments mount ::API::ErrorTracking::ClientKeys mount ::API::ErrorTracking::Collector @@ -202,87 +209,79 @@ module API mount ::API::Features mount ::API::Files mount ::API::FreezePeriods + mount ::API::GenericPackages mount ::API::Geo + mount ::API::GoProxy mount ::API::GroupAvatar mount ::API::GroupBoards mount ::API::GroupClusters + mount ::API::GroupContainerRepositories + mount ::API::GroupDebianDistributions mount ::API::GroupExport mount ::API::GroupImport mount ::API::GroupLabels mount ::API::GroupMilestones - mount ::API::Groups - mount ::API::GroupContainerRepositories - mount ::API::GroupDebianDistributions + mount ::API::GroupPackages mount ::API::GroupVariables + mount ::API::Groups + mount ::API::HelmPackages mount ::API::ImportBitbucketServer mount ::API::ImportGithub - mount ::API::IssueLinks + mount ::API::Integrations + mount ::API::Integrations::JiraConnect::Subscriptions mount ::API::Invitations + mount ::API::IssueLinks mount ::API::Issues mount ::API::Keys mount ::API::Labels mount ::API::Lint mount ::API::Markdown + mount ::API::MavenPackages mount ::API::Members + mount ::API::MergeRequestApprovals mount ::API::MergeRequestDiffs mount ::API::MergeRequests - mount ::API::MergeRequestApprovals mount ::API::Metrics::Dashboard::Annotations mount ::API::Metrics::UserStarredDashboards mount ::API::Namespaces mount ::API::Notes - mount ::API::Discussions - mount ::API::ResourceLabelEvents - mount ::API::ResourceMilestoneEvents - mount ::API::ResourceStateEvents mount ::API::NotificationSettings - mount ::API::ProjectPackages - mount ::API::GroupPackages - mount ::API::PackageFiles - mount ::API::NugetProjectPackages - mount ::API::NugetGroupPackages - mount ::API::PypiPackages - mount ::API::ComposerPackages - mount ::API::ConanProjectPackages - mount ::API::ConanInstancePackages - mount ::API::DebianGroupPackages - mount ::API::DebianProjectPackages - mount ::API::MavenPackages - mount ::API::NpmProjectPackages mount ::API::NpmInstancePackages - mount ::API::GenericPackages - mount ::API::GoProxy - mount ::API::HelmPackages + mount ::API::NpmProjectPackages + mount ::API::NugetGroupPackages + mount ::API::NugetProjectPackages + mount ::API::PackageFiles mount ::API::Pages mount ::API::PagesDomains + mount ::API::PersonalAccessTokens mount ::API::ProjectClusters mount ::API::ProjectContainerRepositories mount ::API::ProjectDebianDistributions mount ::API::ProjectEvents mount ::API::ProjectExport - mount ::API::ProjectImport mount ::API::ProjectHooks + mount ::API::ProjectImport mount ::API::ProjectMilestones + mount ::API::ProjectPackages mount ::API::ProjectRepositoryStorageMoves - mount ::API::Projects mount ::API::ProjectSnapshots mount ::API::ProjectSnippets mount ::API::ProjectStatistics mount ::API::ProjectTemplates - mount ::API::Terraform::State - mount ::API::Terraform::StateVersion - mount ::API::Terraform::Modules::V1::Packages - mount ::API::PersonalAccessTokens + mount ::API::Projects mount ::API::ProtectedBranches mount ::API::ProtectedTags - mount ::API::Releases + mount ::API::PypiPackages mount ::API::Release::Links + mount ::API::Releases mount ::API::RemoteMirrors mount ::API::Repositories mount ::API::ResourceAccessTokens + mount ::API::ResourceLabelEvents + mount ::API::ResourceMilestoneEvents + mount ::API::ResourceStateEvents mount ::API::RubygemPackages mount ::API::Search - mount ::API::Integrations mount ::API::Settings mount ::API::SidekiqMetrics mount ::API::SnippetRepositoryStorageMoves @@ -294,12 +293,15 @@ module API mount ::API::SystemHooks mount ::API::Tags mount ::API::Templates + mount ::API::Terraform::Modules::V1::Packages + mount ::API::Terraform::State + mount ::API::Terraform::StateVersion mount ::API::Todos mount ::API::Topics mount ::API::Unleash mount ::API::UsageData - mount ::API::UsageDataQueries mount ::API::UsageDataNonSqlMetrics + mount ::API::UsageDataQueries mount ::API::UserCounts mount ::API::Users mount ::API::Version diff --git a/lib/api/avatar.rb b/lib/api/avatar.rb index a42d89ddf83..bd9fb37e18b 100644 --- a/lib/api/avatar.rb +++ b/lib/api/avatar.rb @@ -3,6 +3,7 @@ module API class Avatar < ::API::Base feature_category :users + urgency :high resource :avatar do desc 'Return avatar url for a user' do diff --git a/lib/api/badges.rb b/lib/api/badges.rb index d7c850c2f40..68095fb2975 100644 --- a/lib/api/badges.rb +++ b/lib/api/badges.rb @@ -32,7 +32,7 @@ module API params do use :pagination end - get ":id/badges" do + get ":id/badges", urgency: :default do source = find_source(source_type, params[:id]) badges = source.badges @@ -72,7 +72,10 @@ module API params do requires :badge_id, type: Integer, desc: 'The badge ID' end - get ":id/badges/:badge_id" do + # TODO: Set PUT /projects/:id/badges/:badge_id to low urgency and GET to default urgency + # after different urgencies are supported for different HTTP verbs. + # See https://gitlab.com/gitlab-com/gl-infra/scalability/-/issues/1670 + get ":id/badges/:badge_id", urgency: :low do source = find_source(source_type, params[:id]) badge = find_badge(source) @@ -88,7 +91,7 @@ module API requires :image_url, type: String, desc: 'URL of the badge image' optional :name, type: String, desc: 'Name for the badge' end - post ":id/badges" do + post ":id/badges", urgency: :default do source = find_source_if_admin(source_type) badge = ::Badges::CreateService.new(declared_params(include_missing: false)).execute(source) diff --git a/lib/api/boards.rb b/lib/api/boards.rb index 56633c07774..6e3005ce676 100644 --- a/lib/api/boards.rb +++ b/lib/api/boards.rb @@ -8,6 +8,7 @@ module API prepend_mod_with('API::BoardsResponses') # rubocop: disable Cop/InjectEnterpriseEditionModule feature_category :team_planning + urgency :low before { authenticate! } diff --git a/lib/api/branches.rb b/lib/api/branches.rb index a2c9020ac84..b8444351029 100644 --- a/lib/api/branches.rb +++ b/lib/api/branches.rb @@ -52,7 +52,7 @@ module API merged_branch_names = repository.merged_branch_names(branches.map(&:name)) - if Feature.enabled?(:api_caching_branches, user_project, type: :development, default_enabled: :yaml) + if Feature.enabled?(:api_caching_branches, user_project, type: :development) present_cached( branches, with: Entities::Branch, diff --git a/lib/api/bulk_imports.rb b/lib/api/bulk_imports.rb index 53967e0af5d..766e05eca23 100644 --- a/lib/api/bulk_imports.rb +++ b/lib/api/bulk_imports.rb @@ -5,6 +5,7 @@ module API include PaginationParams feature_category :importers + urgency :low helpers do def bulk_imports diff --git a/lib/api/ci/helpers/runner.rb b/lib/api/ci/helpers/runner.rb index 173cfc9a59a..72e36d95dc5 100644 --- a/lib/api/ci/helpers/runner.rb +++ b/lib/api/ci/helpers/runner.rb @@ -53,7 +53,7 @@ module API # https://gitlab.com/gitlab-org/gitlab/-/issues/327703 forbidden! unless job - forbidden! unless job_token_valid?(job) + forbidden! unless job.valid_token?(job_token) forbidden!('Project has been deleted!') if job.project.nil? || job.project.pending_delete? forbidden!('Job has been erased!') if job.erased? @@ -77,6 +77,12 @@ module API job end + def authenticate_job_via_dependent_job! + forbidden! unless current_authenticated_job + forbidden! unless current_job + forbidden! unless can?(current_authenticated_job.user, :read_build, current_job) + end + def current_job id = params[:id] @@ -91,9 +97,28 @@ module API end end - def job_token_valid?(job) - token = (params[JOB_TOKEN_PARAM] || env[JOB_TOKEN_HEADER]).to_s - token && job.valid_token?(token) + # TODO: Replace this with `#current_authenticated_job from API::Helpers` + # after the feature flag `ci_authenticate_running_job_token_for_artifacts` + # is removed. + # + # For the time being, this needs to be overridden because the API + # GET api/v4/jobs/:id/artifacts + # needs to allow requests using token whose job is not running. + # + # https://gitlab.com/gitlab-org/gitlab/-/merge_requests/83713#note_942368526 + def current_authenticated_job + strong_memoize(:current_authenticated_job) do + ::Ci::AuthJobFinder.new(token: job_token).execute + end + end + + # The token used by runner to authenticate a request. + # In most cases, the runner uses the token belonging to the requested job. + # However, when requesting for job artifacts, the runner would use + # the token that belongs to downstream jobs that depend on the job that owns + # the artifacts. + def job_token + @job_token ||= (params[JOB_TOKEN_PARAM] || env[JOB_TOKEN_HEADER]).to_s end def job_forbidden!(job, reason) @@ -111,11 +136,19 @@ module API # noop: overridden in EE end + def log_artifact_size(artifact) + Gitlab::ApplicationContext.push(artifact: artifact) + end + private def get_runner_config_from_request { config: attributes_for_keys(%w(gpus), params.dig('info', 'config')) } end + + def request_using_running_job_token? + current_job.present? && current_authenticated_job.present? && current_job != current_authenticated_job + end end end end diff --git a/lib/api/ci/jobs.rb b/lib/api/ci/jobs.rb index 86897eb61ae..04999b5fb44 100644 --- a/lib/api/ci/jobs.rb +++ b/lib/api/ci/jobs.rb @@ -190,7 +190,7 @@ module API detail 'Retrieves a list of agents for the given job token' end route_setting :authentication, job_token_allowed: true - get '/allowed_agents', feature_category: :kubernetes_management do + get '/allowed_agents', urgency: :low, feature_category: :kubernetes_management do validate_current_authenticated_job status 200 diff --git a/lib/api/ci/pipeline_schedules.rb b/lib/api/ci/pipeline_schedules.rb index 6030fe86f00..4b522f37524 100644 --- a/lib/api/ci/pipeline_schedules.rb +++ b/lib/api/ci/pipeline_schedules.rb @@ -8,6 +8,7 @@ module API before { authenticate! } feature_category :continuous_integration + urgency :low params do requires :id, type: String, desc: 'The ID of a project' diff --git a/lib/api/ci/pipelines.rb b/lib/api/ci/pipelines.rb index 8d2c58dabdf..4253a9eb4d7 100644 --- a/lib/api/ci/pipelines.rb +++ b/lib/api/ci/pipelines.rb @@ -51,7 +51,7 @@ module API desc: 'Sort pipelines' optional :source, type: String, values: ::Ci::Pipeline.sources.keys end - get ':id/pipelines', feature_category: :continuous_integration do + get ':id/pipelines', urgency: :low, feature_category: :continuous_integration do authorize! :read_pipeline, user_project authorize! :read_build, user_project @@ -67,7 +67,7 @@ module API requires :ref, type: String, desc: 'Reference' optional :variables, Array, desc: 'Array of variables available in the pipeline' end - post ':id/pipeline', feature_category: :continuous_integration do + post ':id/pipeline', urgency: :low, feature_category: :continuous_integration do Gitlab::QueryLimiting.disable!('https://gitlab.com/gitlab-org/gitlab/-/issues/20711') authorize! :create_pipeline, user_project @@ -94,7 +94,7 @@ module API params do optional :ref, type: String, desc: 'branch ref of pipeline' end - get ':id/pipelines/latest', feature_category: :continuous_integration do + get ':id/pipelines/latest', urgency: :low, feature_category: :continuous_integration do authorize! :read_pipeline, latest_pipeline present latest_pipeline, with: Entities::Ci::Pipeline @@ -107,7 +107,7 @@ module API params do requires :pipeline_id, type: Integer, desc: 'The pipeline ID' end - get ':id/pipelines/:pipeline_id', feature_category: :continuous_integration do + get ':id/pipelines/:pipeline_id', urgency: :low, feature_category: :continuous_integration do authorize! :read_pipeline, pipeline present pipeline, with: Entities::Ci::Pipeline @@ -205,7 +205,7 @@ module API params do requires :pipeline_id, type: Integer, desc: 'The pipeline ID' end - delete ':id/pipelines/:pipeline_id', feature_category: :continuous_integration do + delete ':id/pipelines/:pipeline_id', urgency: :low, feature_category: :continuous_integration do authorize! :destroy_pipeline, pipeline destroy_conditionally!(pipeline) do @@ -220,7 +220,7 @@ module API params do requires :pipeline_id, type: Integer, desc: 'The pipeline ID' end - post ':id/pipelines/:pipeline_id/retry', feature_category: :continuous_integration do + post ':id/pipelines/:pipeline_id/retry', urgency: :low, feature_category: :continuous_integration do authorize! :update_pipeline, pipeline response = pipeline.retry_failed(current_user) @@ -239,7 +239,7 @@ module API params do requires :pipeline_id, type: Integer, desc: 'The pipeline ID' end - post ':id/pipelines/:pipeline_id/cancel', feature_category: :continuous_integration do + post ':id/pipelines/:pipeline_id/cancel', urgency: :low, feature_category: :continuous_integration do authorize! :update_pipeline, pipeline pipeline.cancel_running diff --git a/lib/api/ci/resource_groups.rb b/lib/api/ci/resource_groups.rb index 616bec499d4..e3fd887475a 100644 --- a/lib/api/ci/resource_groups.rb +++ b/lib/api/ci/resource_groups.rb @@ -3,14 +3,29 @@ module API module Ci class ResourceGroups < ::API::Base + include PaginationParams + before { authenticate! } feature_category :continuous_delivery + urgency :low params do requires :id, type: String, desc: 'The ID of a project' end resource :projects, requirements: ::API::API::NAMESPACE_OR_PROJECT_REQUIREMENTS do + desc 'Get all resource groups for this project' do + success Entities::Ci::ResourceGroup + end + params do + use :pagination + end + get ':id/resource_groups' do + authorize! :read_resource_group, user_project + + present paginate(user_project.resource_groups), with: Entities::Ci::ResourceGroup + end + desc 'Get a single resource group' do success Entities::Ci::ResourceGroup end diff --git a/lib/api/ci/runner.rb b/lib/api/ci/runner.rb index 0e3b295396b..4381309fb9e 100644 --- a/lib/api/ci/runner.rb +++ b/lib/api/ci/runner.rb @@ -29,7 +29,7 @@ module API mutually_exclusive :maintainer_note, :maintainer_note mutually_exclusive :active, :paused end - post '/', feature_category: :runner do + post '/', urgency: :low, feature_category: :runner do attributes = attributes_for_keys(%i[description maintainer_note maintenance_note active paused locked run_untagged tag_list access_level maximum_timeout]) .merge(get_runner_details_from_request) @@ -54,7 +54,7 @@ module API params do requires :token, type: String, desc: %q(Runner's authentication token) end - delete '/', feature_category: :runner do + delete '/', urgency: :low, feature_category: :runner do authenticate_runner! destroy_conditionally!(current_runner) { ::Ci::Runners::UnregisterRunnerService.new(current_runner, params[:token]).execute } @@ -66,7 +66,7 @@ module API params do requires :token, type: String, desc: %q(Runner's authentication token) end - post '/verify', feature_category: :runner do + post '/verify', urgency: :low, feature_category: :runner do authenticate_runner! status 200 body "200" @@ -78,7 +78,7 @@ module API params do requires :token, type: String, desc: 'The current authentication token of the runner' end - post '/reset_authentication_token', feature_category: :runner do + post '/reset_authentication_token', urgency: :low, feature_category: :runner do authenticate_runner! current_runner.reset_token! @@ -212,7 +212,7 @@ module API requires :id, type: Integer, desc: %q(Job's ID) optional :token, type: String, desc: %q(Job's authentication token) end - patch '/:id/trace', urgency: :default, feature_category: :continuous_integration do + patch '/:id/trace', urgency: :low, feature_category: :continuous_integration do job = authenticate_job!(heartbeat_runner: true) error!('400 Missing header Content-Range', 400) unless request.headers.key?('Content-Range') @@ -305,6 +305,7 @@ module API result = ::Ci::JobArtifacts::CreateService.new(job).execute(artifacts, params, metadata_file: metadata) if result[:status] == :success + log_artifact_size(result[:artifact]) status :created body "201" else @@ -323,9 +324,13 @@ module API optional :direct_download, default: false, type: Boolean, desc: %q(Perform direct download from remote storage instead of proxying artifacts) end get '/:id/artifacts', feature_category: :build_artifacts do - job = authenticate_job!(require_running: false) + if request_using_running_job_token? + authenticate_job_via_dependent_job! + else + authenticate_job!(require_running: false) + end - present_carrierwave_file!(job.artifacts_file, supports_direct_download: params[:direct_download]) + present_carrierwave_file!(current_job.artifacts_file, supports_direct_download: params[:direct_download]) end end end diff --git a/lib/api/ci/runners.rb b/lib/api/ci/runners.rb index 3c9e887e751..7863cfd1e79 100644 --- a/lib/api/ci/runners.rb +++ b/lib/api/ci/runners.rb @@ -8,6 +8,7 @@ module API before { authenticate! } feature_category :runner + urgency :low resource :runners do desc 'Get runners available for user' do diff --git a/lib/api/ci/secure_files.rb b/lib/api/ci/secure_files.rb index ee39bdfd90c..6c7f502b428 100644 --- a/lib/api/ci/secure_files.rb +++ b/lib/api/ci/secure_files.rb @@ -62,13 +62,11 @@ module API params do requires :name, type: String, desc: 'The name of the file' requires :file, types: [Rack::Multipart::UploadedFile, ::API::Validations::Types::WorkhorseFile], desc: 'The secure file to be uploaded' - optional :permissions, type: String, desc: 'The file permissions', default: 'read_only', values: %w[read_only read_write execute] end route_setting :authentication, basic_auth_personal_access_token: true, job_token_allowed: true post ':id/secure_files' do secure_file = user_project.secure_files.new( - name: params[:name], - permissions: params[:permissions] || :read_only + name: params[:name] ) secure_file.file = params[:file] @@ -96,11 +94,11 @@ module API helpers do def feature_flag_enabled? - service_unavailable! unless Feature.enabled?(:ci_secure_files, user_project, default_enabled: :yaml) + service_unavailable! unless Feature.enabled?(:ci_secure_files, user_project) end def read_only_feature_flag_enabled? - service_unavailable! if Feature.enabled?(:ci_secure_files_read_only, user_project, type: :ops, default_enabled: :yaml) + service_unavailable! if Feature.enabled?(:ci_secure_files_read_only, user_project, type: :ops) end end end diff --git a/lib/api/ci/triggers.rb b/lib/api/ci/triggers.rb index ae89b475ef8..c49f1c9e9e1 100644 --- a/lib/api/ci/triggers.rb +++ b/lib/api/ci/triggers.rb @@ -8,6 +8,7 @@ module API HTTP_GITLAB_EVENT_HEADER = "HTTP_#{::Gitlab::WebHooks::GITLAB_EVENT_HEADER}".underscore.upcase feature_category :continuous_integration + urgency :low params do requires :id, type: String, desc: 'The ID of a project' diff --git a/lib/api/ci/variables.rb b/lib/api/ci/variables.rb index ec9951aba0d..f9707960b9d 100644 --- a/lib/api/ci/variables.rb +++ b/lib/api/ci/variables.rb @@ -35,7 +35,7 @@ module API requires :key, type: String, desc: 'The key of the variable' end # rubocop: disable CodeReuse/ActiveRecord - get ':id/variables/:key' do + get ':id/variables/:key', urgency: :low do variable = find_variable(user_project, params) not_found!('Variable') unless variable diff --git a/lib/api/clusters/agent_tokens.rb b/lib/api/clusters/agent_tokens.rb new file mode 100644 index 00000000000..1e52790f26b --- /dev/null +++ b/lib/api/clusters/agent_tokens.rb @@ -0,0 +1,98 @@ +# frozen_string_literal: true + +module API + module Clusters + class AgentTokens < ::API::Base + include PaginationParams + + before { authenticate! } + + feature_category :kubernetes_management + + params do + requires :id, type: String, desc: 'The ID of a project' + end + resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do + params do + requires :agent_id, type: Integer, desc: 'The ID of an agent' + end + resource ':id/cluster_agents/:agent_id' do + resource :tokens do + desc 'List agent tokens' do + detail 'This feature was introduced in GitLab 15.0.' + success Entities::Clusters::AgentTokenBasic + end + params do + use :pagination + end + get do + authorize! :read_cluster, user_project + + agent = user_project.cluster_agents.find(params[:agent_id]) + + present paginate(agent.agent_tokens), with: Entities::Clusters::AgentTokenBasic + end + + desc 'Get a single agent token' do + detail 'This feature was introduced in GitLab 15.0.' + success Entities::Clusters::AgentToken + end + params do + requires :token_id, type: Integer, desc: 'The ID of the agent token' + end + get ':token_id' do + authorize! :read_cluster, user_project + + agent = user_project.cluster_agents.find(params[:agent_id]) + token = agent.agent_tokens.find(params[:token_id]) + + present token, with: Entities::Clusters::AgentToken + end + + desc 'Create an agent token' do + detail 'This feature was introduced in GitLab 15.0.' + success Entities::Clusters::AgentTokenWithToken + end + params do + requires :name, type: String, desc: 'The name for the token' + optional :description, type: String, desc: 'The description for the token' + end + post do + authorize! :create_cluster, user_project + + token_params = declared_params(include_missing: false) + + agent = user_project.cluster_agents.find(params[:agent_id]) + + result = ::Clusters::AgentTokens::CreateService.new( + container: agent.project, current_user: current_user, params: token_params.merge(agent_id: agent.id) + ).execute + + bad_request!(result[:message]) if result[:status] == :error + + present result[:token], with: Entities::Clusters::AgentTokenWithToken + end + + desc 'Revoke an agent token' do + detail 'This feature was introduced in GitLab 15.0.' + end + params do + requires :token_id, type: Integer, desc: 'The ID of the agent token' + end + delete ':token_id' do + authorize! :admin_cluster, user_project + + agent = user_project.cluster_agents.find(params[:agent_id]) + token = agent.agent_tokens.find(params[:token_id]) + + # Skipping explicit error handling and relying on exceptions + token.revoked! + + status :no_content + end + end + end + end + end + end +end diff --git a/lib/api/clusters/agents.rb b/lib/api/clusters/agents.rb index 6c1bf21b952..0fa556d2da9 100644 --- a/lib/api/clusters/agents.rb +++ b/lib/api/clusters/agents.rb @@ -8,6 +8,7 @@ module API before { authenticate! } feature_category :kubernetes_management + urgency :low params do requires :id, type: String, desc: 'The ID of a project' diff --git a/lib/api/commit_statuses.rb b/lib/api/commit_statuses.rb index c89abf72e2d..5a6d06dcdd9 100644 --- a/lib/api/commit_statuses.rb +++ b/lib/api/commit_statuses.rb @@ -5,6 +5,7 @@ require 'mime/types' module API class CommitStatuses < ::API::Base feature_category :continuous_integration + urgency :low params do requires :id, type: String, desc: 'The ID of a project' diff --git a/lib/api/composer_packages.rb b/lib/api/composer_packages.rb index c311b34a697..de59cb4a7c3 100644 --- a/lib/api/composer_packages.rb +++ b/lib/api/composer_packages.rb @@ -71,7 +71,7 @@ module API desc 'Composer packages endpoint at group level' route_setting :authentication, job_token_allowed: true, basic_auth_personal_access_token: true, deploy_token_allowed: true - get ':id/-/packages/composer/packages' do + get ':id/-/packages/composer/packages', urgency: :low do presenter.root end @@ -80,7 +80,7 @@ module API requires :sha, type: String, desc: 'Shasum of current json' end route_setting :authentication, job_token_allowed: true, basic_auth_personal_access_token: true, deploy_token_allowed: true - get ':id/-/packages/composer/p/:sha' do + get ':id/-/packages/composer/p/:sha', urgency: :low do presenter.provider end @@ -89,7 +89,7 @@ module API requires :package_name, type: String, file_path: true, desc: 'The Composer package name' end route_setting :authentication, job_token_allowed: true, basic_auth_personal_access_token: true, deploy_token_allowed: true - get ':id/-/packages/composer/p2/*package_name', requirements: COMPOSER_ENDPOINT_REQUIREMENTS, file_path: true do + get ':id/-/packages/composer/p2/*package_name', requirements: COMPOSER_ENDPOINT_REQUIREMENTS, file_path: true, urgency: :low do not_found! if packages.empty? presenter.package_versions @@ -100,7 +100,7 @@ module API requires :package_name, type: String, file_path: true, desc: 'The Composer package name' end route_setting :authentication, job_token_allowed: true, basic_auth_personal_access_token: true, deploy_token_allowed: true - get ':id/-/packages/composer/*package_name', requirements: COMPOSER_ENDPOINT_REQUIREMENTS, file_path: true do + get ':id/-/packages/composer/*package_name', requirements: COMPOSER_ENDPOINT_REQUIREMENTS, file_path: true, urgency: :low do not_found! if packages.empty? not_found! if params[:sha].blank? @@ -122,7 +122,7 @@ module API optional :tag, type: String, desc: 'The name of the tag' exactly_one_of :tag, :branch end - post do + post urgency: :low do authorize_create_package!(authorized_user_project) if params[:branch].present? @@ -147,7 +147,7 @@ module API requires :package_name, type: String, file_path: true, desc: 'The Composer package name' end route_setting :authentication, job_token_allowed: true, basic_auth_personal_access_token: true, deploy_token_allowed: true - get 'archives/*package_name' do + get 'archives/*package_name', urgency: :default do authorize_read_package!(authorized_user_project) metadata = authorized_user_project diff --git a/lib/api/concerns/packages/conan_endpoints.rb b/lib/api/concerns/packages/conan_endpoints.rb index e241633fa8b..d1cc35b16d8 100644 --- a/lib/api/concerns/packages/conan_endpoints.rb +++ b/lib/api/concerns/packages/conan_endpoints.rb @@ -56,7 +56,7 @@ module API route_setting :authentication, job_token_allowed: true, basic_auth_personal_access_token: true - get 'ping' do + get 'ping', urgency: :default do header 'X-Conan-Server-Capabilities', [].join(',') end @@ -70,7 +70,7 @@ module API route_setting :authentication, job_token_allowed: true, basic_auth_personal_access_token: true - get 'conans/search' do + get 'conans/search', urgency: :low do service = ::Packages::Conan::SearchService.new(current_user, query: params[:q]).execute service.payload end @@ -89,7 +89,7 @@ module API route_setting :authentication, job_token_allowed: true, basic_auth_personal_access_token: true - get 'authenticate' do + get 'authenticate', urgency: :low do unauthorized! unless token token.to_jwt @@ -101,7 +101,7 @@ module API route_setting :authentication, job_token_allowed: true, basic_auth_personal_access_token: true - get 'check_credentials' do + get 'check_credentials', urgency: :default do authenticate! :ok end @@ -133,7 +133,7 @@ module API route_setting :authentication, job_token_allowed: true, basic_auth_personal_access_token: true - get 'packages/:conan_package_reference' do + get 'packages/:conan_package_reference', urgency: :low do authorize!(:read_package, project) presenter = ::Packages::Conan::PackagePresenter.new( @@ -152,7 +152,7 @@ module API route_setting :authentication, job_token_allowed: true, basic_auth_personal_access_token: true - get do + get urgency: :low do authorize!(:read_package, project) presenter = ::Packages::Conan::PackagePresenter.new(package, current_user, project) @@ -174,7 +174,7 @@ module API route_setting :authentication, job_token_allowed: true, basic_auth_personal_access_token: true - get 'packages/:conan_package_reference/digest' do + get 'packages/:conan_package_reference/digest', urgency: :low do present_package_download_urls end @@ -184,7 +184,7 @@ module API route_setting :authentication, job_token_allowed: true, basic_auth_personal_access_token: true - get 'digest' do + get 'digest', urgency: :low do present_recipe_download_urls end @@ -204,7 +204,7 @@ module API route_setting :authentication, job_token_allowed: true, basic_auth_personal_access_token: true - get 'packages/:conan_package_reference/download_urls' do + get 'packages/:conan_package_reference/download_urls', urgency: :low do present_package_download_urls end @@ -214,7 +214,7 @@ module API route_setting :authentication, job_token_allowed: true, basic_auth_personal_access_token: true - get 'download_urls' do + get 'download_urls', urgency: :low do present_recipe_download_urls end @@ -235,7 +235,7 @@ module API route_setting :authentication, job_token_allowed: true, basic_auth_personal_access_token: true - post 'packages/:conan_package_reference/upload_urls' do + post 'packages/:conan_package_reference/upload_urls', urgency: :low do authorize!(:read_package, project) status 200 @@ -248,7 +248,7 @@ module API route_setting :authentication, job_token_allowed: true, basic_auth_personal_access_token: true - post 'upload_urls' do + post 'upload_urls', urgency: :low do authorize!(:read_package, project) status 200 @@ -261,7 +261,7 @@ module API route_setting :authentication, job_token_allowed: true, basic_auth_personal_access_token: true - delete do + delete urgency: :low do authorize!(:destroy_package, project) track_package_event('delete_package', :conan, category: 'API::ConanPackages', user: current_user, project: project, namespace: project.namespace) @@ -297,7 +297,7 @@ module API route_setting :authentication, job_token_allowed: true, basic_auth_personal_access_token: true - get do + get urgency: :low do download_package_file(:recipe_file) end @@ -311,7 +311,7 @@ module API route_setting :authentication, job_token_allowed: true, basic_auth_personal_access_token: true - put do + put urgency: :low do upload_package_file(:recipe_file) end @@ -321,7 +321,7 @@ module API route_setting :authentication, job_token_allowed: true, basic_auth_personal_access_token: true - put 'authorize' do + put 'authorize', urgency: :low do authorize_workhorse!(subject: project, maximum_size: project.actual_limits.conan_max_file_size) end end @@ -338,7 +338,7 @@ module API route_setting :authentication, job_token_allowed: true, basic_auth_personal_access_token: true - get do + get urgency: :low do download_package_file(:package_file) end @@ -348,7 +348,7 @@ module API route_setting :authentication, job_token_allowed: true, basic_auth_personal_access_token: true - put 'authorize' do + put 'authorize', urgency: :low do authorize_workhorse!(subject: project, maximum_size: project.actual_limits.conan_max_file_size) end @@ -362,7 +362,7 @@ module API route_setting :authentication, job_token_allowed: true, basic_auth_personal_access_token: true - put do + put urgency: :low do upload_package_file(:package_file) end end diff --git a/lib/api/concerns/packages/debian_distribution_endpoints.rb b/lib/api/concerns/packages/debian_distribution_endpoints.rb index ddc83d0f747..e01f3adbb06 100644 --- a/lib/api/concerns/packages/debian_distribution_endpoints.rb +++ b/lib/api/concerns/packages/debian_distribution_endpoints.rb @@ -10,6 +10,7 @@ module API include PaginationParams feature_category :package_registry + urgency :low helpers ::API::Helpers::PackagesHelpers helpers ::API::Helpers::Packages::BasicAuthHelpers diff --git a/lib/api/concerns/packages/debian_package_endpoints.rb b/lib/api/concerns/packages/debian_package_endpoints.rb index d083643f3d0..e8d27448f02 100644 --- a/lib/api/concerns/packages/debian_package_endpoints.rb +++ b/lib/api/concerns/packages/debian_package_endpoints.rb @@ -16,6 +16,7 @@ module API included do feature_category :package_registry + urgency :low helpers ::API::Helpers::PackagesHelpers helpers ::API::Helpers::Packages::BasicAuthHelpers diff --git a/lib/api/concerns/packages/nuget_endpoints.rb b/lib/api/concerns/packages/nuget_endpoints.rb index 208daeb3037..e0328e488c6 100644 --- a/lib/api/concerns/packages/nuget_endpoints.rb +++ b/lib/api/concerns/packages/nuget_endpoints.rb @@ -56,7 +56,7 @@ module API desc 'The NuGet Service Index' do detail 'This feature was introduced in GitLab 12.6' end - get 'index', format: :json do + get 'index', format: :json, urgency: :default do authorize_read_package!(project_or_group) track_package_event('cli_metadata', :nuget, **snowplow_gitlab_standard_context.merge(category: 'API::NugetPackages')) @@ -77,7 +77,7 @@ module API desc 'The NuGet Metadata Service - Package name level' do detail 'This feature was introduced in GitLab 12.8' end - get 'index', format: :json do + get 'index', format: :json, urgency: :low do present ::Packages::Nuget::PackagesMetadataPresenter.new(find_packages(params[:package_name])), with: ::API::Entities::Nuget::PackagesMetadata end @@ -88,7 +88,7 @@ module API params do requires :package_version, type: String, desc: 'The NuGet package version', regexp: API::NO_SLASH_URL_PART_REGEX end - get '*package_version', format: :json do + get '*package_version', format: :json, urgency: :low do present ::Packages::Nuget::PackageMetadataPresenter.new(find_package(params[:package_name], params[:package_version])), with: ::API::Entities::Nuget::PackageMetadata end @@ -109,7 +109,7 @@ module API desc 'The NuGet Search Service' do detail 'This feature was introduced in GitLab 12.8' end - get format: :json do + get format: :json, urgency: :low do search_options = { include_prerelease_versions: params[:prerelease], per_page: params[:take], diff --git a/lib/api/container_registry_event.rb b/lib/api/container_registry_event.rb index 9bad31f6661..66689f8d7c8 100644 --- a/lib/api/container_registry_event.rb +++ b/lib/api/container_registry_event.rb @@ -4,7 +4,8 @@ module API class ContainerRegistryEvent < ::API::Base DOCKER_DISTRIBUTION_EVENTS_V1_JSON = 'application/vnd.docker.distribution.events.v1+json' - feature_category :package_registry + feature_category :container_registry + urgency :low before { authenticate_registry_notification! } diff --git a/lib/api/container_repositories.rb b/lib/api/container_repositories.rb index 17d667fb6df..d4fa6153a92 100644 --- a/lib/api/container_repositories.rb +++ b/lib/api/container_repositories.rb @@ -10,6 +10,7 @@ module API before { authenticate! } feature_category :container_registry + urgency :low namespace 'registry' do params do diff --git a/lib/api/dependency_proxy.rb b/lib/api/dependency_proxy.rb index 9d0b1bf4423..290a90934d7 100644 --- a/lib/api/dependency_proxy.rb +++ b/lib/api/dependency_proxy.rb @@ -5,6 +5,7 @@ module API helpers ::API::Helpers::PackagesHelpers feature_category :dependency_proxy + urgency :low after_validation do authorize! :admin_group, user_group diff --git a/lib/api/deploy_keys.rb b/lib/api/deploy_keys.rb index 0ab9fe6644c..ca13db8701e 100644 --- a/lib/api/deploy_keys.rb +++ b/lib/api/deploy_keys.rb @@ -7,6 +7,7 @@ module API before { authenticate! } feature_category :continuous_delivery + urgency :low helpers do def add_deploy_keys_project(project, attrs = {}) diff --git a/lib/api/deploy_tokens.rb b/lib/api/deploy_tokens.rb index 074c307e881..3e0411d2e91 100644 --- a/lib/api/deploy_tokens.rb +++ b/lib/api/deploy_tokens.rb @@ -5,6 +5,7 @@ module API include PaginationParams feature_category :continuous_delivery + urgency :low helpers do def scope_params diff --git a/lib/api/deployments.rb b/lib/api/deployments.rb index 6939853c06b..8db5f54b45a 100644 --- a/lib/api/deployments.rb +++ b/lib/api/deployments.rb @@ -8,6 +8,7 @@ module API before { authenticate! } feature_category :continuous_delivery + urgency :low params do requires :id, type: String, desc: 'The project ID' diff --git a/lib/api/entities/ci/job_request/dependency.rb b/lib/api/entities/ci/job_request/dependency.rb index 2672a4a245b..63c1552de8a 100644 --- a/lib/api/entities/ci/job_request/dependency.rb +++ b/lib/api/entities/ci/job_request/dependency.rb @@ -5,7 +5,12 @@ module API module Ci module JobRequest class Dependency < Grape::Entity - expose :id, :name, :token + expose :id, :name + + expose :token do |job, options| + options[:running_job]&.token + end + expose :artifacts_file, using: Entities::Ci::JobArtifactFile, if: ->(job, _) { job.available_artifacts? } end end diff --git a/lib/api/entities/ci/job_request/response.rb b/lib/api/entities/ci/job_request/response.rb index 86c945cb236..9de415ebacb 100644 --- a/lib/api/entities/ci/job_request/response.rb +++ b/lib/api/entities/ci/job_request/response.rb @@ -28,8 +28,10 @@ module API expose :artifacts, using: Entities::Ci::JobRequest::Artifacts expose :cache, using: Entities::Ci::JobRequest::Cache expose :credentials, using: Entities::Ci::JobRequest::Credentials - expose :all_dependencies, as: :dependencies, using: Entities::Ci::JobRequest::Dependency expose :features + expose :dependencies do |job, options| + Entities::Ci::JobRequest::Dependency.represent(job.all_dependencies, options.merge(running_job: job)) + end end end end diff --git a/lib/api/entities/ci/lint/result.rb b/lib/api/entities/ci/lint/result.rb index 39039868bba..b44a6e13463 100644 --- a/lib/api/entities/ci/lint/result.rb +++ b/lib/api/entities/ci/lint/result.rb @@ -9,6 +9,7 @@ module API expose :errors expose :warnings expose :merged_yaml + expose :includes expose :jobs, if: -> (result, options) { options[:include_jobs] } end end diff --git a/lib/api/entities/ci/secure_file.rb b/lib/api/entities/ci/secure_file.rb index b60a1a6ac90..639615e5779 100644 --- a/lib/api/entities/ci/secure_file.rb +++ b/lib/api/entities/ci/secure_file.rb @@ -6,7 +6,6 @@ module API class SecureFile < Grape::Entity expose :id expose :name - expose :permissions expose :checksum expose :checksum_algorithm expose :created_at diff --git a/lib/api/entities/clusters/agent_token.rb b/lib/api/entities/clusters/agent_token.rb new file mode 100644 index 00000000000..e8cc1009361 --- /dev/null +++ b/lib/api/entities/clusters/agent_token.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +module API + module Entities + module Clusters + class AgentToken < AgentTokenBasic + expose :last_used_at + end + end + end +end diff --git a/lib/api/entities/clusters/agent_token_basic.rb b/lib/api/entities/clusters/agent_token_basic.rb new file mode 100644 index 00000000000..793ec8188b7 --- /dev/null +++ b/lib/api/entities/clusters/agent_token_basic.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +module API + module Entities + module Clusters + class AgentTokenBasic < Grape::Entity + expose :id + expose :name + expose :description + expose :agent_id + expose :status + expose :created_at + expose :created_by_user_id + end + end + end +end diff --git a/lib/api/entities/clusters/agent_token_with_token.rb b/lib/api/entities/clusters/agent_token_with_token.rb new file mode 100644 index 00000000000..8b84c80795f --- /dev/null +++ b/lib/api/entities/clusters/agent_token_with_token.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +module API + module Entities + module Clusters + class AgentTokenWithToken < AgentToken + expose :token + end + end + end +end diff --git a/lib/api/entities/environment.rb b/lib/api/entities/environment.rb index 91867f3403d..b1a720ac6bb 100644 --- a/lib/api/entities/environment.rb +++ b/lib/api/entities/environment.rb @@ -6,6 +6,7 @@ module API include RequestAwareEntity include Gitlab::Utils::StrongMemoize + expose :tier expose :project, using: Entities::BasicProjectDetails expose :last_deployment, using: Entities::Deployment, if: { last_deployment: true } expose :state diff --git a/lib/api/entities/plan_limit.rb b/lib/api/entities/plan_limit.rb index 9f4d1635998..94e50f19b35 100644 --- a/lib/api/entities/plan_limit.rb +++ b/lib/api/entities/plan_limit.rb @@ -3,6 +3,14 @@ module API module Entities class PlanLimit < Grape::Entity + expose :ci_pipeline_size + expose :ci_active_jobs + expose :ci_active_pipelines + expose :ci_project_subscriptions + expose :ci_pipeline_schedules + expose :ci_needs_size_limit + expose :ci_registered_group_runners + expose :ci_registered_project_runners expose :conan_max_file_size expose :generic_packages_max_file_size expose :helm_max_file_size @@ -11,6 +19,7 @@ module API expose :nuget_max_file_size expose :pypi_max_file_size expose :terraform_module_max_file_size + expose :storage_size_limit end end end diff --git a/lib/api/entities/project.rb b/lib/api/entities/project.rb index 60cc5167c41..9e216b0aed5 100644 --- a/lib/api/entities/project.rb +++ b/lib/api/entities/project.rb @@ -35,6 +35,10 @@ module API expose :members do |project| expose_url(api_v4_projects_members_path(id: project.id)) end + + expose :cluster_agents do |project| + expose_url(api_v4_projects_cluster_agents_path(id: project.id)) + end end expose :packages_enabled @@ -99,6 +103,7 @@ module API expose :ci_default_git_depth expose :ci_forward_deployment_enabled expose :ci_job_token_scope_enabled + expose :ci_separated_caches expose :public_builds, as: :public_jobs expose :build_git_strategy, if: lambda { |project, options| options[:user_can_admin_project] } do |project, options| project.build_allow_git_fetch ? 'fetch' : 'clone' @@ -121,6 +126,7 @@ module API expose :printing_merge_request_link_enabled expose :merge_method expose :squash_option + expose :enforce_auth_checks_on_uploads expose :suggestion_commit_message expose :merge_commit_template expose :squash_commit_template diff --git a/lib/api/entities/projects/topic.rb b/lib/api/entities/projects/topic.rb index d3d1cbec81c..976c307382a 100644 --- a/lib/api/entities/projects/topic.rb +++ b/lib/api/entities/projects/topic.rb @@ -6,6 +6,7 @@ module API class Topic < Grape::Entity expose :id expose :name + expose :title expose :description expose :total_projects_count expose :avatar_url do |topic, options| diff --git a/lib/api/entities/user.rb b/lib/api/entities/user.rb index ff711b4dec2..2366d137cc2 100644 --- a/lib/api/entities/user.rb +++ b/lib/api/entities/user.rb @@ -18,6 +18,9 @@ module API expose :following, if: ->(user, opts) { Ability.allowed?(opts[:current_user], :read_user_profile, user) } do |user| user.followees.size end + expose :is_followed, if: ->(user, opts) { Ability.allowed?(opts[:current_user], :read_user_profile, user) && opts[:current_user] } do |user, opts| + opts[:current_user].following?(user) + end expose :local_time do |user| local_time(user.timezone) end diff --git a/lib/api/environments.rb b/lib/api/environments.rb index 19b48c1e3cf..11f1cab0c72 100644 --- a/lib/api/environments.rb +++ b/lib/api/environments.rb @@ -8,6 +8,7 @@ module API before { authenticate! } feature_category :continuous_delivery + urgency :low params do requires :id, type: String, desc: 'The project ID' @@ -29,6 +30,8 @@ module API environments = ::Environments::EnvironmentsFinder.new(user_project, current_user, params).execute present paginate(environments), with: Entities::Environment, current_user: current_user + rescue ::Environments::EnvironmentsFinder::InvalidStatesError => exception + bad_request!(exception.message) end desc 'Creates a new environment' do @@ -39,6 +42,7 @@ module API requires :name, type: String, desc: 'The name of the environment to be created' optional :external_url, type: String, desc: 'URL on which this deployment is viewable' optional :slug, absence: { message: "is automatically generated and cannot be changed" } + optional :tier, type: String, values: Environment.tiers.keys, desc: 'The tier of the environment to be created' end post ':id/environments' do authorize! :create_environment, user_project @@ -62,13 +66,14 @@ module API optional :name, type: String, desc: 'DEPRECATED: Renaming environment can lead to errors, this will be removed in 15.0' optional :external_url, type: String, desc: 'The new URL on which this deployment is viewable' optional :slug, absence: { message: "is automatically generated and cannot be changed" } + optional :tier, type: String, values: Environment.tiers.keys, desc: 'The tier of the environment to be created' end put ':id/environments/:environment_id' do authorize! :update_environment, user_project environment = user_project.environments.find(params[:environment_id]) - update_params = declared_params(include_missing: false).extract!(:name, :external_url) + update_params = declared_params(include_missing: false).extract!(:name, :external_url, :tier) if environment.update(update_params) present environment, with: Entities::Environment, current_user: current_user else diff --git a/lib/api/error_tracking/client_keys.rb b/lib/api/error_tracking/client_keys.rb index e97df03b6f0..d92cf220433 100644 --- a/lib/api/error_tracking/client_keys.rb +++ b/lib/api/error_tracking/client_keys.rb @@ -43,6 +43,8 @@ module API delete '/client_keys/:key_id' do key = user_project.error_tracking_client_keys.find(params[:key_id]) key.destroy! + + present key, with: Entities::ErrorTracking::ClientKey end end end diff --git a/lib/api/error_tracking/collector.rb b/lib/api/error_tracking/collector.rb index 22a4e04a91c..29b213eaffb 100644 --- a/lib/api/error_tracking/collector.rb +++ b/lib/api/error_tracking/collector.rb @@ -12,7 +12,7 @@ module API content_type :txt, 'text/plain' default_format :envelope - rescue_from ActiveRecord::RecordInvalid do |e| + rescue_from Gitlab::ErrorTracking::ErrorRepository::DatabaseError do |e| render_api_error!(e.message, 400) end diff --git a/lib/api/events.rb b/lib/api/events.rb index db5ed7b7e6e..0a0141484ef 100644 --- a/lib/api/events.rb +++ b/lib/api/events.rb @@ -9,6 +9,7 @@ module API allow_access_with_scope :read_user, if: -> (request) { request.get? || request.head? } feature_category :users + urgency :low resource :events do desc "List currently authenticated user's events" do diff --git a/lib/api/feature_flags.rb b/lib/api/feature_flags.rb index c1f958ac007..42050888c14 100644 --- a/lib/api/feature_flags.rb +++ b/lib/api/feature_flags.rb @@ -8,6 +8,7 @@ module API .merge(name: API::NO_SLASH_URL_PART_REGEX) feature_category :feature_flags + urgency :low before do authorize_read_feature_flags! diff --git a/lib/api/feature_flags_user_lists.rb b/lib/api/feature_flags_user_lists.rb index 8577da173b1..854719db4a1 100644 --- a/lib/api/feature_flags_user_lists.rb +++ b/lib/api/feature_flags_user_lists.rb @@ -9,6 +9,7 @@ module API } feature_category :feature_flags + urgency :low before do authorize_admin_feature_flags_user_lists! diff --git a/lib/api/features.rb b/lib/api/features.rb index 398e57794c8..bff2817a2ec 100644 --- a/lib/api/features.rb +++ b/lib/api/features.rb @@ -5,6 +5,7 @@ module API before { authenticated_as_admin! } feature_category :feature_flags + urgency :low helpers do def gate_value(params) @@ -69,12 +70,14 @@ module API optional :feature_group, type: String, desc: 'A Feature group name' optional :user, type: String, desc: 'A GitLab username' optional :group, type: String, desc: "A GitLab group's path, such as 'gitlab-org'" + optional :namespace, type: String, desc: "A GitLab group or user namespace path, such as 'gitlab-org'" optional :project, type: String, desc: 'A projects path, like gitlab-org/gitlab-ce' optional :force, type: Boolean, desc: 'Skip feature flag validation checks, ie. YAML definition' mutually_exclusive :key, :feature_group mutually_exclusive :key, :user mutually_exclusive :key, :group + mutually_exclusive :key, :namespace mutually_exclusive :key, :project end post ':name' do diff --git a/lib/api/files.rb b/lib/api/files.rb index 41a8e899614..fd574ca865b 100644 --- a/lib/api/files.rb +++ b/lib/api/files.rb @@ -56,6 +56,16 @@ module API end end + def fetch_blame_range(blame_params) + return if blame_params[:range].blank? + + range = Range.new(blame_params[:range][:start], blame_params[:range][:end]) + + render_api_error!('range[start] must be less than or equal to range[end]', 400) if range.begin > range.end + + range + end + def blob_data { file_name: @blob.name, @@ -110,13 +120,19 @@ module API params do requires :file_path, type: String, file_path: true, desc: 'The url encoded path to the file. Ex. lib%2Fclass%2Erb' requires :ref, type: String, desc: 'The name of branch, tag or commit', allow_blank: false + optional :range, type: Hash do + requires :start, type: Integer, desc: 'The first line of the range to blame', allow_blank: false, values: ->(v) { v > 0 } + requires :end, type: Integer, desc: 'The last line of the range to blame', allow_blank: false, values: ->(v) { v > 0 } + end end get ":id/repository/files/:file_path/blame", requirements: FILE_ENDPOINT_REQUIREMENTS do + blame_params = declared_params(include_missing: false) + assign_file_vars! set_http_headers(blob_data) - blame_ranges = Gitlab::Blame.new(@blob, @commit).groups(highlight: false) + blame_ranges = Gitlab::Blame.new(@blob, @commit, range: fetch_blame_range(blame_params)).groups(highlight: false) present blame_ranges, with: Entities::BlameRange end diff --git a/lib/api/freeze_periods.rb b/lib/api/freeze_periods.rb index d001ced8581..e69baeee97f 100644 --- a/lib/api/freeze_periods.rb +++ b/lib/api/freeze_periods.rb @@ -7,6 +7,7 @@ module API before { authenticate! } feature_category :continuous_delivery + urgency :low params do requires :id, type: String, desc: 'The ID of a project' diff --git a/lib/api/generic_packages.rb b/lib/api/generic_packages.rb index 97230976482..0b1c06b3c26 100644 --- a/lib/api/generic_packages.rb +++ b/lib/api/generic_packages.rb @@ -10,6 +10,7 @@ module API ALLOWED_STATUSES = %w[default hidden].freeze feature_category :package_registry + urgency :low before do require_packages_enabled! diff --git a/lib/api/geo.rb b/lib/api/geo.rb index 9fc610c9b32..85f242cd135 100644 --- a/lib/api/geo.rb +++ b/lib/api/geo.rb @@ -3,6 +3,7 @@ module API class Geo < ::API::Base feature_category :geo_replication + urgency :low helpers do # Overridden in EE diff --git a/lib/api/go_proxy.rb b/lib/api/go_proxy.rb index ea30f17522e..2d9c0cd6ce1 100755 --- a/lib/api/go_proxy.rb +++ b/lib/api/go_proxy.rb @@ -5,6 +5,7 @@ module API helpers ::API::Helpers::PackagesHelpers feature_category :package_registry + urgency :low # basic semver, except case encoded (A => !a) MODULE_VERSION_REGEX = /v(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-([-.!a-z0-9]+))?(?:\+([-.!a-z0-9]+))?/.freeze diff --git a/lib/api/group_boards.rb b/lib/api/group_boards.rb index e9350da555c..180b6110cf2 100644 --- a/lib/api/group_boards.rb +++ b/lib/api/group_boards.rb @@ -8,6 +8,7 @@ module API prepend_mod_with('API::BoardsResponses') # rubocop: disable Cop/InjectEnterpriseEditionModule feature_category :team_planning + urgency :low before { authenticate! } diff --git a/lib/api/group_clusters.rb b/lib/api/group_clusters.rb index a5a60ce8741..edaa32c26c4 100644 --- a/lib/api/group_clusters.rb +++ b/lib/api/group_clusters.rb @@ -10,6 +10,7 @@ module API end feature_category :kubernetes_management + urgency :low params do requires :id, type: String, desc: 'The ID of the group' @@ -138,7 +139,7 @@ module API end def ensure_feature_enabled! - not_found! unless Feature.enabled?(:certificate_based_clusters, user_group, default_enabled: :yaml, type: :ops) + not_found! unless user_group.certificate_based_clusters_enabled? end end end diff --git a/lib/api/group_container_repositories.rb b/lib/api/group_container_repositories.rb index 55e18fd1370..b834d177a12 100644 --- a/lib/api/group_container_repositories.rb +++ b/lib/api/group_container_repositories.rb @@ -9,7 +9,8 @@ module API before { authorize_read_group_container_images! } - feature_category :package_registry + feature_category :container_registry + urgency :low REPOSITORY_ENDPOINT_REQUIREMENTS = API::NAMESPACE_OR_PROJECT_REQUIREMENTS.merge( tag_name: API::NO_SLASH_URL_PART_REGEX) @@ -24,8 +25,6 @@ module API end params do use :pagination - optional :tags, type: Boolean, default: false, desc: 'Determines if tags should be included' - optional :tags_count, type: Boolean, default: false, desc: 'Determines if the tags count should be included' end get ':id/registry/repositories' do repositories = ContainerRepositoriesFinder.new( @@ -34,7 +33,7 @@ module API track_package_event('list_repositories', :container, user: current_user, namespace: user_group) - present paginate(repositories), with: Entities::ContainerRegistry::Repository, tags: params[:tags], tags_count: params[:tags_count] + present paginate(repositories), with: Entities::ContainerRegistry::Repository, tags: false, tags_count: false end end diff --git a/lib/api/group_export.rb b/lib/api/group_export.rb index 5754eceda97..2948960a9b4 100644 --- a/lib/api/group_export.rb +++ b/lib/api/group_export.rb @@ -7,6 +7,7 @@ module API end feature_category :importers + urgency :low params do requires :id, type: String, desc: 'The ID of a group' diff --git a/lib/api/group_import.rb b/lib/api/group_import.rb index 4a752732652..abb8c10efc6 100644 --- a/lib/api/group_import.rb +++ b/lib/api/group_import.rb @@ -3,6 +3,7 @@ module API class GroupImport < ::API::Base feature_category :importers + urgency :low helpers Helpers::FileUploadHelpers diff --git a/lib/api/group_labels.rb b/lib/api/group_labels.rb index 7c1f23be828..e4cbe442f58 100644 --- a/lib/api/group_labels.rb +++ b/lib/api/group_labels.rb @@ -8,6 +8,7 @@ module API before { authenticate! } feature_category :team_planning + urgency :low params do requires :id, type: String, desc: 'The ID of a group' diff --git a/lib/api/group_milestones.rb b/lib/api/group_milestones.rb index b097022e9c1..0096e466bef 100644 --- a/lib/api/group_milestones.rb +++ b/lib/api/group_milestones.rb @@ -8,6 +8,7 @@ module API before { authenticate! } feature_category :team_planning + urgency :low params do requires :id, type: String, desc: 'The ID of a group' diff --git a/lib/api/group_packages.rb b/lib/api/group_packages.rb index e396c9608cf..af6e2b1e422 100644 --- a/lib/api/group_packages.rb +++ b/lib/api/group_packages.rb @@ -9,6 +9,7 @@ module API end feature_category :package_registry + urgency :low helpers ::API::Helpers::PackagesHelpers diff --git a/lib/api/group_variables.rb b/lib/api/group_variables.rb index e726f9b61cc..2235746b254 100644 --- a/lib/api/group_variables.rb +++ b/lib/api/group_variables.rb @@ -21,7 +21,7 @@ module API params do use :pagination end - get ':id/variables' do + get ':id/variables', urgency: :low do variables = user_group.variables present paginate(variables), with: Entities::Ci::Variable end diff --git a/lib/api/groups.rb b/lib/api/groups.rb index 0ed14476c61..60bb51bf48f 100644 --- a/lib/api/groups.rb +++ b/lib/api/groups.rb @@ -196,7 +196,7 @@ module API use :optional_params end - post feature_category: :subgroups do + post feature_category: :subgroups, urgency: :low do parent_group = find_group!(params[:parent_id]) if params[:parent_id].present? if parent_group authorize! :create_subgroup, parent_group @@ -229,7 +229,7 @@ module API use :optional_update_params use :optional_update_params_ee end - put ':id', feature_category: :subgroups do + put ':id', feature_category: :subgroups, urgency: :low do group = find_group!(params[:id]) group.preload_shared_group_links @@ -266,7 +266,7 @@ module API end desc 'Remove a group.' - delete ":id", feature_category: :subgroups do + delete ":id", feature_category: :subgroups, urgency: :low do group = find_group!(params[:id]) authorize! :admin_group, group check_subscription! group @@ -361,7 +361,7 @@ module API use :group_list_params use :with_custom_attributes end - get ":id/descendant_groups", feature_category: :subgroups do + get ":id/descendant_groups", feature_category: :subgroups, urgency: :low do finder_params = declared_params(include_missing: false).merge(include_parent_descendants: true) groups = find_groups(finder_params, params[:id]) present_groups params, groups @@ -418,7 +418,6 @@ module API optional :expires_at, type: Date, desc: 'Share expiration date' end post ":id/share", feature_category: :subgroups do - shared_group = find_group!(params[:id]) shared_with_group = find_group!(params[:group_id]) group_link_create_params = { @@ -426,11 +425,11 @@ module API expires_at: params[:expires_at] } - result = ::Groups::GroupLinks::CreateService.new(shared_group, shared_with_group, current_user, group_link_create_params).execute - shared_group.preload_shared_group_links + result = ::Groups::GroupLinks::CreateService.new(user_group, shared_with_group, current_user, group_link_create_params).execute + user_group.preload_shared_group_links if result[:status] == :success - present shared_group, with: Entities::GroupDetail, current_user: current_user + present user_group, with: Entities::GroupDetail, current_user: current_user else render_api_error!(result[:message], result[:http_status]) end diff --git a/lib/api/helm_packages.rb b/lib/api/helm_packages.rb index 4278d17e003..e0e4e02fa55 100644 --- a/lib/api/helm_packages.rb +++ b/lib/api/helm_packages.rb @@ -9,6 +9,7 @@ module API include ::API::Helpers::Authentication feature_category :package_registry + urgency :low PACKAGE_FILENAME = 'package.tgz' HELM_REQUIREMENTS = { diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb index ee0520df8ff..a079c591519 100644 --- a/lib/api/helpers.rb +++ b/lib/api/helpers.rb @@ -144,7 +144,7 @@ module API return true unless job_token_authentication? return true unless route_authentication_setting[:job_token_scope] == :project - ::Feature.enabled?(:ci_job_token_scope, project, default_enabled: :yaml) && + ::Feature.enabled?(:ci_job_token_scope, project) && current_authenticated_job.project == project end @@ -160,7 +160,17 @@ module API def find_group!(id) group = find_group(id) + check_group_access(group) + end + + # rubocop: disable CodeReuse/ActiveRecord + def find_group_by_full_path!(full_path) + group = Group.find_by_full_path(full_path) + check_group_access(group) + end + # rubocop: enable CodeReuse/ActiveRecord + def check_group_access(group) return group if can?(current_user, :read_group, group) return unauthorized! if authenticate_non_public? @@ -384,7 +394,14 @@ module API end def order_options_with_tie_breaker - order_options = { params[:order_by] => params[:sort] } + order_by = if Feature.enabled?(:replace_order_by_created_at_with_id) && + params[:order_by] == 'created_at' + 'id' + else + params[:order_by] + end + + order_options = { order_by => params[:sort] } order_options['id'] ||= params[:sort] || 'asc' order_options end @@ -555,6 +572,8 @@ module API def present_carrierwave_file!(file, supports_direct_download: true) return not_found! unless file&.exists? + log_artifact_size(file) if file.is_a?(JobArtifactUploader) + if file.file_storage? present_disk_file!(file.path, file.filename) elsif supports_direct_download && file.class.direct_download_enabled? @@ -567,9 +586,6 @@ module API end def increment_counter(event_name) - feature_name = "usage_data_#{event_name}" - return unless Feature.enabled?(feature_name, default_enabled: :yaml) - Gitlab::UsageDataCounters.count(event_name) rescue StandardError => error Gitlab::AppLogger.warn("Redis tracking event failed for event: #{event_name}, message: #{error.message}") @@ -708,16 +724,23 @@ module API # Deprecated. Use `send_artifacts_entry` instead. def legacy_send_artifacts_entry(file, entry) header(*Gitlab::Workhorse.send_artifacts_entry(file, entry)) + log_artifact_size(file) body '' end def send_artifacts_entry(file, entry) header(*Gitlab::Workhorse.send_artifacts_entry(file, entry)) + header(*Gitlab::Workhorse.detect_content_type) + log_artifact_size(file) body '' end + def log_artifact_size(file) + Gitlab::ApplicationContext.push(artifact: file.model) + end + # The Grape Error Middleware only has access to `env` but not `params` nor # `request`. We workaround this by defining methods that returns the right # values. diff --git a/lib/api/helpers/internal_helpers.rb b/lib/api/helpers/internal_helpers.rb index 46685df0989..e03f029a6ef 100644 --- a/lib/api/helpers/internal_helpers.rb +++ b/lib/api/helpers/internal_helpers.rb @@ -124,8 +124,7 @@ module API repository: repository.gitaly_repository.to_h, address: Gitlab::GitalyClient.address(repository.shard), token: Gitlab::GitalyClient.token(repository.shard), - features: Feature::Gitaly.server_feature_flags(repository.project), - use_sidechannel: Feature.enabled?(:gitlab_shell_upload_pack_sidechannel, repository.project, default_enabled: :yaml) + features: Feature::Gitaly.server_feature_flags(repository.project) } end end diff --git a/lib/api/helpers/members_helpers.rb b/lib/api/helpers/members_helpers.rb index f26ac1318b1..c91e153c7b9 100644 --- a/lib/api/helpers/members_helpers.rb +++ b/lib/api/helpers/members_helpers.rb @@ -63,7 +63,7 @@ module API def add_single_member_by_user_id(create_service_params) source = create_service_params[:source] - user_id = create_service_params[:user_ids] + user_id = create_service_params[:user_id] user = User.find_by(id: user_id) # rubocop: disable CodeReuse/ActiveRecord if user diff --git a/lib/api/helpers/projects_helpers.rb b/lib/api/helpers/projects_helpers.rb index f1125899f8c..7a9dd78e4ed 100644 --- a/lib/api/helpers/projects_helpers.rb +++ b/lib/api/helpers/projects_helpers.rb @@ -13,7 +13,6 @@ module API optional :build_git_strategy, type: String, values: %w(fetch clone), desc: 'The Git strategy. Defaults to `fetch`' optional :build_timeout, type: Integer, desc: 'Build timeout' optional :auto_cancel_pending_pipelines, type: String, values: %w(disabled enabled), desc: 'Auto-cancel pending pipelines' - optional :build_coverage_regex, type: String, desc: 'Test coverage parsing' optional :ci_config_path, type: String, desc: 'The path to CI config file. Defaults to `.gitlab-ci.yml`' optional :service_desk_enabled, type: Boolean, desc: 'Disable or enable the service desk' optional :keep_latest_artifact, type: Boolean, desc: 'Indicates if the latest artifact should be kept for this project.' @@ -41,8 +40,9 @@ module API optional :emails_disabled, type: Boolean, desc: 'Disable email notifications' optional :show_default_award_emojis, type: Boolean, desc: 'Show default award emojis' optional :warn_about_potentially_unwanted_characters, type: Boolean, desc: 'Warn about Potentially Unwanted Characters' + optional :enforce_auth_checks_on_uploads, type: Boolean, desc: 'Enforce auth check on uploads' optional :shared_runners_enabled, type: Boolean, desc: 'Flag indication if shared runners are enabled for that project' - optional :resolve_outdated_diff_discussions, type: Boolean, desc: 'Automatically resolve merge request diffs discussions on lines changed with a push' + optional :resolve_outdated_diff_discussions, type: Boolean, desc: 'Automatically resolve merge request diff threads on lines changed with a push' optional :remove_source_branch_after_merge, type: Boolean, desc: 'Remove the source branch by default after merge' optional :container_registry_enabled, type: Boolean, desc: 'Deprecated: Use :container_registry_access_level instead. Flag indication if the container registry is enabled for that project' optional :container_expiration_policy_attributes, type: Hash do @@ -54,7 +54,7 @@ module API optional :request_access_enabled, type: Boolean, desc: 'Allow users to request member access' optional :only_allow_merge_if_pipeline_succeeds, type: Boolean, desc: 'Only allow to merge if builds succeed' optional :allow_merge_on_skipped_pipeline, type: Boolean, desc: 'Allow to merge if pipeline is skipped' - optional :only_allow_merge_if_all_discussions_are_resolved, type: Boolean, desc: 'Only allow to merge if all discussions are resolved' + optional :only_allow_merge_if_all_discussions_are_resolved, type: Boolean, desc: 'Only allow to merge if all threads are resolved' optional :tag_list, type: Array[String], coerce_with: ::API::Validations::Types::CommaSeparatedToArray.coerce, desc: 'Deprecated: Use :topics instead' optional :topics, type: Array[String], coerce_with: ::API::Validations::Types::CommaSeparatedToArray.coerce, desc: 'The list of topics for a project' # TODO: remove rubocop disable - https://gitlab.com/gitlab-org/gitlab/issues/14960 @@ -124,7 +124,6 @@ module API :auto_devops_enabled, :auto_devops_deploy_strategy, :auto_cancel_pending_pipelines, - :build_coverage_regex, :build_git_strategy, :build_timeout, :builds_access_level, @@ -175,6 +174,7 @@ module API :service_desk_enabled, :keep_latest_artifact, :mr_default_target_self, + :enforce_auth_checks_on_uploads, # TODO: remove in API v5, replaced by *_access_level :issues_enabled, @@ -192,8 +192,6 @@ module API def validate_git_import_url!(import_url) return if import_url.blank? - yield if block_given? - result = Import::ValidateRemoteGitEndpointService.new(url: import_url).execute # network call if result.error? diff --git a/lib/api/import_bitbucket_server.rb b/lib/api/import_bitbucket_server.rb index 0f0d62dcbfb..0f2d6239d0d 100644 --- a/lib/api/import_bitbucket_server.rb +++ b/lib/api/import_bitbucket_server.rb @@ -3,10 +3,7 @@ module API class ImportBitbucketServer < ::API::Base feature_category :importers - - before do - forbidden! unless Gitlab::CurrentSettings.import_sources&.include?('bitbucket_server') - end + urgency :low helpers do def client diff --git a/lib/api/import_github.rb b/lib/api/import_github.rb index c91a7700f58..46ca8e4c428 100644 --- a/lib/api/import_github.rb +++ b/lib/api/import_github.rb @@ -3,19 +3,16 @@ module API class ImportGithub < ::API::Base feature_category :importers + urgency :low rescue_from Octokit::Unauthorized, with: :provider_unauthorized - before do - forbidden! unless Gitlab::CurrentSettings.import_sources&.include?('github') - end - helpers do def client @client ||= if Feature.enabled?(:remove_legacy_github_client) Gitlab::GithubImport::Client.new(params[:personal_access_token], host: params[:github_hostname]) else - Gitlab::LegacyGithubImport::Client.new(params[:personal_access_token], client_options) + Gitlab::LegacyGithubImport::Client.new(params[:personal_access_token], **client_options) end end diff --git a/lib/api/integrations/jira_connect/subscriptions.rb b/lib/api/integrations/jira_connect/subscriptions.rb new file mode 100644 index 00000000000..fa19dc2be3f --- /dev/null +++ b/lib/api/integrations/jira_connect/subscriptions.rb @@ -0,0 +1,51 @@ +# frozen_string_literal: true + +module API + class Integrations + module JiraConnect + class Subscriptions < ::API::Base + feature_category :integrations + + before { authenticate! } + + namespace :integrations do + namespace :jira_connect do + resource :subscriptions do + desc 'Subscribe a namespace to a JiraConnectInstallation' + params do + requires :jwt, type: String, desc: 'JWT token for authorization with the Jira Connect installation' + requires :namespace_path, type: String, desc: 'Path for the namespace that should be subscribed' + end + post do + not_found! unless Feature.enabled?(:jira_connect_oauth, current_user) + + jwt = Atlassian::JiraConnect::Jwt::Symmetric.new(params[:jwt]) + installation = JiraConnectInstallation.find_by_client_key(jwt.iss_claim) + + if !installation || !jwt.valid?(installation.shared_secret) || !jwt.verify_context_qsh_claim + unauthorized! + end + + jira_user = installation.client.user_info(jwt.sub_claim) + + result = ::JiraConnectSubscriptions::CreateService.new( + installation, + current_user, + namespace_path: params['namespace_path'], + jira_user: jira_user + ).execute + + if result[:status] == :success + status :created + { success: true } + else + render_api_error!(result[:message], result[:http_status]) + end + end + end + end + end + end + end + end +end diff --git a/lib/api/internal/base.rb b/lib/api/internal/base.rb index 2ab5d482295..b53f855c3a2 100644 --- a/lib/api/internal/base.rb +++ b/lib/api/internal/base.rb @@ -43,7 +43,7 @@ module API # This is a separate method so that EE can alter its behaviour more # easily. - if Feature.enabled?(:rate_limit_gitlab_shell, default_enabled: :yaml) + if Feature.enabled?(:rate_limit_gitlab_shell) check_rate_limit!(:gitlab_shell_operation, scope: [params[:action], params[:project], actor.key_or_user]) end @@ -123,10 +123,19 @@ module API 'Could not find a user for the given key' unless actor.user end + # TODO: backwards compatibility; remove after https://gitlab.com/gitlab-org/gitlab-shell/-/merge_requests/454 is merged def two_factor_otp_check { success: false, message: 'Feature is not available' } end + def two_factor_manual_otp_check + { success: false, message: 'Feature is not available' } + end + + def two_factor_push_otp_check + { success: false, message: 'Feature is not available' } + end + def with_admin_mode_bypass!(actor_id) return yield unless Gitlab::CurrentSettings.admin_mode @@ -320,10 +329,23 @@ module API end end + # TODO: backwards compatibility; remove after https://gitlab.com/gitlab-org/gitlab-shell/-/merge_requests/454 is merged post '/two_factor_otp_check', feature_category: :authentication_and_authorization do status 200 - two_factor_otp_check + two_factor_manual_otp_check + end + + post '/two_factor_push_otp_check', feature_category: :authentication_and_authorization do + status 200 + + two_factor_push_otp_check + end + + post '/two_factor_manual_otp_check', feature_category: :authentication_and_authorization do + status 200 + + two_factor_manual_otp_check end end end diff --git a/lib/api/internal/container_registry/migration.rb b/lib/api/internal/container_registry/migration.rb index b84e14c6f31..c750db94dab 100644 --- a/lib/api/internal/container_registry/migration.rb +++ b/lib/api/internal/container_registry/migration.rb @@ -5,6 +5,7 @@ module API module ContainerRegistry class Migration < ::API::Base feature_category :container_registry + urgency :low STATUS_PRE_IMPORT_COMPLETE = 'pre_import_complete' STATUS_PRE_IMPORT_FAILED = 'pre_import_failed' @@ -36,23 +37,25 @@ module API requires :status, type: String, values: POSSIBLE_VALUES, desc: 'The migration step status' end put 'internal/registry/repositories/*repository_path/migration/status' do - repository = find_repository!(declared_params[:repository_path]) + ::Gitlab::Database::LoadBalancing::Session.current.use_primary do + repository = find_repository!(declared_params[:repository_path]) - unless repository.migration_in_active_state? - bad_request!("Wrong migration state (#{repository.migration_state})") - end - - case declared_params[:status] - when STATUS_PRE_IMPORT_COMPLETE - unless repository.finish_pre_import_and_start_import - bad_request!("Couldn't transition from pre_importing to importing") + unless repository.migration_in_active_state? + bad_request!("Wrong migration state (#{repository.migration_state})") end - when STATUS_IMPORT_COMPLETE - unless repository.finish_import - bad_request!("Couldn't transition from importing to import_done") + + case declared_params[:status] + when STATUS_PRE_IMPORT_COMPLETE + unless repository.finish_pre_import_and_start_import + bad_request!("Couldn't transition from pre_importing to importing") + end + when STATUS_IMPORT_COMPLETE + unless repository.finish_import + bad_request!("Couldn't transition from importing to import_done") + end + when STATUS_IMPORT_FAILED, STATUS_PRE_IMPORT_FAILED + repository.abort_import! end - when STATUS_IMPORT_FAILED, STATUS_PRE_IMPORT_FAILED - repository.abort_import end status 200 diff --git a/lib/api/internal/kubernetes.rb b/lib/api/internal/kubernetes.rb index 59bc917a602..34acfac4cb1 100644 --- a/lib/api/internal/kubernetes.rb +++ b/lib/api/internal/kubernetes.rb @@ -5,7 +5,6 @@ module API module Internal class Kubernetes < ::API::Base feature_category :kubernetes_management - before do check_feature_enabled authenticate_gitlab_kas_request! @@ -48,7 +47,7 @@ module API end def check_feature_enabled - not_found! unless Feature.enabled?(:kubernetes_agent_internal_api, default_enabled: true, type: :ops) + not_found! unless Feature.enabled?(:kubernetes_agent_internal_api, type: :ops) end def check_agent_token @@ -68,7 +67,7 @@ module API detail 'Retrieves agent info for the given token' end route_setting :authentication, cluster_agent_token_allowed: true - get '/agent_info' do + get '/agent_info', urgency: :low do project = agent.project status 200 @@ -82,7 +81,7 @@ module API end end - namespace 'kubernetes/agent_configuration' do + namespace 'kubernetes/agent_configuration', urgency: :low do desc 'POST agent configuration' do detail 'Store configuration for an agent' end diff --git a/lib/api/invitations.rb b/lib/api/invitations.rb index 75f63a5d98f..6fb3eca0ba8 100644 --- a/lib/api/invitations.rb +++ b/lib/api/invitations.rb @@ -28,7 +28,7 @@ module API optional :tasks_to_be_done, type: Array[String], coerce_with: Validations::Types::CommaSeparatedToArray.coerce, desc: 'Tasks the inviter wants the member to do' optional :tasks_project_id, type: Integer, desc: 'The project ID in which to create the task issues' end - post ":id/invitations" do + post ":id/invitations", urgency: :low do ::Gitlab::QueryLimiting.disable!('https://gitlab.com/gitlab-org/gitlab/-/issues/354016') bad_request!('Must provide either email or user_id as a parameter') if params[:email].blank? && params[:user_id].blank? @@ -36,7 +36,7 @@ module API source = find_source(source_type, params[:id]) authorize_admin_source!(source_type, source) - create_service_params = params.except(:user_id).merge({ user_ids: params[:user_id], source: source }) + create_service_params = params.merge(source: source) ::Members::InviteService.new(current_user, create_service_params).execute end diff --git a/lib/api/issue_links.rb b/lib/api/issue_links.rb index 0e93a4adb65..cf075af8373 100644 --- a/lib/api/issue_links.rb +++ b/lib/api/issue_links.rb @@ -7,6 +7,7 @@ module API before { authenticate! } feature_category :team_planning + urgency :low params do requires :id, type: String, desc: 'The ID of a project' diff --git a/lib/api/issues.rb b/lib/api/issues.rb index e9bb9fe7a97..971163c18db 100644 --- a/lib/api/issues.rb +++ b/lib/api/issues.rb @@ -9,6 +9,7 @@ module API before { authenticate_non_get! } feature_category :team_planning + urgency :low helpers do params :negatable_issue_filter_params do diff --git a/lib/api/labels.rb b/lib/api/labels.rb index e3253d15c15..e2d4f5d823a 100644 --- a/lib/api/labels.rb +++ b/lib/api/labels.rb @@ -8,6 +8,7 @@ module API before { authenticate! } feature_category :team_planning + urgency :low LABEL_ENDPOINT_REQUIREMENTS = API::NAMESPACE_OR_PROJECT_REQUIREMENTS.merge( name: API::NO_SLASH_URL_PART_REGEX, diff --git a/lib/api/maven_packages.rb b/lib/api/maven_packages.rb index 5245cd10564..2fed724f947 100644 --- a/lib/api/maven_packages.rb +++ b/lib/api/maven_packages.rb @@ -6,6 +6,7 @@ module API }.freeze feature_category :package_registry + urgency :low content_type :md5, 'text/plain' content_type :sha1, 'text/plain' diff --git a/lib/api/members.rb b/lib/api/members.rb index 01e859c94c4..e2045c6def7 100644 --- a/lib/api/members.rb +++ b/lib/api/members.rb @@ -6,12 +6,14 @@ module API before { authenticate! } - feature_category :authentication_and_authorization urgency :low helpers ::API::Helpers::MembersHelpers - %w[group project].each do |source_type| + { + "group" => :subgroups, + "project" => :projects + }.each do |source_type, feature_category| params do requires :id, type: String, desc: "The #{source_type} ID" end @@ -27,7 +29,7 @@ module API use :pagination end - get ":id/members" do + get ":id/members", feature_category: feature_category do source = find_source(source_type, params[:id]) members = paginate(retrieve_members(source, params: params)) @@ -46,7 +48,7 @@ module API use :pagination end - get ":id/members/all" do + get ":id/members/all", feature_category: feature_category do source = find_source(source_type, params[:id]) members = paginate(retrieve_members(source, params: params, deep: true)) @@ -61,7 +63,7 @@ module API requires :user_id, type: Integer, desc: 'The user ID of the member' end # rubocop: disable CodeReuse/ActiveRecord - get ":id/members/:user_id" do + get ":id/members/:user_id", feature_category: feature_category do source = find_source(source_type, params[:id]) members = source_members(source) @@ -78,7 +80,7 @@ module API requires :user_id, type: Integer, desc: 'The user ID of the member' end # rubocop: disable CodeReuse/ActiveRecord - get ":id/members/all/:user_id" do + get ":id/members/all/:user_id", feature_category: feature_category do source = find_source(source_type, params[:id]) members = find_all_members(source) @@ -100,16 +102,15 @@ module API optional :tasks_project_id, type: Integer, desc: 'The project ID in which to create the task issues' end - post ":id/members" do + post ":id/members", feature_category: feature_category do source = find_source(source_type, params[:id]) authorize_admin_source!(source_type, source) - user_id = params[:user_id].to_s - create_service_params = params.except(:user_id).merge({ user_ids: user_id, source: source }) + create_service_params = params.merge(source: source) - if add_multiple_members?(user_id) + if add_multiple_members?(params[:user_id].to_s) ::Members::CreateService.new(current_user, create_service_params).execute - elsif add_single_member?(user_id) + elsif add_single_member?(params[:user_id].to_s) add_single_member_by_user_id(create_service_params) end end @@ -123,7 +124,7 @@ module API optional :expires_at, type: DateTime, desc: 'Date string in the format YEAR-MONTH-DAY' end # rubocop: disable CodeReuse/ActiveRecord - put ":id/members/:user_id" do + put ":id/members/:user_id", feature_category: feature_category do source = find_source(source_type, params.delete(:id)) authorize_admin_source!(source_type, source) @@ -152,7 +153,7 @@ module API desc: 'Flag indicating if the removed member should be unassigned from any issues or merge requests within given group or project' end # rubocop: disable CodeReuse/ActiveRecord - delete ":id/members/:user_id" do + delete ":id/members/:user_id", feature_category: feature_category do source = find_source(source_type, params[:id]) member = source_members(source).find_by!(user_id: params[:user_id]) diff --git a/lib/api/merge_requests.rb b/lib/api/merge_requests.rb index de9a2a198d9..730baae63a2 100644 --- a/lib/api/merge_requests.rb +++ b/lib/api/merge_requests.rb @@ -373,7 +373,7 @@ module API desc 'Get the merge request pipelines' do success Entities::Ci::PipelineBasic end - get ':id/merge_requests/:merge_request_iid/pipelines', feature_category: :continuous_integration do + get ':id/merge_requests/:merge_request_iid/pipelines', urgency: :low, feature_category: :continuous_integration do pipelines = merge_request_pipelines_with_access present paginate(pipelines), with: Entities::Ci::PipelineBasic @@ -382,7 +382,7 @@ module API desc 'Create a pipeline for merge request' do success ::API::Entities::Ci::Pipeline end - post ':id/merge_requests/:merge_request_iid/pipelines', feature_category: :continuous_integration do + post ':id/merge_requests/:merge_request_iid/pipelines', urgency: :low, feature_category: :continuous_integration do pipeline = ::MergeRequests::CreatePipelineService .new(project: user_project, current_user: current_user, params: { allow_duplicate: true }) .execute(find_merge_request_with_access(params[:merge_request_iid])) diff --git a/lib/api/namespaces.rb b/lib/api/namespaces.rb index 1f3516e0667..4ff7096b5d9 100644 --- a/lib/api/namespaces.rb +++ b/lib/api/namespaces.rb @@ -30,7 +30,7 @@ module API use :pagination use :optional_list_params_ee end - get feature_category: :subgroups do + get feature_category: :subgroups, urgency: :low do owned_only = params[:owned_only] == true namespaces = current_user.admin ? Namespace.all : current_user.namespaces(owned_only: owned_only) @@ -52,7 +52,7 @@ module API params do requires :id, type: String, desc: "Namespace's ID or path" end - get ':id', requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS, feature_category: :subgroups do + get ':id', requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS, feature_category: :subgroups, urgency: :low do user_namespace = find_namespace!(params[:id]) present user_namespace, with: Entities::Namespace, current_user: current_user @@ -65,7 +65,7 @@ module API requires :namespace, type: String, desc: "Namespace's path" optional :parent_id, type: Integer, desc: "The ID of the parent namespace. If no ID is specified, only top-level namespaces are considered." end - get ':namespace/exists', requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS, feature_category: :subgroups do + get ':namespace/exists', requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS, feature_category: :subgroups, urgency: :low do namespace_path = params[:namespace] exists = Namespace.without_project_namespaces.by_parent(params[:parent_id]).filter_by_path(namespace_path).exists? diff --git a/lib/api/notes.rb b/lib/api/notes.rb index c12b3bf5562..2a854bd785e 100644 --- a/lib/api/notes.rb +++ b/lib/api/notes.rb @@ -94,7 +94,7 @@ module API note = create_note(noteable, opts) - if note.errors.attribute_names == [:commands_only] + if note.errors.attribute_names == [:commands_only, :command_names] status 202 present note, with: Entities::NoteCommands elsif note.valid? diff --git a/lib/api/notification_settings.rb b/lib/api/notification_settings.rb index 420eabb41db..8cd72d2ab15 100644 --- a/lib/api/notification_settings.rb +++ b/lib/api/notification_settings.rb @@ -6,6 +6,7 @@ module API before { authenticate! } feature_category :team_planning + urgency :low helpers ::API::Helpers::MembersHelpers diff --git a/lib/api/npm_instance_packages.rb b/lib/api/npm_instance_packages.rb index 12fc008e00f..e387dd65e41 100644 --- a/lib/api/npm_instance_packages.rb +++ b/lib/api/npm_instance_packages.rb @@ -4,6 +4,7 @@ module API helpers ::API::Helpers::Packages::Npm feature_category :package_registry + urgency :low rescue_from ActiveRecord::RecordInvalid do |e| render_api_error!(e.message, 400) diff --git a/lib/api/npm_project_packages.rb b/lib/api/npm_project_packages.rb index dbfc0a61577..21bb2e69799 100644 --- a/lib/api/npm_project_packages.rb +++ b/lib/api/npm_project_packages.rb @@ -4,6 +4,7 @@ module API helpers ::API::Helpers::Packages::Npm feature_category :package_registry + urgency :low rescue_from ActiveRecord::RecordInvalid do |e| render_api_error!(e.message, 400) diff --git a/lib/api/nuget_project_packages.rb b/lib/api/nuget_project_packages.rb index 03d1492908d..1e630cffea1 100644 --- a/lib/api/nuget_project_packages.rb +++ b/lib/api/nuget_project_packages.rb @@ -105,7 +105,7 @@ module API params do use :file_params end - put do + put urgency: :low do upload_nuget_package_file do |package| track_package_event( 'push_package', @@ -121,7 +121,7 @@ module API forbidden! end - put 'authorize' do + put 'authorize', urgency: :low do authorize_nuget_upload end @@ -133,7 +133,7 @@ module API params do use :file_params end - put 'symbolpackage' do + put 'symbolpackage', urgency: :low do upload_nuget_package_file(symbol_package: true) do |package| track_package_event( 'push_symbol_package', @@ -149,7 +149,7 @@ module API forbidden! end - put 'symbolpackage/authorize' do + put 'symbolpackage/authorize', urgency: :low do authorize_nuget_upload end @@ -165,7 +165,7 @@ module API desc 'The NuGet Content Service - index request' do detail 'This feature was introduced in GitLab 12.8' end - get 'index', format: :json do + get 'index', format: :json, urgency: :low do present ::Packages::Nuget::PackagesVersionsPresenter.new(find_packages(params[:package_name])), with: ::API::Entities::Nuget::PackagesVersions end @@ -177,7 +177,7 @@ module API requires :package_version, type: String, desc: 'The NuGet package version', regexp: API::NO_SLASH_URL_PART_REGEX requires :package_filename, type: String, desc: 'The NuGet package filename', regexp: API::NO_SLASH_URL_PART_REGEX end - get '*package_version/*package_filename', format: [:nupkg, :snupkg] do + get '*package_version/*package_filename', format: [:nupkg, :snupkg], urgency: :low do filename = "#{params[:package_filename]}.#{params[:format]}" package_file = ::Packages::PackageFileFinder.new(find_package(params[:package_name], params[:package_version]), filename, with_file_name_like: true) .execute diff --git a/lib/api/package_files.rb b/lib/api/package_files.rb index 4861c0c740e..278dc4c2044 100644 --- a/lib/api/package_files.rb +++ b/lib/api/package_files.rb @@ -9,6 +9,7 @@ module API end feature_category :package_registry + urgency :low helpers ::API::Helpers::PackagesHelpers diff --git a/lib/api/personal_access_tokens.rb b/lib/api/personal_access_tokens.rb index 56590bb9a8f..40e6486dae9 100644 --- a/lib/api/personal_access_tokens.rb +++ b/lib/api/personal_access_tokens.rb @@ -39,6 +39,12 @@ module API def find_token(id) PersonalAccessToken.find(id) || not_found! end + + def revoke_token(token) + service = ::PersonalAccessTokens::RevokeService.new(current_user, token: token).execute + + service.success? ? no_content! : bad_request!(nil) + end end resources :personal_access_tokens do @@ -48,13 +54,14 @@ module API present paginate(tokens), with: Entities::PersonalAccessToken end + delete 'self' do + revoke_token(access_token) + end + delete ':id' do - service = ::PersonalAccessTokens::RevokeService.new( - current_user, - token: find_token(params[:id]) - ).execute + token = find_token(params[:id]) - service.success? ? no_content! : bad_request!(nil) + revoke_token(token) end end end diff --git a/lib/api/project_clusters.rb b/lib/api/project_clusters.rb index 8bba67a53af..4644d38ea80 100644 --- a/lib/api/project_clusters.rb +++ b/lib/api/project_clusters.rb @@ -10,6 +10,7 @@ module API end feature_category :kubernetes_management + urgency :low params do requires :id, type: String, desc: 'The ID of the project' @@ -143,7 +144,9 @@ module API end def ensure_feature_enabled! - not_found! unless Feature.enabled?(:certificate_based_clusters, user_project, default_enabled: :yaml, type: :ops) + namespace = user_project.namespace + + not_found! unless namespace.certificate_based_clusters_enabled? end end end diff --git a/lib/api/project_container_repositories.rb b/lib/api/project_container_repositories.rb index d4efca6e8f2..6a6275ed02a 100644 --- a/lib/api/project_container_repositories.rb +++ b/lib/api/project_container_repositories.rb @@ -13,6 +13,7 @@ module API before { authorize_read_container_images! } feature_category :package_registry + urgency :low params do requires :id, type: String, desc: 'The ID of a project' @@ -91,7 +92,7 @@ module API # rubocop:disable CodeReuse/Worker CleanupContainerRepositoryWorker.perform_async(current_user.id, repository.id, - declared_params.except(:repository_id).merge(container_expiration_policy: false)) + declared_params.except(:repository_id)) # rubocop:enable CodeReuse/Worker track_package_event('delete_tag_bulk', :container, user: current_user, project: user_project, namespace: user_project.namespace) diff --git a/lib/api/project_export.rb b/lib/api/project_export.rb index 8b27d8d2163..d610b5e4f95 100644 --- a/lib/api/project_export.rb +++ b/lib/api/project_export.rb @@ -3,6 +3,7 @@ module API class ProjectExport < ::API::Base feature_category :importers + urgency :low before do not_found! unless Gitlab::CurrentSettings.project_export_enabled? @@ -65,9 +66,13 @@ module API if export_strategy&.invalid? render_validation_error!(export_strategy) else - user_project.add_export_job(current_user: current_user, - after_export_strategy: export_strategy, - params: project_export_params) + begin + user_project.add_export_job(current_user: current_user, + after_export_strategy: export_strategy, + params: project_export_params) + rescue Project::ExportLimitExceeded => e + render_api_error!(e.message, 400) + end end accepted! @@ -75,7 +80,7 @@ module API resource do before do - not_found! unless ::Feature.enabled?(:bulk_import, default_enabled: :yaml) + not_found! unless ::Feature.enabled?(:bulk_import) end desc 'Start relations export' do diff --git a/lib/api/project_import.rb b/lib/api/project_import.rb index bd8faefa803..7a66044c5b6 100644 --- a/lib/api/project_import.rb +++ b/lib/api/project_import.rb @@ -8,6 +8,7 @@ module API helpers Helpers::FileUploadHelpers feature_category :importers + urgency :low before { authenticate! unless route.settings[:skip_authentication] } @@ -178,7 +179,7 @@ module API success Entities::ProjectImportStatus end post 'remote-import-s3' do - not_found! unless ::Feature.enabled?(:import_project_from_remote_file_s3, default_enabled: :yaml) + not_found! unless ::Feature.enabled?(:import_project_from_remote_file_s3) check_rate_limit! :project_import, scope: [current_user, :project_import] diff --git a/lib/api/project_milestones.rb b/lib/api/project_milestones.rb index 435e4bed776..9f82dbf9813 100644 --- a/lib/api/project_milestones.rb +++ b/lib/api/project_milestones.rb @@ -8,6 +8,7 @@ module API before { authenticate! } feature_category :team_planning + urgency :low params do requires :id, type: String, desc: 'The ID of a project' diff --git a/lib/api/project_packages.rb b/lib/api/project_packages.rb index c997afea865..79a5ca531e1 100644 --- a/lib/api/project_packages.rb +++ b/lib/api/project_packages.rb @@ -9,6 +9,7 @@ module API end feature_category :package_registry + urgency :low helpers ::API::Helpers::PackagesHelpers diff --git a/lib/api/projects.rb b/lib/api/projects.rb index 9f7b3f9b088..44b1acaca88 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -76,7 +76,7 @@ module API # Temporarily introduced for upload API: https://gitlab.com/gitlab-org/gitlab/-/issues/325788 def project_attachment_size(user_project) return PROJECT_ATTACHMENT_SIZE_EXEMPT if exempt_from_global_attachment_size?(user_project) - return user_project.max_attachment_size if Feature.enabled?(:enforce_max_attachment_size_upload_api, user_project, default_enabled: :yaml) + return user_project.max_attachment_size if Feature.enabled?(:enforce_max_attachment_size_upload_api, user_project) PROJECT_ATTACHMENT_SIZE_EXEMPT end @@ -90,10 +90,6 @@ module API Gitlab::AppLogger.info({ message: "File exceeds maximum size", file_bytes: file.size, project_id: user_project.id, project_path: user_project.full_path, upload_allowed: allowed }) end end - - def check_import_by_url_is_enabled - Gitlab::CurrentSettings.import_sources&.include?('git') || forbidden! - end end helpers do @@ -202,6 +198,11 @@ module API params[:builds_enabled] = params.delete(:jobs_enabled) if params.key?(:jobs_enabled) params end + + def add_import_params(params) + params[:import_type] = 'git' if params[:import_url]&.present? + params + end end resource :users, requirements: API::USER_REQUIREMENTS do @@ -214,7 +215,7 @@ module API use :statistics_params use :with_custom_attributes end - get ":user_id/projects", feature_category: :projects, urgency: :default do + get ":user_id/projects", feature_category: :projects, urgency: :low do user = find_user(params[:user_id]) not_found!('User') unless user @@ -231,7 +232,7 @@ module API use :collection_params use :statistics_params end - get ":user_id/starred_projects", feature_category: :projects do + get ":user_id/starred_projects", feature_category: :projects, urgency: :low do user = find_user(params[:user_id]) not_found!('User') unless user @@ -267,13 +268,14 @@ module API use :optional_create_project_params use :create_params end - post do + post urgency: :low do Gitlab::QueryLimiting.disable!('https://gitlab.com/gitlab-org/gitlab/issues/21139') attrs = declared_params(include_missing: false) attrs = translate_params_for_compatibility(attrs) + attrs = add_import_params(attrs) filter_attributes_using_license!(attrs) - validate_git_import_url!(params[:import_url]) { check_import_by_url_is_enabled } + validate_git_import_url!(params[:import_url]) project = ::Projects::CreateService.new(current_user, attrs).execute @@ -286,6 +288,8 @@ module API error!(project.errors[:limit_reached], 403) end + forbidden! if project.errors[:import_source_disabled].present? + render_validation_error!(project) end end @@ -311,6 +315,7 @@ module API attrs = declared_params(include_missing: false) attrs = translate_params_for_compatibility(attrs) + attrs = add_import_params(attrs) filter_attributes_using_license!(attrs) validate_git_import_url!(params[:import_url]) @@ -321,6 +326,8 @@ module API user_can_admin_project: can?(current_user, :admin_project, project), current_user: current_user else + forbidden! if project.errors[:import_source_disabled].present? + render_validation_error!(project) end end @@ -342,7 +349,7 @@ module API desc: 'Include project license data' end # TODO: Set higher urgency https://gitlab.com/gitlab-org/gitlab/-/issues/357622 - get ":id", feature_category: :projects, urgency: :default do + get ":id", feature_category: :projects, urgency: :low do options = { with: current_user ? Entities::ProjectWithAccess : Entities::BasicProjectDetails, current_user: current_user, @@ -441,6 +448,7 @@ module API authorize! :change_visibility_level, user_project if user_project.visibility_attribute_present?(attrs) attrs = translate_params_for_compatibility(attrs) + attrs = add_import_params(attrs) filter_attributes_using_license!(attrs) verify_update_project_attrs!(user_project, attrs) @@ -469,7 +477,7 @@ module API desc 'Unarchive a project' do success Entities::Project end - post ':id/unarchive', feature_category: :projects do + post ':id/unarchive', feature_category: :projects, urgency: :default do authorize!(:archive_project, user_project) ::Projects::UpdateService.new(user_project, current_user, archived: false).execute @@ -575,14 +583,14 @@ module API end post ":id/share", feature_category: :authentication_and_authorization do authorize! :admin_project, user_project - group = Group.find_by_id(params[:group_id]) + shared_with_group = Group.find_by_id(params[:group_id]) unless user_project.allowed_to_share_with_group? break render_api_error!("The project sharing with group is disabled", 400) end - result = ::Projects::GroupLinks::CreateService.new(user_project, current_user, declared_params(include_missing: false)) - .execute(group) + result = ::Projects::GroupLinks::CreateService + .new(user_project, shared_with_group, current_user, declared_params(include_missing: false)).execute if result[:status] == :success present result[:link], with: Entities::ProjectGroupLink @@ -663,7 +671,7 @@ module API optional :skip_users, type: Array[Integer], coerce_with: ::API::Validations::Types::CommaSeparatedToIntegerArray.coerce, desc: 'Filter out users with the specified IDs' use :pagination end - get ':id/users', feature_category: :authentication_and_authorization do + get ':id/users', urgency: :low, feature_category: :authentication_and_authorization do users = DeclarativePolicy.subject_scope { user_project.team.users } users = users.search(params[:search]) if params[:search].present? users = users.where_not_in(params[:skip_users]) if params[:skip_users].present? @@ -706,6 +714,17 @@ module API end end + desc 'Start a task to recalculate repository size for a project' do + detail 'This feature was introduced in GitLab 15.0.' + end + post ':id/repository_size', feature_category: :source_code_management do + authorize_admin_project + + user_project.repository.expire_statistics_caches + + ::Projects::UpdateStatisticsService.new(user_project, nil, statistics: [:repository_size, :lfs_objects_size]).execute + end + desc 'Transfer a project to a new namespace' params do requires :namespace, type: String, desc: 'The ID or path of the new namespace' @@ -729,7 +748,7 @@ module API params do requires :id, type: String, desc: 'ID of a project' end - get ':id/storage', feature_category: :projects do + get ':id/storage', feature_category: :source_code_management do authenticated_as_admin! present user_project, with: Entities::ProjectRepositoryStorage, current_user: current_user diff --git a/lib/api/pypi_packages.rb b/lib/api/pypi_packages.rb index d4f51beb2e5..f11270457c9 100644 --- a/lib/api/pypi_packages.rb +++ b/lib/api/pypi_packages.rb @@ -14,6 +14,7 @@ module API include ::API::Helpers::Packages::BasicAuthHelpers::Constants feature_category :package_registry + urgency :low default_format :json diff --git a/lib/api/release/links.rb b/lib/api/release/links.rb index 52c73104bb4..bc5ffe5b21f 100644 --- a/lib/api/release/links.rb +++ b/lib/api/release/links.rb @@ -11,6 +11,7 @@ module API before { authorize! :read_release, user_project } feature_category :release_orchestration + urgency :low params do requires :id, type: String, desc: 'The ID of a project' diff --git a/lib/api/releases.rb b/lib/api/releases.rb index 9e085a91a7c..c69f45f1f38 100644 --- a/lib/api/releases.rb +++ b/lib/api/releases.rb @@ -9,6 +9,7 @@ module API RELEASE_CLI_USER_AGENT = 'GitLab-release-cli' feature_category :release_orchestration + urgency :low params do requires :id, type: String, desc: 'The ID of a group' @@ -29,8 +30,6 @@ module API use :pagination end get ":id/releases" do - not_found! unless Feature.enabled?(:group_releases_finder_inoperator) - finder_options = { sort: params[:sort] } diff --git a/lib/api/rubygem_packages.rb b/lib/api/rubygem_packages.rb index 6ac5ad0518b..e6c54faebd9 100644 --- a/lib/api/rubygem_packages.rb +++ b/lib/api/rubygem_packages.rb @@ -8,6 +8,7 @@ module API helpers ::API::Helpers::PackagesHelpers feature_category :package_registry + urgency :low # The Marshal version can be found by "#{Marshal::MAJOR_VERSION}.#{Marshal::MINOR_VERSION}" # Updating the version should require a GitLab API version change. diff --git a/lib/api/search.rb b/lib/api/search.rb index 4ef8fef329c..fd4d46cf77d 100644 --- a/lib/api/search.rb +++ b/lib/api/search.rb @@ -11,6 +11,7 @@ module API end feature_category :global_search + urgency :low rescue_from ActiveRecord::QueryCanceled do |e| render_api_error!({ error: 'Request timed out' }, 408) diff --git a/lib/api/settings.rb b/lib/api/settings.rb index 774ab472f2d..c25a56d5f08 100644 --- a/lib/api/settings.rb +++ b/lib/api/settings.rb @@ -95,6 +95,7 @@ module API optional :invisible_captcha_enabled, type: Boolean, desc: 'Enable Invisible Captcha spam detection during signup.' optional :max_artifacts_size, type: Integer, desc: "Set the maximum file size for each job's artifacts" optional :max_attachment_size, type: Integer, desc: 'Maximum attachment size in MB' + optional :max_export_size, type: Integer, desc: 'Maximum export size in MB' optional :max_import_size, type: Integer, desc: 'Maximum import size in MB' optional :max_pages_size, type: Integer, desc: 'Maximum size of pages in MB' optional :metrics_method_call_threshold, type: Integer, desc: 'A method call is only tracked when it takes longer to complete than the given amount of milliseconds.' @@ -180,6 +181,7 @@ module API optional :runner_token_expiration_interval, type: Integer, desc: 'Token expiration interval for shared runners, in seconds' optional :group_runner_token_expiration_interval, type: Integer, desc: 'Token expiration interval for group runners, in seconds' optional :project_runner_token_expiration_interval, type: Integer, desc: 'Token expiration interval for project runners, in seconds' + optional :pipeline_limit_per_project_user_sha, type: Integer, desc: "Maximum number of pipeline creation requests allowed per minute per user and commit. Set to 0 for unlimited requests per minute." Gitlab::SSHPublicKey.supported_types.each do |type| optional :"#{type}_key_restriction", diff --git a/lib/api/sidekiq_metrics.rb b/lib/api/sidekiq_metrics.rb index c30b9d7583a..bca1376d489 100644 --- a/lib/api/sidekiq_metrics.rb +++ b/lib/api/sidekiq_metrics.rb @@ -10,7 +10,8 @@ module API helpers do def queue_metrics - Sidekiq::Queue.all.each_with_object({}) do |queue, hash| + ::Gitlab::SidekiqConfig.routing_queues.each_with_object({}) do |queue_name, hash| + queue = Sidekiq::Queue.new(queue_name) hash[queue.name] = { backlog: queue.size, latency: queue.latency.to_i diff --git a/lib/api/terraform/modules/v1/packages.rb b/lib/api/terraform/modules/v1/packages.rb index 797b4aad033..8da77ba18ae 100644 --- a/lib/api/terraform/modules/v1/packages.rb +++ b/lib/api/terraform/modules/v1/packages.rb @@ -22,6 +22,7 @@ module API }.freeze feature_category :infrastructure_as_code + urgency :low after_validation do require_packages_enabled! diff --git a/lib/api/terraform/state.rb b/lib/api/terraform/state.rb index 29e71611092..7b111451b9f 100644 --- a/lib/api/terraform/state.rb +++ b/lib/api/terraform/state.rb @@ -8,6 +8,7 @@ module API include ::Gitlab::Utils::StrongMemoize feature_category :infrastructure_as_code + urgency :low default_format :json diff --git a/lib/api/terraform/state_version.rb b/lib/api/terraform/state_version.rb index d3680323b9f..ca37c786666 100644 --- a/lib/api/terraform/state_version.rb +++ b/lib/api/terraform/state_version.rb @@ -6,6 +6,7 @@ module API default_format :json feature_category :infrastructure_as_code + urgency :low before do authenticate! diff --git a/lib/api/todos.rb b/lib/api/todos.rb index 1bc3e25a46c..f1779df7cc6 100644 --- a/lib/api/todos.rb +++ b/lib/api/todos.rb @@ -7,6 +7,7 @@ module API before { authenticate! } feature_category :team_planning + urgency :low ISSUABLE_TYPES = { 'merge_requests' => ->(iid) { find_merge_request_with_access(iid) }, diff --git a/lib/api/topics.rb b/lib/api/topics.rb index e4a1fa2367e..15f79e75be3 100644 --- a/lib/api/topics.rb +++ b/lib/api/topics.rb @@ -38,7 +38,8 @@ module API success Entities::Projects::Topic end params do - requires :name, type: String, desc: 'Name' + requires :name, type: String, desc: 'Slug (name)' + requires :title, type: String, desc: 'Title' optional :description, type: String, desc: 'Description' optional :avatar, type: ::API::Validations::Types::WorkhorseFile, desc: 'Avatar image for topic' end @@ -60,7 +61,8 @@ module API end params do requires :id, type: Integer, desc: 'ID of project topic' - optional :name, type: String, desc: 'Name' + optional :name, type: String, desc: 'Slug (name)' + optional :title, type: String, desc: 'Title' optional :description, type: String, desc: 'Description' optional :avatar, type: ::API::Validations::Types::WorkhorseFile, desc: 'Avatar image for topic' end diff --git a/lib/api/unleash.rb b/lib/api/unleash.rb index 6dadaf4fc54..37fe540cde1 100644 --- a/lib/api/unleash.rb +++ b/lib/api/unleash.rb @@ -30,7 +30,7 @@ module API end desc 'Get a list of features' - get 'client/features', urgency: :medium do + get 'client/features' do present :version, 1 present :features, feature_flags, with: ::API::Entities::UnleashFeature end diff --git a/lib/api/usage_data.rb b/lib/api/usage_data.rb index 43c75206b88..6e81a578d4a 100644 --- a/lib/api/usage_data.rb +++ b/lib/api/usage_data.rb @@ -8,7 +8,7 @@ module API namespace 'usage_data' do before do - not_found! unless Feature.enabled?(:usage_data_api, default_enabled: :yaml, type: :ops) + not_found! unless Feature.enabled?(:usage_data_api, type: :ops) forbidden!('Invalid CSRF token is provided') unless verified_request? end @@ -40,7 +40,7 @@ module API desc 'Get a list of all metric definitions' do detail 'This feature was introduced in GitLab 13.11.' end - get 'metric_definitions' do + get 'metric_definitions', urgency: :low do content_type 'application/yaml' env['api.format'] = :binary diff --git a/lib/api/usage_data_non_sql_metrics.rb b/lib/api/usage_data_non_sql_metrics.rb index 983038e0263..41f369a43b8 100644 --- a/lib/api/usage_data_non_sql_metrics.rb +++ b/lib/api/usage_data_non_sql_metrics.rb @@ -5,10 +5,11 @@ module API before { authenticated_as_admin! } feature_category :service_ping + urgency :low namespace 'usage_data' do before do - not_found! unless Feature.enabled?(:usage_data_non_sql_metrics, default_enabled: :yaml, type: :ops) + not_found! unless Feature.enabled?(:usage_data_non_sql_metrics, type: :ops) end desc 'Get Non SQL usage ping metrics' do diff --git a/lib/api/usage_data_queries.rb b/lib/api/usage_data_queries.rb index 3432e71eb28..fe972942111 100644 --- a/lib/api/usage_data_queries.rb +++ b/lib/api/usage_data_queries.rb @@ -5,10 +5,11 @@ module API before { authenticated_as_admin! } feature_category :service_ping + urgency :low namespace 'usage_data' do before do - not_found! unless Feature.enabled?(:usage_data_queries_api, default_enabled: :yaml, type: :ops) + not_found! unless Feature.enabled?(:usage_data_queries_api, type: :ops) end desc 'Get raw SQL queries for usage data SQL metrics' do diff --git a/lib/api/user_counts.rb b/lib/api/user_counts.rb index e5dfac3b1a1..756901c5717 100644 --- a/lib/api/user_counts.rb +++ b/lib/api/user_counts.rb @@ -19,7 +19,7 @@ module API todos: current_user.todos_pending_count } - if Feature.enabled?(:mr_attention_requests, default_enabled: :yaml) + if current_user&.mr_attention_requests_enabled? counts[:attention_requests] = current_user.attention_requested_open_merge_requests_count end diff --git a/lib/api/users.rb b/lib/api/users.rb index b26611cfe03..b10458c4358 100644 --- a/lib/api/users.rb +++ b/lib/api/users.rb @@ -10,6 +10,8 @@ module API feature_category :users, ['/users/:id/custom_attributes', '/users/:id/custom_attributes/:key'] + urgency :high, ['/users/:id/custom_attributes', '/users/:id/custom_attributes/:key'] + resource :users, requirements: { uid: /[0-9]*/, id: /[0-9]*/ } do include CustomAttributesEndpoints @@ -99,7 +101,7 @@ module API use :optional_index_params_ee end # rubocop: disable CodeReuse/ActiveRecord - get feature_category: :users, urgency: :default do + get feature_category: :users, urgency: :low do authenticated_as_admin! if params[:extern_uid].present? && params[:provider].present? unless current_user&.admin? @@ -781,7 +783,7 @@ module API optional :type, type: String, values: %w[Project Namespace] use :pagination end - get ":user_id/memberships", feature_category: :users do + get ":user_id/memberships", feature_category: :users, urgency: :high do authenticated_as_admin! user = find_user_by_id(params) @@ -1078,7 +1080,7 @@ module API params do use :pagination end - get "emails", feature_category: :users do + get "emails", feature_category: :users, urgency: :high do present paginate(current_user.emails), with: Entities::Email end @@ -1120,7 +1122,7 @@ module API optional :show_whitespace_in_diffs, type: Boolean, desc: 'Flag indicating the user sees whitespace changes in diffs' at_least_one_of :view_diffs_file_by_file, :show_whitespace_in_diffs end - put "preferences", feature_category: :users do + put "preferences", feature_category: :users, urgency: :high do authenticate! preferences = current_user.user_preference |