Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/lib/api
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2021-02-18 13:34:06 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2021-02-18 13:34:06 +0300
commit859a6fb938bb9ee2a317c46dfa4fcc1af49608f0 (patch)
treed7f2700abe6b4ffcb2dcfc80631b2d87d0609239 /lib/api
parent446d496a6d000c73a304be52587cd9bbc7493136 (diff)
Add latest changes from gitlab-org/gitlab@13-9-stable-eev13.9.0-rc42
Diffstat (limited to 'lib/api')
-rw-r--r--lib/api/api.rb37
-rw-r--r--lib/api/applications.rb16
-rw-r--r--lib/api/ci/pipelines.rb1
-rw-r--r--lib/api/concerns/packages/conan_endpoints.rb1
-rw-r--r--lib/api/debian_group_packages.rb4
-rw-r--r--lib/api/debian_package_endpoints.rb21
-rw-r--r--lib/api/debian_project_packages.rb14
-rw-r--r--lib/api/deploy_tokens.rb10
-rw-r--r--lib/api/deployments.rb2
-rw-r--r--lib/api/entities/application_setting.rb1
-rw-r--r--lib/api/entities/ci/job.rb3
-rw-r--r--lib/api/entities/merge_request_basic.rb2
-rw-r--r--lib/api/entities/user.rb7
-rw-r--r--lib/api/entities/user_status.rb1
-rw-r--r--lib/api/events.rb2
-rw-r--r--lib/api/generic_packages.rb4
-rwxr-xr-xlib/api/go_proxy.rb16
-rw-r--r--lib/api/group_labels.rb2
-rw-r--r--lib/api/group_packages.rb4
-rw-r--r--lib/api/helpers.rb22
-rw-r--r--lib/api/helpers/internal_helpers.rb2
-rw-r--r--lib/api/helpers/members_helpers.rb2
-rw-r--r--lib/api/helpers/notes_helpers.rb2
-rw-r--r--lib/api/helpers/rate_limiter.rb4
-rw-r--r--lib/api/internal/base.rb36
-rw-r--r--lib/api/internal/kubernetes.rb2
-rw-r--r--lib/api/issues.rb2
-rw-r--r--lib/api/jobs.rb5
-rw-r--r--lib/api/labels.rb6
-rw-r--r--lib/api/members.rb12
-rw-r--r--lib/api/merge_requests.rb6
-rw-r--r--lib/api/notes.rb4
-rw-r--r--lib/api/nuget_group_packages.rb2
-rw-r--r--lib/api/nuget_project_packages.rb2
-rw-r--r--lib/api/project_packages.rb4
-rw-r--r--lib/api/project_templates.rb18
-rw-r--r--lib/api/projects.rb2
-rw-r--r--lib/api/repositories.rb59
-rw-r--r--lib/api/resource_access_tokens.rb94
-rw-r--r--lib/api/rubygem_packages.rb102
-rw-r--r--lib/api/settings.rb11
-rw-r--r--lib/api/snippet_repository_storage_moves.rb7
-rw-r--r--lib/api/subscriptions.rb5
-rw-r--r--lib/api/suggestions.rb10
-rw-r--r--lib/api/support/git_access_actor.rb2
-rw-r--r--lib/api/users.rb70
-rw-r--r--lib/api/version.rb2
47 files changed, 502 insertions, 141 deletions
diff --git a/lib/api/api.rb b/lib/api/api.rb
index ada0da28749..0598f03c7ab 100644
--- a/lib/api/api.rb
+++ b/lib/api/api.rb
@@ -30,7 +30,7 @@ module API
]
allow_access_with_scope :api
- allow_access_with_scope :read_api, if: -> (request) { request.get? }
+ allow_access_with_scope :read_api, if: -> (request) { request.get? || request.head? }
prefix :api
version 'v3', using: :path do
@@ -68,6 +68,10 @@ module API
set_peek_enabled_for_current_request
end
+ after do
+ Gitlab::UsageDataCounters::VSCodeExtensionActivityUniqueCounter.track_api_request_when_trackable(user_agent: request&.user_agent, user: @current_user)
+ end
+
# The locale is set to the current user's locale when `current_user` is loaded
after { Gitlab::I18n.use_default_locale }
@@ -123,13 +127,32 @@ module API
format :json
formatter :json, Gitlab::Json::GrapeFormatter
+ content_type :json, 'application/json'
+ # Remove the `text/plain+deprecated` with `api_always_use_application_json` feature flag
# There is a small chance some users depend on the old behavior.
# We this change under a feature flag to see if affects GitLab.com users.
- if Gitlab::Database.cached_table_exists?('features') && Feature.enabled?(:api_json_content_type)
- content_type :json, 'application/json'
- else
- content_type :txt, 'text/plain'
+ # The `+deprecated` is added to distinguish content type
+ # as defined by `API::API` vs ex. `API::Repositories`
+ content_type :txt, 'text/plain+deprecated'
+
+ before do
+ # the feature flag workaround is only for `.txt`
+ api_format = env[Grape::Env::API_FORMAT]
+ next unless api_format == :txt
+
+ # get all defined content-types for the endpoint
+ api_endpoint = env[Grape::Env::API_ENDPOINT]
+ content_types = api_endpoint&.namespace_stackable_with_hash(:content_types).to_h
+
+ # Only overwrite `text/plain+deprecated`
+ if content_types[api_format] == 'text/plain+deprecated'
+ if Feature.enabled?(:api_always_use_application_json)
+ content_type 'application/json'
+ else
+ content_type 'text/plain'
+ end
+ end
end
# Ensure the namespace is right, otherwise we might load Grape::API::Helpers
@@ -249,6 +272,8 @@ module API
mount ::API::Release::Links
mount ::API::RemoteMirrors
mount ::API::Repositories
+ mount ::API::ResourceAccessTokens
+ mount ::API::RubygemPackages
mount ::API::Search
mount ::API::Services
mount ::API::Settings
@@ -294,4 +319,4 @@ module API
end
end
-API::API.prepend_if_ee('::EE::API::API')
+API::API.prepend_ee_mod
diff --git a/lib/api/applications.rb b/lib/api/applications.rb
index 8b14e16b495..b883f83cc19 100644
--- a/lib/api/applications.rb
+++ b/lib/api/applications.rb
@@ -8,15 +8,6 @@ module API
feature_category :authentication_and_authorization
resource :applications do
- helpers do
- def validate_redirect_uri(value)
- uri = ::URI.parse(value)
- !uri.is_a?(URI::HTTP) || uri.host
- rescue URI::InvalidURIError
- false
- end
- end
-
desc 'Create a new application' do
detail 'This feature was introduced in GitLab 10.5'
success Entities::ApplicationWithSecret
@@ -30,13 +21,6 @@ module API
desc: 'Application will be used where the client secret is confidential'
end
post do
- # Validate that host in uri is specified
- # Please remove it when https://github.com/doorkeeper-gem/doorkeeper/pull/1440 is merged
- # and the doorkeeper gem version is bumped
- unless validate_redirect_uri(declared_params[:redirect_uri])
- render_api_error!({ redirect_uri: ["must be an absolute URI."] }, :bad_request)
- end
-
application = Doorkeeper::Application.new(declared_params)
if application.save
diff --git a/lib/api/ci/pipelines.rb b/lib/api/ci/pipelines.rb
index 1b36e27f6c9..fa75d012613 100644
--- a/lib/api/ci/pipelines.rb
+++ b/lib/api/ci/pipelines.rb
@@ -121,6 +121,7 @@ module API
end
params do
requires :pipeline_id, type: Integer, desc: 'The pipeline ID'
+ optional :include_retried, type: Boolean, default: false, desc: 'Includes retried jobs'
use :optional_scope
use :pagination
end
diff --git a/lib/api/concerns/packages/conan_endpoints.rb b/lib/api/concerns/packages/conan_endpoints.rb
index 6c8b3a1ba4a..1796d51324f 100644
--- a/lib/api/concerns/packages/conan_endpoints.rb
+++ b/lib/api/concerns/packages/conan_endpoints.rb
@@ -72,6 +72,7 @@ module API
namespace 'users' do
format :txt
+ content_type :txt, 'text/plain'
desc 'Authenticate user against conan CLI' do
detail 'This feature was introduced in GitLab 12.2'
diff --git a/lib/api/debian_group_packages.rb b/lib/api/debian_group_packages.rb
index e3cacc4132f..f138f400601 100644
--- a/lib/api/debian_group_packages.rb
+++ b/lib/api/debian_group_packages.rb
@@ -8,12 +8,14 @@ module API
resource :groups, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
before do
+ require_packages_enabled!
+
not_found! unless ::Feature.enabled?(:debian_packages, user_group)
authorize_read_package!(user_group)
end
- namespace ':id/-/packages/debian' do
+ namespace ':id/packages/debian' do
include DebianPackageEndpoints
end
end
diff --git a/lib/api/debian_package_endpoints.rb b/lib/api/debian_package_endpoints.rb
index c95c75b7e5c..e7689b3feff 100644
--- a/lib/api/debian_package_endpoints.rb
+++ b/lib/api/debian_package_endpoints.rb
@@ -32,6 +32,7 @@ module API
helpers ::API::Helpers::Packages::BasicAuthHelpers
format :txt
+ content_type :txt, 'text/plain'
rescue_from ArgumentError do |e|
render_api_error!(e.message, 400)
@@ -50,33 +51,33 @@ module API
end
namespace 'dists/*distribution', requirements: DISTRIBUTION_REQUIREMENTS do
- # GET {projects|groups}/:id/-/packages/debian/dists/*distribution/Release.gpg
+ # GET {projects|groups}/:id/packages/debian/dists/*distribution/Release.gpg
desc 'The Release file signature' do
detail 'This feature was introduced in GitLab 13.5'
end
- route_setting :authentication, deploy_token_allowed: true, basic_auth_personal_access_token: true, job_token_allowed: :basic_auth
+ route_setting :authentication, deploy_token_allowed: true, basic_auth_personal_access_token: true, job_token_allowed: :basic_auth, authenticate_non_public: true
get 'Release.gpg' do
not_found!
end
- # GET {projects|groups}/:id/-/packages/debian/dists/*distribution/Release
+ # GET {projects|groups}/:id/packages/debian/dists/*distribution/Release
desc 'The unsigned Release file' do
detail 'This feature was introduced in GitLab 13.5'
end
- route_setting :authentication, deploy_token_allowed: true, basic_auth_personal_access_token: true, job_token_allowed: :basic_auth
+ route_setting :authentication, deploy_token_allowed: true, basic_auth_personal_access_token: true, job_token_allowed: :basic_auth, authenticate_non_public: true
get 'Release' do
# https://gitlab.com/gitlab-org/gitlab/-/issues/5835#note_414103286
'TODO Release'
end
- # GET {projects|groups}/:id/-/packages/debian/dists/*distribution/InRelease
+ # GET {projects|groups}/:id/packages/debian/dists/*distribution/InRelease
desc 'The signed Release file' do
detail 'This feature was introduced in GitLab 13.5'
end
- route_setting :authentication, deploy_token_allowed: true, basic_auth_personal_access_token: true, job_token_allowed: :basic_auth
+ route_setting :authentication, deploy_token_allowed: true, basic_auth_personal_access_token: true, job_token_allowed: :basic_auth, authenticate_non_public: true
get 'InRelease' do
not_found!
end
@@ -87,12 +88,12 @@ module API
end
namespace ':component/binary-:architecture', requirements: COMPONENT_ARCHITECTURE_REQUIREMENTS do
- # GET {projects|groups}/:id/-/packages/debian/dists/*distribution/:component/binary-:architecture/Packages
+ # GET {projects|groups}/:id/packages/debian/dists/*distribution/:component/binary-:architecture/Packages
desc 'The binary files index' do
detail 'This feature was introduced in GitLab 13.5'
end
- route_setting :authentication, deploy_token_allowed: true, basic_auth_personal_access_token: true, job_token_allowed: :basic_auth
+ route_setting :authentication, deploy_token_allowed: true, basic_auth_personal_access_token: true, job_token_allowed: :basic_auth, authenticate_non_public: true
get 'Packages' do
# https://gitlab.com/gitlab-org/gitlab/-/issues/5835#note_414103286
'TODO Packages'
@@ -107,7 +108,7 @@ module API
end
namespace 'pool/:component/:letter/:source_package', requirements: COMPONENT_LETTER_SOURCE_PACKAGE_REQUIREMENTS do
- # GET {projects|groups}/:id/-/packages/debian/pool/:component/:letter/:source_package/:file_name
+ # GET {projects|groups}/:id/packages/debian/pool/:component/:letter/:source_package/:file_name
params do
requires :file_name, type: String, desc: 'The Debian File Name'
end
@@ -115,7 +116,7 @@ module API
detail 'This feature was introduced in GitLab 13.5'
end
- route_setting :authentication, deploy_token_allowed: true, basic_auth_personal_access_token: true, job_token_allowed: :basic_auth
+ route_setting :authentication, deploy_token_allowed: true, basic_auth_personal_access_token: true, job_token_allowed: :basic_auth, authenticate_non_public: true
get ':file_name', requirements: FILE_NAME_REQUIREMENTS do
# https://gitlab.com/gitlab-org/gitlab/-/issues/5835#note_414103286
'TODO File'
diff --git a/lib/api/debian_project_packages.rb b/lib/api/debian_project_packages.rb
index f8129c18dff..8c0db42a448 100644
--- a/lib/api/debian_project_packages.rb
+++ b/lib/api/debian_project_packages.rb
@@ -8,27 +8,29 @@ module API
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
before do
+ require_packages_enabled!
+
not_found! unless ::Feature.enabled?(:debian_packages, user_project)
authorize_read_package!
end
- namespace ':id/-/packages/debian' do
+ namespace ':id/packages/debian' do
include DebianPackageEndpoints
params do
requires :file_name, type: String, desc: 'The file name'
end
- namespace 'incoming/:file_name', requirements: FILE_NAME_REQUIREMENTS do
+ namespace ':file_name', requirements: FILE_NAME_REQUIREMENTS do
content_type :json, Gitlab::Workhorse::INTERNAL_API_CONTENT_TYPE
- # PUT {projects|groups}/:id/-/packages/debian/incoming/:file_name
+ # PUT {projects|groups}/:id/packages/debian/:file_name
params do
requires :file, type: ::API::Validations::Types::WorkhorseFile, desc: 'The package file to be published (generated by Multipart middleware)'
end
- route_setting :authentication, deploy_token_allowed: true, basic_auth_personal_access_token: true, job_token_allowed: :basic_auth
+ route_setting :authentication, deploy_token_allowed: true, basic_auth_personal_access_token: true, job_token_allowed: :basic_auth, authenticate_non_public: true
put do
authorize_upload!(authorized_user_project)
bad_request!('File is too large') if authorized_user_project.actual_limits.exceeded?(:debian_max_file_size, params[:file].size)
@@ -42,8 +44,8 @@ module API
forbidden!
end
- # PUT {projects|groups}/:id/-/packages/debian/incoming/:file_name/authorize
- route_setting :authentication, deploy_token_allowed: true, basic_auth_personal_access_token: true, job_token_allowed: :basic_auth
+ # PUT {projects|groups}/:id/packages/debian/:file_name/authorize
+ route_setting :authentication, deploy_token_allowed: true, basic_auth_personal_access_token: true, job_token_allowed: :basic_auth, authenticate_non_public: true
put 'authorize' do
authorize_workhorse!(
subject: authorized_user_project,
diff --git a/lib/api/deploy_tokens.rb b/lib/api/deploy_tokens.rb
index 5fab590eb4e..30ec4e52b2a 100644
--- a/lib/api/deploy_tokens.rb
+++ b/lib/api/deploy_tokens.rb
@@ -28,8 +28,6 @@ module API
use :pagination
end
get 'deploy_tokens' do
- service_unavailable! unless Feature.enabled?(:deploy_tokens_api, default_enabled: true)
-
authenticated_as_admin!
present paginate(DeployToken.all), with: Entities::DeployToken
@@ -39,10 +37,6 @@ module API
requires :id, type: String, desc: 'The ID of a project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
- before do
- service_unavailable! unless Feature.enabled?(:deploy_tokens_api, user_project, default_enabled: true)
- end
-
params do
use :pagination
end
@@ -102,10 +96,6 @@ module API
requires :id, type: String, desc: 'The ID of a group'
end
resource :groups, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
- before do
- service_unavailable! unless Feature.enabled?(:deploy_tokens_api, user_group, default_enabled: true)
- end
-
params do
use :pagination
end
diff --git a/lib/api/deployments.rb b/lib/api/deployments.rb
index 5346fcf03c9..d0c842bb19d 100644
--- a/lib/api/deployments.rb
+++ b/lib/api/deployments.rb
@@ -36,7 +36,7 @@ module API
get ':id/deployments' do
authorize! :read_deployment, user_project
- deployments = DeploymentsFinder.new(user_project, params).execute
+ deployments = DeploymentsFinder.new(params.merge(project: user_project)).execute
present paginate(deployments), with: Entities::Deployment
end
diff --git a/lib/api/entities/application_setting.rb b/lib/api/entities/application_setting.rb
index e9572a8d430..2468c1f9b18 100644
--- a/lib/api/entities/application_setting.rb
+++ b/lib/api/entities/application_setting.rb
@@ -31,6 +31,7 @@ module API
expose :password_authentication_enabled_for_web, as: :password_authentication_enabled
expose :password_authentication_enabled_for_web, as: :signin_enabled
expose :allow_local_requests_from_web_hooks_and_services, as: :allow_local_requests_from_hooks_and_services
+ expose :asset_proxy_allowlist, as: :asset_proxy_whitelist
end
end
end
diff --git a/lib/api/entities/ci/job.rb b/lib/api/entities/ci/job.rb
index 7fe1a802e24..76487ed01dc 100644
--- a/lib/api/entities/ci/job.rb
+++ b/lib/api/entities/ci/job.rb
@@ -9,6 +9,9 @@ module API
expose :job_artifacts, as: :artifacts, using: ::API::Entities::Ci::JobArtifact
expose :runner, with: ::API::Entities::Runner
expose :artifacts_expire_at
+ expose :tag_list do |job|
+ job.tags.map(&:name).sort
+ end
end
end
end
diff --git a/lib/api/entities/merge_request_basic.rb b/lib/api/entities/merge_request_basic.rb
index 7f1b5b87725..88c84c494e2 100644
--- a/lib/api/entities/merge_request_basic.rb
+++ b/lib/api/entities/merge_request_basic.rb
@@ -27,7 +27,7 @@ module API
expose(:downvotes) { |merge_request, options| issuable_metadata.downvotes }
expose :author, :assignees, :assignee, using: Entities::UserBasic
- expose :reviewers, if: -> (merge_request, _) { merge_request.allows_reviewers? }, using: Entities::UserBasic
+ expose :reviewers, using: Entities::UserBasic
expose :source_project_id, :target_project_id
expose :labels do |merge_request, options|
if options[:with_labels_details]
diff --git a/lib/api/entities/user.rb b/lib/api/entities/user.rb
index 4aa5c9b7236..248a86751d2 100644
--- a/lib/api/entities/user.rb
+++ b/lib/api/entities/user.rb
@@ -6,9 +6,16 @@ module API
include UsersHelper
expose :created_at, if: ->(user, opts) { Ability.allowed?(opts[:current_user], :read_user_profile, user) }
expose :bio, :bio_html, :location, :public_email, :skype, :linkedin, :twitter, :website_url, :organization, :job_title
+ expose :bot?, as: :bot
expose :work_information do |user|
work_information(user)
end
+ expose :followers, if: ->(user, opts) { Ability.allowed?(opts[:current_user], :read_user_profile, user) } do |user|
+ user.followers.count
+ end
+ expose :following, if: ->(user, opts) { Ability.allowed?(opts[:current_user], :read_user_profile, user) } do |user|
+ user.followees.count
+ end
end
end
end
diff --git a/lib/api/entities/user_status.rb b/lib/api/entities/user_status.rb
index 1d5cc27e5ef..ef4772f60c6 100644
--- a/lib/api/entities/user_status.rb
+++ b/lib/api/entities/user_status.rb
@@ -9,6 +9,7 @@ module API
expose :message_html do |entity|
MarkupHelper.markdown_field(entity, :message)
end
+ expose :clear_status_at
end
end
end
diff --git a/lib/api/events.rb b/lib/api/events.rb
index 233c62b5389..db5ed7b7e6e 100644
--- a/lib/api/events.rb
+++ b/lib/api/events.rb
@@ -6,7 +6,7 @@ module API
include APIGuard
helpers ::API::Helpers::EventsHelpers
- allow_access_with_scope :read_user, if: -> (request) { request.get? }
+ allow_access_with_scope :read_user, if: -> (request) { request.get? || request.head? }
feature_category :users
diff --git a/lib/api/generic_packages.rb b/lib/api/generic_packages.rb
index 167531fdaec..24d726f4a41 100644
--- a/lib/api/generic_packages.rb
+++ b/lib/api/generic_packages.rb
@@ -7,6 +7,8 @@ module API
file_name: API::NO_SLASH_URL_PART_REGEX
}.freeze
+ ALLOWED_STATUSES = %w[default hidden].freeze
+
feature_category :package_registry
before do
@@ -35,6 +37,7 @@ module API
requires :package_name, type: String, desc: 'Package name', regexp: Gitlab::Regex.generic_package_name_regex, file_path: true
requires :package_version, type: String, desc: 'Package version', regexp: Gitlab::Regex.generic_package_version_regex
requires :file_name, type: String, desc: 'Package file name', regexp: Gitlab::Regex.generic_package_file_name_regex, file_path: true
+ optional :status, type: String, values: ALLOWED_STATUSES, desc: 'Package status'
end
put 'authorize' do
@@ -49,6 +52,7 @@ module API
requires :package_name, type: String, desc: 'Package name', regexp: Gitlab::Regex.generic_package_name_regex, file_path: true
requires :package_version, type: String, desc: 'Package version', regexp: Gitlab::Regex.generic_package_version_regex
requires :file_name, type: String, desc: 'Package file name', regexp: Gitlab::Regex.generic_package_file_name_regex, file_path: true
+ optional :status, type: String, values: ALLOWED_STATUSES, desc: 'Package status'
requires :file, type: ::API::Validations::Types::WorkhorseFile, desc: 'The package file to be published (generated by Multipart middleware)'
end
diff --git a/lib/api/go_proxy.rb b/lib/api/go_proxy.rb
index 2d978019f2a..ea30f17522e 100755
--- a/lib/api/go_proxy.rb
+++ b/lib/api/go_proxy.rb
@@ -30,20 +30,6 @@ module API
str.gsub(/![[:alpha:]]/) { |s| s[1..].upcase }
end
- def find_project!(id)
- # based on API::Helpers::Packages::BasicAuthHelpers#authorized_project_find!
-
- project = find_project(id)
-
- return project if project && can?(current_user, :read_project, project)
-
- if current_user
- not_found!('Project')
- else
- unauthorized!
- end
- end
-
def find_module
not_found! unless Feature.enabled?(:go_proxy, user_project)
@@ -74,7 +60,7 @@ module API
requires :id, type: String, desc: 'The ID of a project'
requires :module_name, type: String, desc: 'Module name', coerce_with: ->(val) { CGI.unescape(val) }
end
- route_setting :authentication, job_token_allowed: true, basic_auth_personal_access_token: true
+ route_setting :authentication, job_token_allowed: true, basic_auth_personal_access_token: true, authenticate_non_public: true
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
before do
authorize_read_package!
diff --git a/lib/api/group_labels.rb b/lib/api/group_labels.rb
index 7fbf4445116..bea538441ee 100644
--- a/lib/api/group_labels.rb
+++ b/lib/api/group_labels.rb
@@ -12,7 +12,7 @@ module API
params do
requires :id, type: String, desc: 'The ID of a group'
end
- resource :groups, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
+ resource :groups, requirements: ::API::Labels::LABEL_ENDPOINT_REQUIREMENTS do
desc 'Get all labels of the group' do
detail 'This feature was added in GitLab 11.8'
success Entities::GroupLabel
diff --git a/lib/api/group_packages.rb b/lib/api/group_packages.rb
index d482f4d0585..ab4e91ff925 100644
--- a/lib/api/group_packages.rb
+++ b/lib/api/group_packages.rb
@@ -33,12 +33,14 @@ module API
desc: 'Return packages with this name'
optional :include_versionless, type: Boolean,
desc: 'Returns packages without a version'
+ optional :status, type: String, values: Packages::Package.statuses.keys,
+ desc: 'Return packages with specified status'
end
get ':id/packages' do
packages = Packages::GroupPackagesFinder.new(
current_user,
user_group,
- declared(params).slice(:exclude_subgroups, :order_by, :sort, :package_type, :package_name, :include_versionless)
+ declared(params).slice(:exclude_subgroups, :order_by, :sort, :package_type, :package_name, :include_versionless, :status)
).execute
present paginate(packages), with: ::API::Entities::Package, user: current_user, group: true
diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb
index 79af9c37378..0abb21c9831 100644
--- a/lib/api/helpers.rb
+++ b/lib/api/helpers.rb
@@ -119,11 +119,10 @@ module API
def find_project!(id)
project = find_project(id)
- if can?(current_user, :read_project, project)
- project
- else
- not_found!('Project')
- end
+ return project if can?(current_user, :read_project, project)
+ return unauthorized! if authenticate_non_public?
+
+ not_found!('Project')
end
# rubocop: disable CodeReuse/ActiveRecord
@@ -139,11 +138,10 @@ module API
def find_group!(id)
group = find_group(id)
- if can?(current_user, :read_group, group)
- group
- else
- not_found!('Group')
- end
+ return group if can?(current_user, :read_group, group)
+ return unauthorized! if authenticate_non_public?
+
+ not_found!('Group')
end
def check_namespace_access(namespace)
@@ -657,6 +655,10 @@ module API
Gitlab::Shell.secret_token
end
+ def authenticate_non_public?
+ route_authentication_setting[:authenticate_non_public] && !current_user
+ end
+
def send_git_blob(repository, blob)
env['api.format'] = :txt
content_type 'text/plain'
diff --git a/lib/api/helpers/internal_helpers.rb b/lib/api/helpers/internal_helpers.rb
index 12b0a053e79..9a1ff2ba8ce 100644
--- a/lib/api/helpers/internal_helpers.rb
+++ b/lib/api/helpers/internal_helpers.rb
@@ -124,7 +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
+ 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 8aed578905e..2de077b5a3b 100644
--- a/lib/api/helpers/members_helpers.rb
+++ b/lib/api/helpers/members_helpers.rb
@@ -1,7 +1,5 @@
# frozen_string_literal: true
-# rubocop:disable GitlabSecurity/PublicSend
-
module API
module Helpers
module MembersHelpers
diff --git a/lib/api/helpers/notes_helpers.rb b/lib/api/helpers/notes_helpers.rb
index 6798c4d284b..71a18524104 100644
--- a/lib/api/helpers/notes_helpers.rb
+++ b/lib/api/helpers/notes_helpers.rb
@@ -138,7 +138,7 @@ module API
parent = noteable_parent(noteable)
::Discussions::ResolveService.new(parent, current_user, one_or_more_discussions: discussion).execute
else
- discussion.unresolve!
+ ::Discussions::UnresolveService.new(discussion, current_user).execute
end
present discussion, with: Entities::Discussion
diff --git a/lib/api/helpers/rate_limiter.rb b/lib/api/helpers/rate_limiter.rb
index 5a531b5324a..3a16aef6a74 100644
--- a/lib/api/helpers/rate_limiter.rb
+++ b/lib/api/helpers/rate_limiter.rb
@@ -3,8 +3,8 @@
module API
module Helpers
module RateLimiter
- def check_rate_limit!(key, scope)
- if rate_limiter.throttled?(key, scope: scope)
+ def check_rate_limit!(key, scope, users_allowlist = nil)
+ if rate_limiter.throttled?(key, scope: scope, users_allowlist: users_allowlist)
log_request(key)
render_exceeded_limit_error!
end
diff --git a/lib/api/internal/base.rb b/lib/api/internal/base.rb
index 12bb6e77c3e..a3fee49cd8f 100644
--- a/lib/api/internal/base.rb
+++ b/lib/api/internal/base.rb
@@ -52,7 +52,9 @@ module API
actor.update_last_used_at!
check_result = begin
- access_check!(actor, params)
+ Gitlab::Auth::CurrentUserMode.bypass_session!(actor.user&.id) do
+ access_check!(actor, params)
+ end
rescue Gitlab::GitAccess::ForbiddenError => e
# The return code needs to be 401. If we return 403
# the custom message we return won't be shown to the user
@@ -114,6 +116,10 @@ module API
'Could not find a user for the given key' unless actor.user
end
+
+ def two_factor_otp_check
+ { success: false, message: 'Feature is not available' }
+ end
end
namespace 'internal' do
@@ -276,6 +282,11 @@ module API
present response, with: Entities::InternalPostReceive::Response
end
+ # This endpoint was added in https://gitlab.com/gitlab-org/gitlab/-/issues/212308
+ # It was added with the plan to be used by GitLab PAM module but we
+ # decided to pursue a different approach, so it's currently not used.
+ # We might revive the PAM module though as it provides better user
+ # flow.
post '/two_factor_config', feature_category: :authentication_and_authorization do
status 200
@@ -301,28 +312,7 @@ module API
post '/two_factor_otp_check', feature_category: :authentication_and_authorization do
status 200
- break { success: false, message: 'Feature flag is disabled' } unless Feature.enabled?(:two_factor_for_cli)
-
- actor.update_last_used_at!
- user = actor.user
-
- error_message = validate_actor_key(actor, params[:key_id])
-
- break { success: false, message: error_message } if error_message
-
- break { success: false, message: 'Deploy keys cannot be used for Two Factor' } if actor.key.is_a?(DeployKey)
-
- break { success: false, message: 'Two-factor authentication is not enabled for this user' } unless user.two_factor_enabled?
-
- otp_validation_result = ::Users::ValidateOtpService.new(user).execute(params.fetch(:otp_attempt))
-
- if otp_validation_result[:status] == :success
- ::Gitlab::Auth::Otp::SessionEnforcer.new(actor.key).update_session
-
- { success: true }
- else
- { success: false, message: 'Invalid OTP' }
- end
+ two_factor_otp_check
end
end
end
diff --git a/lib/api/internal/kubernetes.rb b/lib/api/internal/kubernetes.rb
index 73723a96401..87ad79d601f 100644
--- a/lib/api/internal/kubernetes.rb
+++ b/lib/api/internal/kubernetes.rb
@@ -52,6 +52,8 @@ module API
def check_agent_token
forbidden! unless agent_token
+
+ forbidden! unless Gitlab::Kas.included_in_gitlab_com_rollout?(agent.project)
end
end
diff --git a/lib/api/issues.rb b/lib/api/issues.rb
index 73e2163248d..ea09174f03a 100644
--- a/lib/api/issues.rb
+++ b/lib/api/issues.rb
@@ -231,7 +231,7 @@ module API
post ':id/issues' do
Gitlab::QueryLimiting.whitelist('https://gitlab.com/gitlab-org/gitlab-foss/issues/42320')
- check_rate_limit! :issues_create, [current_user, :issues_create]
+ check_rate_limit! :issues_create, [current_user]
authorize! :create_issue, user_project
diff --git a/lib/api/jobs.rb b/lib/api/jobs.rb
index e14a4a5e680..390dbc892e2 100644
--- a/lib/api/jobs.rb
+++ b/lib/api/jobs.rb
@@ -45,7 +45,7 @@ module API
builds = user_project.builds.order('id DESC')
builds = filter_builds(builds, params[:scope])
- builds = builds.preload(:user, :job_artifacts_archive, :job_artifacts, :runner, pipeline: :project)
+ builds = builds.preload(:user, :job_artifacts_archive, :job_artifacts, :runner, :tags, pipeline: :project)
present paginate(builds), with: Entities::Ci::Job
end
# rubocop: enable CodeReuse/ActiveRecord
@@ -82,7 +82,8 @@ module API
content_type 'text/plain'
env['api.format'] = :binary
- trace = build.trace.raw
+ # The trace can be nil bu body method expects a string as an argument.
+ trace = build.trace.raw || ''
body trace
end
diff --git a/lib/api/labels.rb b/lib/api/labels.rb
index c9f29865664..aa3746dae42 100644
--- a/lib/api/labels.rb
+++ b/lib/api/labels.rb
@@ -9,10 +9,14 @@ module API
feature_category :issue_tracking
+ LABEL_ENDPOINT_REQUIREMENTS = API::NAMESPACE_OR_PROJECT_REQUIREMENTS.merge(
+ name: API::NO_SLASH_URL_PART_REGEX,
+ label_id: API::NO_SLASH_URL_PART_REGEX)
+
params do
requires :id, type: String, desc: 'The ID of a project'
end
- resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
+ resource :projects, requirements: LABEL_ENDPOINT_REQUIREMENTS do
desc 'Get all labels of the project' do
success Entities::ProjectLabel
end
diff --git a/lib/api/members.rb b/lib/api/members.rb
index 9bea74e2ce9..42f608102b3 100644
--- a/lib/api/members.rb
+++ b/lib/api/members.rb
@@ -137,12 +137,14 @@ module API
authorize_admin_source!(source_type, source)
member = source_members(source).find_by!(user_id: params[:user_id])
- updated_member =
- ::Members::UpdateService
- .new(current_user, declared_params(include_missing: false))
- .execute(member)
- if updated_member.valid?
+ result = ::Members::UpdateService
+ .new(current_user, declared_params(include_missing: false))
+ .execute(member)
+
+ updated_member = result[:member]
+
+ if result[:status] == :success
present_members updated_member
else
render_validation_error!(updated_member)
diff --git a/lib/api/merge_requests.rb b/lib/api/merge_requests.rb
index 142ecd0dc1e..5051c1a5529 100644
--- a/lib/api/merge_requests.rb
+++ b/lib/api/merge_requests.rb
@@ -26,6 +26,7 @@ module API
%i[
assignee_id
assignee_ids
+ reviewer_ids
description
labels
add_labels
@@ -160,7 +161,8 @@ module API
helpers do
params :optional_params do
optional :assignee_id, type: Integer, desc: 'The ID of a user to assign the merge request'
- optional :assignee_ids, type: Array[Integer], coerce_with: ::API::Validations::Types::CommaSeparatedToIntegerArray.coerce, desc: 'The array of user IDs to assign issue'
+ optional :assignee_ids, type: Array[Integer], coerce_with: ::API::Validations::Types::CommaSeparatedToIntegerArray.coerce, desc: 'Comma-separated list of assignee ids'
+ optional :reviewer_ids, type: Array[Integer], coerce_with: ::API::Validations::Types::CommaSeparatedToIntegerArray.coerce, desc: 'Comma-separated list of reviewer ids'
optional :description, type: String, desc: 'The description of the merge request'
optional :labels, type: Array[String], coerce_with: Validations::Types::CommaSeparatedToArray.coerce, desc: 'Comma-separated list of label names'
optional :add_labels, type: Array[String], coerce_with: Validations::Types::CommaSeparatedToArray.coerce, desc: 'Comma-separated list of label names'
@@ -368,7 +370,7 @@ module API
with: Entities::MergeRequestChanges,
current_user: current_user,
project: user_project,
- access_raw_diffs: params.fetch(:access_raw_diffs, false)
+ access_raw_diffs: to_boolean(params.fetch(:access_raw_diffs, false))
end
desc 'Get the merge request pipelines' do
diff --git a/lib/api/notes.rb b/lib/api/notes.rb
index d249431b2f8..418efe3d1a7 100644
--- a/lib/api/notes.rb
+++ b/lib/api/notes.rb
@@ -4,6 +4,7 @@ module API
class Notes < ::API::Base
include PaginationParams
helpers ::API::Helpers::NotesHelpers
+ helpers Helpers::RateLimiter
before { authenticate! }
@@ -72,6 +73,9 @@ module API
optional :created_at, type: String, desc: 'The creation date of the note'
end
post ":id/#{noteables_str}/:noteable_id/notes", feature_category: feature_category do
+ allowlist =
+ Gitlab::CurrentSettings.current_application_settings.notes_create_limit_allowlist
+ check_rate_limit! :notes_create, [current_user], allowlist
noteable = find_noteable(noteable_type, params[:noteable_id])
opts = {
diff --git a/lib/api/nuget_group_packages.rb b/lib/api/nuget_group_packages.rb
index e373f051b24..a80de06d6b0 100644
--- a/lib/api/nuget_group_packages.rb
+++ b/lib/api/nuget_group_packages.rb
@@ -18,7 +18,7 @@ module API
default_format :json
authenticate_with do |accept|
- accept.token_types(:personal_access_token, :deploy_token, :job_token)
+ accept.token_types(:personal_access_token_with_username, :deploy_token_with_username, :job_token_with_username)
.sent_through(:http_basic_auth)
end
diff --git a/lib/api/nuget_project_packages.rb b/lib/api/nuget_project_packages.rb
index 2146f4d4b78..e071b6bd68f 100644
--- a/lib/api/nuget_project_packages.rb
+++ b/lib/api/nuget_project_packages.rb
@@ -20,7 +20,7 @@ module API
default_format :json
authenticate_with do |accept|
- accept.token_types(:personal_access_token, :deploy_token, :job_token)
+ accept.token_types(:personal_access_token_with_username, :deploy_token_with_username, :job_token_with_username)
.sent_through(:http_basic_auth)
end
diff --git a/lib/api/project_packages.rb b/lib/api/project_packages.rb
index 32636662987..0fdaa4b2656 100644
--- a/lib/api/project_packages.rb
+++ b/lib/api/project_packages.rb
@@ -32,11 +32,13 @@ module API
desc: 'Return packages with this name'
optional :include_versionless, type: Boolean,
desc: 'Returns packages without a version'
+ optional :status, type: String, values: Packages::Package.statuses.keys,
+ desc: 'Return packages with specified status'
end
get ':id/packages' do
packages = ::Packages::PackagesFinder.new(
user_project,
- declared_params.slice(:order_by, :sort, :package_type, :package_name, :include_versionless)
+ declared_params.slice(:order_by, :sort, :package_type, :package_name, :include_versionless, :status)
).execute
present paginate(packages), with: ::API::Entities::Package, user: current_user
diff --git a/lib/api/project_templates.rb b/lib/api/project_templates.rb
index 19244ed697f..fdfdc244cbe 100644
--- a/lib/api/project_templates.rb
+++ b/lib/api/project_templates.rb
@@ -26,9 +26,7 @@ module API
use :pagination
end
get ':id/templates/:type' do
- templates = TemplateFinder
- .build(params[:type], user_project)
- .execute
+ templates = TemplateFinder.all_template_names_array(user_project, params[:type])
present paginate(::Kaminari.paginate_array(templates)), with: Entities::TemplatesList
end
@@ -38,16 +36,22 @@ module API
end
params do
requires :name, type: String, desc: 'The name of the template'
-
+ optional :source_template_project_id, type: Integer,
+ desc: 'The project id where a given template is being stored. This is useful when multiple templates from different projects have the same name'
optional :project, type: String, desc: 'The project name to use when expanding placeholders in the template. Only affects licenses'
optional :fullname, type: String, desc: 'The full name of the copyright holder to use when expanding placeholders in the template. Only affects licenses'
end
get ':id/templates/:type/:name', requirements: TEMPLATE_NAMES_ENDPOINT_REQUIREMENTS do
begin
- template = TemplateFinder
- .build(params[:type], user_project, name: params[:name])
- .execute
+ template = TemplateFinder.build(
+ params[:type],
+ user_project,
+ {
+ name: params[:name],
+ source_template_project_id: params[:source_template_project_id]
+ }
+ ).execute
rescue ::Gitlab::Template::Finders::RepoTemplateFinder::FileNotFoundError
not_found!('Template')
end
diff --git a/lib/api/projects.rb b/lib/api/projects.rb
index 2d09ad01757..fca68c3606b 100644
--- a/lib/api/projects.rb
+++ b/lib/api/projects.rb
@@ -295,6 +295,8 @@ module API
optional :namespace_path, type: String, desc: 'The path of the namespace that the project will be forked into'
optional :path, type: String, desc: 'The path that will be assigned to the fork'
optional :name, type: String, desc: 'The name that will be assigned to the fork'
+ optional :description, type: String, desc: 'The description that will be assigned to the fork'
+ optional :visibility, type: String, values: Gitlab::VisibilityLevel.string_values, desc: 'The visibility of the fork'
end
post ':id/fork', feature_category: :source_code_management do
Gitlab::QueryLimiting.whitelist('https://gitlab.com/gitlab-org/gitlab-foss/issues/42284')
diff --git a/lib/api/repositories.rb b/lib/api/repositories.rb
index 8af8ffc3b63..eaedd53aedb 100644
--- a/lib/api/repositories.rb
+++ b/lib/api/repositories.rb
@@ -170,6 +170,65 @@ module API
not_found!("Merge Base")
end
end
+
+ desc 'Generates a changelog section for a release' do
+ detail 'This feature was introduced in GitLab 13.9'
+ end
+ params do
+ requires :version,
+ type: String,
+ regexp: Gitlab::Regex.unbounded_semver_regex,
+ desc: 'The version of the release, using the semantic versioning format'
+
+ optional :from,
+ type: String,
+ desc: 'The first commit in the range of commits to use for the changelog'
+
+ requires :to,
+ type: String,
+ desc: 'The last commit in the range of commits to use for the changelog'
+
+ optional :date,
+ type: DateTime,
+ desc: 'The date and time of the release'
+
+ optional :branch,
+ type: String,
+ desc: 'The branch to commit the changelog changes to'
+
+ optional :trailer,
+ type: String,
+ desc: 'The Git trailer to use for determining if commits are to be included in the changelog',
+ default: ::Repositories::ChangelogService::DEFAULT_TRAILER
+
+ optional :file,
+ type: String,
+ desc: 'The file to commit the changelog changes to',
+ default: ::Repositories::ChangelogService::DEFAULT_FILE
+
+ optional :message,
+ type: String,
+ desc: 'The commit message to use when committing the changelog'
+ end
+ post ':id/repository/changelog' do
+ branch = params[:branch] || user_project.default_branch_or_master
+ access = Gitlab::UserAccess.new(current_user, container: user_project)
+
+ unless access.can_push_to_branch?(branch)
+ forbidden!("You are not allowed to commit a changelog on this branch")
+ end
+
+ service = ::Repositories::ChangelogService.new(
+ user_project,
+ current_user,
+ **declared_params(include_missing: false)
+ )
+
+ service.execute
+ status(200)
+ rescue Gitlab::Changelog::Error => ex
+ render_api_error!("Failed to generate the changelog: #{ex.message}", 422)
+ end
end
end
end
diff --git a/lib/api/resource_access_tokens.rb b/lib/api/resource_access_tokens.rb
new file mode 100644
index 00000000000..66948f9eaf3
--- /dev/null
+++ b/lib/api/resource_access_tokens.rb
@@ -0,0 +1,94 @@
+# frozen_string_literal: true
+
+module API
+ class ResourceAccessTokens < ::API::Base
+ include PaginationParams
+
+ before { authenticate! }
+
+ feature_category :authentication_and_authorization
+
+ %w[project].each do |source_type|
+ resource source_type.pluralize, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
+ desc 'Get list of all access tokens for the specified resource' do
+ detail 'This feature was introduced in GitLab 13.9.'
+ end
+ params do
+ requires :id, type: String, desc: "The #{source_type} ID"
+ end
+ get ":id/access_tokens" do
+ resource = find_source(source_type, params[:id])
+
+ next unauthorized! unless has_permission_to_read?(resource)
+
+ tokens = PersonalAccessTokensFinder.new({ user: resource.bots, impersonation: false }).execute
+
+ present paginate(tokens), with: Entities::PersonalAccessToken
+ end
+
+ desc 'Revoke a resource access token' do
+ detail 'This feature was introduced in GitLab 13.9.'
+ end
+ params do
+ requires :id, type: String, desc: "The #{source_type} ID"
+ requires :token_id, type: String, desc: "The ID of the token"
+ end
+ delete ':id/access_tokens/:token_id' do
+ resource = find_source(source_type, params[:id])
+ token = find_token(resource, params[:token_id])
+
+ if token.nil?
+ next not_found!("Could not find #{source_type} access token with token_id: #{params[:token_id]}")
+ end
+
+ service = ::ResourceAccessTokens::RevokeService.new(
+ current_user,
+ resource,
+ token
+ ).execute
+
+ service.success? ? no_content! : bad_request!(service.message)
+ end
+
+ desc 'Create a resource access token' do
+ detail 'This feature was introduced in GitLab 13.9.'
+ end
+ params do
+ requires :id, type: String, desc: "The #{source_type} ID"
+ requires :name, type: String, desc: "Resource access token name"
+ requires :scopes, type: Array[String], desc: "The permissions of the token"
+ optional :expires_at, type: Date, desc: "The expiration date of the token"
+ end
+ post ':id/access_tokens' do
+ resource = find_source(source_type, params[:id])
+
+ token_response = ::ResourceAccessTokens::CreateService.new(
+ current_user,
+ resource,
+ declared_params
+ ).execute
+
+ if token_response.success?
+ present token_response.payload[:access_token], with: Entities::PersonalAccessToken
+ else
+ bad_request!(token_response.message)
+ end
+ end
+ end
+ end
+
+ helpers do
+ def find_source(source_type, id)
+ public_send("find_#{source_type}!", id) # rubocop:disable GitlabSecurity/PublicSend
+ end
+
+ def find_token(resource, token_id)
+ PersonalAccessTokensFinder.new({ user: resource.bots, impersonation: false }).find_by_id(token_id)
+ end
+
+ def has_permission_to_read?(resource)
+ can?(current_user, :project_bot_access, resource) || can?(current_user, :admin_resource_access_tokens, resource)
+ end
+ end
+ end
+end
diff --git a/lib/api/rubygem_packages.rb b/lib/api/rubygem_packages.rb
new file mode 100644
index 00000000000..7819aab879c
--- /dev/null
+++ b/lib/api/rubygem_packages.rb
@@ -0,0 +1,102 @@
+# frozen_string_literal: true
+
+###
+# API endpoints for the RubyGem package registry
+module API
+ class RubygemPackages < ::API::Base
+ include ::API::Helpers::Authentication
+ helpers ::API::Helpers::PackagesHelpers
+
+ feature_category :package_registry
+
+ # The Marshal version can be found by "#{Marshal::MAJOR_VERSION}.#{Marshal::MINOR_VERSION}"
+ # Updating the version should require a GitLab API version change.
+ MARSHAL_VERSION = '4.8'
+
+ FILE_NAME_REQUIREMENTS = {
+ file_name: API::NO_SLASH_URL_PART_REGEX
+ }.freeze
+
+ content_type :binary, 'application/octet-stream'
+
+ authenticate_with do |accept|
+ accept.token_types(:personal_access_token, :deploy_token, :job_token)
+ .sent_through(:http_token)
+ end
+
+ before do
+ require_packages_enabled!
+ authenticate!
+ not_found! unless Feature.enabled?(:rubygem_packages, user_project)
+ end
+
+ params do
+ requires :id, type: String, desc: 'The ID or full path of a project'
+ end
+ resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
+ namespace ':id/packages/rubygems' do
+ desc 'Download the spec index file' do
+ detail 'This feature was introduced in GitLab 13.9'
+ end
+ params do
+ requires :file_name, type: String, desc: 'Spec file name'
+ end
+ get ":file_name", requirements: FILE_NAME_REQUIREMENTS do
+ # To be implemented in https://gitlab.com/gitlab-org/gitlab/-/issues/299267
+ not_found!
+ end
+
+ desc 'Download the gemspec file' do
+ detail 'This feature was introduced in GitLab 13.9'
+ end
+ params do
+ requires :file_name, type: String, desc: 'Gemspec file name'
+ end
+ get "quick/Marshal.#{MARSHAL_VERSION}/:file_name", requirements: FILE_NAME_REQUIREMENTS do
+ # To be implemented in https://gitlab.com/gitlab-org/gitlab/-/issues/299284
+ not_found!
+ end
+
+ desc 'Download the .gem package' do
+ detail 'This feature was introduced in GitLab 13.9'
+ end
+ params do
+ requires :file_name, type: String, desc: 'Package file name'
+ end
+ get "gems/:file_name", requirements: FILE_NAME_REQUIREMENTS do
+ # To be implemented in https://gitlab.com/gitlab-org/gitlab/-/issues/299283
+ not_found!
+ end
+
+ namespace 'api/v1' do
+ desc 'Authorize a gem upload from workhorse' do
+ detail 'This feature was introduced in GitLab 13.9'
+ end
+ post 'gems/authorize' do
+ # To be implemented in https://gitlab.com/gitlab-org/gitlab/-/issues/299263
+ not_found!
+ end
+
+ desc 'Upload a gem' do
+ detail 'This feature was introduced in GitLab 13.9'
+ end
+ post 'gems' do
+ # To be implemented in https://gitlab.com/gitlab-org/gitlab/-/issues/299263
+ not_found!
+ end
+
+ desc 'Fetch a list of dependencies' do
+ detail 'This feature was introduced in GitLab 13.9'
+ end
+ params do
+ optional :gems, type: String, desc: 'Comma delimited gem names'
+ end
+ get 'dependencies' do
+ # To be implemented in https://gitlab.com/gitlab-org/gitlab/-/issues/299282
+ not_found!
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/api/settings.rb b/lib/api/settings.rb
index f329a94adf2..e7ee8b08d87 100644
--- a/lib/api/settings.rb
+++ b/lib/api/settings.rb
@@ -10,8 +10,7 @@ module API
helpers do
def current_settings
- @current_setting ||=
- (ApplicationSetting.current_without_cache || ApplicationSetting.create_from_defaults)
+ @current_setting ||= ApplicationSetting.find_or_create_without_cache
end
def filter_attributes_using_license(attrs)
@@ -42,7 +41,8 @@ module API
optional :asset_proxy_enabled, type: Boolean, desc: 'Enable proxying of assets'
optional :asset_proxy_url, type: String, desc: 'URL of the asset proxy server'
optional :asset_proxy_secret_key, type: String, desc: 'Shared secret with the asset proxy server'
- optional :asset_proxy_whitelist, type: Array[String], coerce_with: Validations::Types::CommaSeparatedToArray.coerce, desc: 'Assets that match these domain(s) will NOT be proxied. Wildcards allowed. Your GitLab installation URL is automatically whitelisted.'
+ optional :asset_proxy_whitelist, type: Array[String], coerce_with: Validations::Types::CommaSeparatedToArray.coerce, desc: 'Deprecated: Use :asset_proxy_allowlist instead. Assets that match these domain(s) will NOT be proxied. Wildcards allowed. Your GitLab installation URL is automatically whitelisted.'
+ optional :asset_proxy_allowlist, type: Array[String], coerce_with: Validations::Types::CommaSeparatedToArray.coerce, desc: 'Assets that match these domain(s) will NOT be proxied. Wildcards allowed. Your GitLab installation URL is automatically allowed.'
optional :container_registry_token_expire_delay, type: Integer, desc: 'Authorization token duration (minutes)'
optional :default_artifacts_expire_in, type: String, desc: "Set the default expiration time for each job's artifacts"
optional :default_ci_config_path, type: String, desc: 'The instance default CI configuration path for new projects'
@@ -211,6 +211,11 @@ module API
attrs[:abuse_notification_email] = attrs.delete(:admin_notification_email)
end
+ # support legacy names, can be removed in v5
+ if attrs.has_key?(:asset_proxy_whitelist)
+ attrs[:asset_proxy_allowlist] = attrs.delete(:asset_proxy_whitelist)
+ end
+
# since 13.0 it's not possible to disable hashed storage - support can be removed in 14.0
attrs.delete(:hashed_storage_enabled) if attrs.has_key?(:hashed_storage_enabled)
diff --git a/lib/api/snippet_repository_storage_moves.rb b/lib/api/snippet_repository_storage_moves.rb
index 1a5b41eb1ec..84dbc03ba33 100644
--- a/lib/api/snippet_repository_storage_moves.rb
+++ b/lib/api/snippet_repository_storage_moves.rb
@@ -58,9 +58,14 @@ module API
resource :snippets do
helpers do
def user_snippet
- Snippet.find_by(id: params[:id]) # rubocop: disable CodeReuse/ActiveRecord
+ @user_snippet ||= Snippet.find_by(id: params[:id]) # rubocop: disable CodeReuse/ActiveRecord
end
end
+
+ before do
+ not_found!('Snippet') unless user_snippet
+ end
+
desc 'Get a list of all snippets repository storage moves' do
detail 'This feature was introduced in GitLab 13.8.'
success Entities::SnippetRepositoryStorageMove
diff --git a/lib/api/subscriptions.rb b/lib/api/subscriptions.rb
index 914bab52929..87dc1358a51 100644
--- a/lib/api/subscriptions.rb
+++ b/lib/api/subscriptions.rb
@@ -6,6 +6,9 @@ module API
before { authenticate! }
+ SUBSCRIBE_ENDPOINT_REQUIREMENTS = API::NAMESPACE_OR_PROJECT_REQUIREMENTS.merge(
+ subscribable_id: API::NO_SLASH_URL_PART_REGEX)
+
subscribables = [
{
type: 'merge_requests',
@@ -44,7 +47,7 @@ module API
requires :id, type: String, desc: "The #{source_type} ID"
requires :subscribable_id, type: String, desc: 'The ID of a resource'
end
- resource source_type.pluralize, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
+ resource source_type.pluralize, requirements: SUBSCRIBE_ENDPOINT_REQUIREMENTS do
desc 'Subscribe to a resource' do
success subscribable[:entity]
end
diff --git a/lib/api/suggestions.rb b/lib/api/suggestions.rb
index a024d6de874..7921700e365 100644
--- a/lib/api/suggestions.rb
+++ b/lib/api/suggestions.rb
@@ -12,12 +12,13 @@ module API
end
params do
requires :id, type: String, desc: 'The suggestion ID'
+ optional :commit_message, type: String, desc: "A custom commit message to use instead of the default generated message or the project's default message"
end
put ':id/apply' do
suggestion = Suggestion.find_by_id(params[:id])
if suggestion
- apply_suggestions(suggestion, current_user)
+ apply_suggestions(suggestion, current_user, params[:commit_message])
else
render_api_error!(_('Suggestion is not applicable as the suggestion was not found.'), :not_found)
end
@@ -28,6 +29,7 @@ module API
end
params do
requires :ids, type: Array[Integer], coerce_with: ::API::Validations::Types::CommaSeparatedToIntegerArray.coerce, desc: "An array of suggestion ID's"
+ optional :commit_message, type: String, desc: "A custom commit message to use instead of the default generated message or the project's default message"
end
put 'batch_apply' do
ids = params[:ids]
@@ -35,7 +37,7 @@ module API
suggestions = Suggestion.id_in(ids)
if suggestions.size == ids.length
- apply_suggestions(suggestions, current_user)
+ apply_suggestions(suggestions, current_user, params[:commit_message])
else
render_api_error!(_('Suggestions are not applicable as one or more suggestions were not found.'), :not_found)
end
@@ -43,10 +45,10 @@ module API
end
helpers do
- def apply_suggestions(suggestions, current_user)
+ def apply_suggestions(suggestions, current_user, message)
authorize_suggestions(*suggestions)
- result = ::Suggestions::ApplyService.new(current_user, *suggestions).execute
+ result = ::Suggestions::ApplyService.new(current_user, *suggestions, message: message).execute
if result[:status] == :success
present suggestions, with: Entities::Suggestion, current_user: current_user
diff --git a/lib/api/support/git_access_actor.rb b/lib/api/support/git_access_actor.rb
index 39730da1251..71395086ac2 100644
--- a/lib/api/support/git_access_actor.rb
+++ b/lib/api/support/git_access_actor.rb
@@ -37,6 +37,8 @@ module API
end
def update_last_used_at!
+ return if Feature.enabled?(:disable_ssh_key_used_tracking)
+
key&.update_last_used_at
end
diff --git a/lib/api/users.rb b/lib/api/users.rb
index cee09f60a2b..f91e3c34ef2 100644
--- a/lib/api/users.rb
+++ b/lib/api/users.rb
@@ -6,7 +6,7 @@ module API
include APIGuard
include Helpers::CustomAttributes
- allow_access_with_scope :read_user, if: -> (request) { request.get? }
+ allow_access_with_scope :read_user, if: -> (request) { request.get? || request.head? }
feature_category :users, ['/users/:id/custom_attributes', '/users/:id/custom_attributes/:key']
@@ -159,6 +159,68 @@ module API
present user.status || {}, with: Entities::UserStatus
end
+ desc 'Follow a user' do
+ success Entities::User
+ end
+ params do
+ requires :id, type: Integer, desc: 'The ID of the user'
+ end
+ post ':id/follow', feature_category: :users do
+ user = find_user(params[:id])
+ not_found!('User') unless user
+
+ if current_user.follow(user)
+ present user, with: Entities::UserBasic
+ else
+ not_modified!
+ end
+ end
+
+ desc 'Unfollow a user' do
+ success Entities::User
+ end
+ params do
+ requires :id, type: Integer, desc: 'The ID of the user'
+ end
+ post ':id/unfollow', feature_category: :users do
+ user = find_user(params[:id])
+ not_found!('User') unless user
+
+ if current_user.unfollow(user)
+ present user, with: Entities::UserBasic
+ else
+ not_modified!
+ end
+ end
+
+ desc 'Get the users who follow a user' do
+ success Entities::UserBasic
+ end
+ params do
+ requires :id, type: Integer, desc: 'The ID of the user'
+ use :pagination
+ end
+ get ':id/following', feature_category: :users do
+ user = find_user(params[:id])
+ not_found!('User') unless user && can?(current_user, :read_user_profile, user)
+
+ present paginate(user.followees), with: Entities::UserBasic
+ end
+
+ desc 'Get the followers of a user' do
+ success Entities::UserBasic
+ end
+ params do
+ requires :id, type: Integer, desc: 'The ID of the user'
+ use :pagination
+ end
+ get ':id/followers', feature_category: :users do
+ user = find_user(params[:id])
+ not_found!('User') unless user && can?(current_user, :read_user_profile, user)
+
+ present paginate(user.followers), with: Entities::UserBasic
+ end
+
desc 'Create a user. Available only for admins.' do
success Entities::UserWithAdmin
end
@@ -1004,11 +1066,15 @@ module API
optional :emoji, type: String, desc: "The emoji to set on the status"
optional :message, type: String, desc: "The status message to set"
optional :availability, type: String, desc: "The availability of user to set"
+ optional :clear_status_after, type: String, desc: "Automatically clear emoji, message and availability fields after a certain time", values: UserStatus::CLEAR_STATUS_QUICK_OPTIONS.keys
end
put "status", feature_category: :users do
forbidden! unless can?(current_user, :update_user_status, current_user)
- if ::Users::SetStatusService.new(current_user, declared_params).execute
+ update_params = declared_params
+ update_params.delete(:clear_status_after) if Feature.disabled?(:clear_status_with_quick_options, current_user, default_enabled: :yaml)
+
+ if ::Users::SetStatusService.new(current_user, update_params).execute
present current_user.status, with: Entities::UserStatus
else
render_validation_error!(current_user.status)
diff --git a/lib/api/version.rb b/lib/api/version.rb
index f8072658cc6..86eb34ca589 100644
--- a/lib/api/version.rb
+++ b/lib/api/version.rb
@@ -5,7 +5,7 @@ module API
helpers ::API::Helpers::GraphqlHelpers
include APIGuard
- allow_access_with_scope :read_user, if: -> (request) { request.get? }
+ allow_access_with_scope :read_user, if: -> (request) { request.get? || request.head? }
before { authenticate! }