diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2021-02-05 16:20:45 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2021-02-05 16:20:45 +0000 |
commit | d298fad0c0564454271cba11e6f20c19681534ac (patch) | |
tree | 0a19d07d8b3bdd2574617305c300e404f2ace581 /lib/api | |
parent | c9f9eec79cab801a50db698f682aacffbedf07f7 (diff) | |
download | gitlab-ce-13.9.0-rc41.tar.gz |
Add latest changes from gitlab-org/gitlab@13-9-stable-eev13.9.0-rc41
Diffstat (limited to 'lib/api')
29 files changed, 272 insertions, 96 deletions
diff --git a/lib/api/api.rb b/lib/api/api.rb index ada0da28749..725dddead70 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 @@ -123,13 +123,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 +268,7 @@ module API mount ::API::Release::Links mount ::API::RemoteMirrors mount ::API::Repositories + mount ::API::ResourceAccessTokens mount ::API::Search mount ::API::Services mount ::API::Settings @@ -294,4 +314,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/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/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/user.rb b/lib/api/entities/user.rb index 4aa5c9b7236..b392e7831e5 100644 --- a/lib/api/entities/user.rb +++ b/lib/api/entities/user.rb @@ -6,6 +6,7 @@ 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 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/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/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/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/internal/base.rb b/lib/api/internal/base.rb index 12bb6e77c3e..6de80c17960 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 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/jobs.rb b/lib/api/jobs.rb index e14a4a5e680..c09b01f5b4e 100644 --- a/lib/api/jobs.rb +++ b/lib/api/jobs.rb @@ -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 ab0e9b95e4a..cff0866c65e 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' @@ -359,7 +361,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/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..353f2ed1c25 100644 --- a/lib/api/repositories.rb +++ b/lib/api/repositories.rb @@ -170,6 +170,67 @@ 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' + + requires :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 + not_found! unless Feature.enabled?(:changelog_api, user_project) + + 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 => ex + render_api_error!("Failed to generate the changelog: #{ex.message}", 500) + 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/settings.rb b/lib/api/settings.rb index f329a94adf2..6b1ad33d84b 100644 --- a/lib/api/settings.rb +++ b/lib/api/settings.rb @@ -42,7 +42,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 +212,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/users.rb b/lib/api/users.rb index cee09f60a2b..36368adf2f0 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'] 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! } |