From e8d2c2579383897a1dd7f9debd359abe8ae8373d Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Tue, 20 Jul 2021 09:55:51 +0000 Subject: Add latest changes from gitlab-org/gitlab@14-1-stable-ee --- .../prometheus_integration/create.rb | 4 +- .../prometheus_integration_base.rb | 2 +- .../prometheus_integration/reset_token.rb | 2 +- .../prometheus_integration/update.rb | 2 +- .../mutations/boards/issues/issue_move_list.rb | 2 - .../mutations/ci/job_token_scope/add_project.rb | 49 ++++++++++++++++++++++ .../mutations/ci/job_token_scope/remove_project.rb | 49 ++++++++++++++++++++++ app/graphql/mutations/ci/runner/update.rb | 2 + .../concerns/mutations/package_eventable.rb | 2 +- .../concerns/mutations/spam_protection.rb | 19 --------- app/graphql/mutations/issues/create.rb | 3 +- app/graphql/mutations/issues/set_confidential.rb | 8 +++- app/graphql/mutations/issues/update.rb | 3 +- app/graphql/mutations/packages/destroy.rb | 37 ++++++++++++++++ .../mutations/release_asset_links/create.rb | 4 ++ .../ci_configuration/base_security_analyzer.rb | 44 +++++++++++++++++++ .../security/ci_configuration/configure_sast.rb | 33 ++------------- .../ci_configuration/configure_secret_detection.rb | 33 ++------------- app/graphql/mutations/snippets/create.rb | 10 ++--- app/graphql/mutations/snippets/update.rb | 10 ++--- 20 files changed, 214 insertions(+), 104 deletions(-) create mode 100644 app/graphql/mutations/ci/job_token_scope/add_project.rb create mode 100644 app/graphql/mutations/ci/job_token_scope/remove_project.rb create mode 100644 app/graphql/mutations/packages/destroy.rb create mode 100644 app/graphql/mutations/security/ci_configuration/base_security_analyzer.rb (limited to 'app/graphql/mutations') diff --git a/app/graphql/mutations/alert_management/prometheus_integration/create.rb b/app/graphql/mutations/alert_management/prometheus_integration/create.rb index c6dc85dc07c..4d0a5a5cb13 100644 --- a/app/graphql/mutations/alert_management/prometheus_integration/create.rb +++ b/app/graphql/mutations/alert_management/prometheus_integration/create.rb @@ -23,7 +23,7 @@ module Mutations def resolve(args) project = authorized_find!(args[:project_path]) - return integration_exists if project.prometheus_service + return integration_exists if project.prometheus_integration result = ::Projects::Operations::UpdateService.new( project, @@ -32,7 +32,7 @@ module Mutations **token_attributes ).execute - response(project.prometheus_service, result) + response(project.prometheus_integration, result) end private diff --git a/app/graphql/mutations/alert_management/prometheus_integration/prometheus_integration_base.rb b/app/graphql/mutations/alert_management/prometheus_integration/prometheus_integration_base.rb index cb243f49b33..d8678ea4d61 100644 --- a/app/graphql/mutations/alert_management/prometheus_integration/prometheus_integration_base.rb +++ b/app/graphql/mutations/alert_management/prometheus_integration/prometheus_integration_base.rb @@ -14,7 +14,7 @@ module Mutations private def find_object(id:) - GitlabSchema.object_from_id(id, expected_class: ::PrometheusService) + GitlabSchema.object_from_id(id, expected_class: ::Integrations::Prometheus) end def response(integration, result) diff --git a/app/graphql/mutations/alert_management/prometheus_integration/reset_token.rb b/app/graphql/mutations/alert_management/prometheus_integration/reset_token.rb index 428be091436..33a12405583 100644 --- a/app/graphql/mutations/alert_management/prometheus_integration/reset_token.rb +++ b/app/graphql/mutations/alert_management/prometheus_integration/reset_token.rb @@ -6,7 +6,7 @@ module Mutations class ResetToken < PrometheusIntegrationBase graphql_name 'PrometheusIntegrationResetToken' - argument :id, Types::GlobalIDType[::PrometheusService], + argument :id, Types::GlobalIDType[::Integrations::Prometheus], required: true, description: "The ID of the integration to mutate." diff --git a/app/graphql/mutations/alert_management/prometheus_integration/update.rb b/app/graphql/mutations/alert_management/prometheus_integration/update.rb index 7594766176f..ddab1af908c 100644 --- a/app/graphql/mutations/alert_management/prometheus_integration/update.rb +++ b/app/graphql/mutations/alert_management/prometheus_integration/update.rb @@ -6,7 +6,7 @@ module Mutations class Update < PrometheusIntegrationBase graphql_name 'PrometheusIntegrationUpdate' - argument :id, Types::GlobalIDType[::PrometheusService], + argument :id, Types::GlobalIDType[::Integrations::Prometheus], required: true, description: "The ID of the integration to mutate." diff --git a/app/graphql/mutations/boards/issues/issue_move_list.rb b/app/graphql/mutations/boards/issues/issue_move_list.rb index 4c9752c6343..b73657ea0c8 100644 --- a/app/graphql/mutations/boards/issues/issue_move_list.rb +++ b/app/graphql/mutations/boards/issues/issue_move_list.rb @@ -53,8 +53,6 @@ module Mutations end def resolve(board:, project_path:, iid:, **args) - Gitlab::QueryLimiting.disable!('https://gitlab.com/gitlab-org/gitlab/-/issues/247861') - issue = authorized_find!(project_path: project_path, iid: iid) move_params = { id: issue.id, board_id: board.id }.merge(move_arguments(args)) diff --git a/app/graphql/mutations/ci/job_token_scope/add_project.rb b/app/graphql/mutations/ci/job_token_scope/add_project.rb new file mode 100644 index 00000000000..30f98a537b5 --- /dev/null +++ b/app/graphql/mutations/ci/job_token_scope/add_project.rb @@ -0,0 +1,49 @@ +# frozen_string_literal: true + +module Mutations + module Ci + module JobTokenScope + class AddProject < BaseMutation + include FindsProject + + graphql_name 'CiJobTokenScopeAddProject' + + authorize :admin_project + + argument :project_path, GraphQL::ID_TYPE, + required: true, + description: 'The project that the CI job token scope belongs to.' + + argument :target_project_path, GraphQL::ID_TYPE, + required: true, + description: 'The project to be added to the CI job token scope.' + + field :ci_job_token_scope, + Types::Ci::JobTokenScopeType, + null: true, + description: "The CI job token's scope of access." + + def resolve(project_path:, target_project_path:) + project = authorized_find!(project_path) + target_project = Project.find_by_full_path(target_project_path) + + result = ::Ci::JobTokenScope::AddProjectService + .new(project, current_user) + .execute(target_project) + + if result.success? + { + ci_job_token_scope: ::Ci::JobToken::Scope.new(project), + errors: [] + } + else + { + ci_job_token_scope: nil, + errors: [result.message] + } + end + end + end + end + end +end diff --git a/app/graphql/mutations/ci/job_token_scope/remove_project.rb b/app/graphql/mutations/ci/job_token_scope/remove_project.rb new file mode 100644 index 00000000000..71c9083bef8 --- /dev/null +++ b/app/graphql/mutations/ci/job_token_scope/remove_project.rb @@ -0,0 +1,49 @@ +# frozen_string_literal: true + +module Mutations + module Ci + module JobTokenScope + class RemoveProject < BaseMutation + include FindsProject + + graphql_name 'CiJobTokenScopeRemoveProject' + + authorize :admin_project + + argument :project_path, GraphQL::ID_TYPE, + required: true, + description: 'The project that the CI job token scope belongs to.' + + argument :target_project_path, GraphQL::ID_TYPE, + required: true, + description: 'The project to be removed from the CI job token scope.' + + field :ci_job_token_scope, + Types::Ci::JobTokenScopeType, + null: true, + description: "The CI job token's scope of access." + + def resolve(project_path:, target_project_path:) + project = authorized_find!(project_path) + target_project = Project.find_by_full_path(target_project_path) + + result = ::Ci::JobTokenScope::RemoveProjectService + .new(project, current_user) + .execute(target_project) + + if result.success? + { + ci_job_token_scope: ::Ci::JobToken::Scope.new(project), + errors: [] + } + else + { + ci_job_token_scope: nil, + errors: [result.message] + } + end + end + end + end + end +end diff --git a/app/graphql/mutations/ci/runner/update.rb b/app/graphql/mutations/ci/runner/update.rb index 5b61b2ffc0d..4cdfa1fb1bd 100644 --- a/app/graphql/mutations/ci/runner/update.rb +++ b/app/graphql/mutations/ci/runner/update.rb @@ -66,3 +66,5 @@ module Mutations end end end + +Mutations::Ci::Runner::Update.prepend_mod_with('Mutations::Ci::Runner::Update') diff --git a/app/graphql/mutations/concerns/mutations/package_eventable.rb b/app/graphql/mutations/concerns/mutations/package_eventable.rb index 86fd7b9a88a..134e3659125 100644 --- a/app/graphql/mutations/concerns/mutations/package_eventable.rb +++ b/app/graphql/mutations/concerns/mutations/package_eventable.rb @@ -8,7 +8,7 @@ module Mutations def track_event(event, scope) ::Packages::CreateEventService.new(nil, current_user, event_name: event, scope: scope).execute - ::Gitlab::Tracking.event(event.to_s, scope.to_s) + ::Gitlab::Tracking.event(event.to_s, scope.to_s, user: current_user) end end end diff --git a/app/graphql/mutations/concerns/mutations/spam_protection.rb b/app/graphql/mutations/concerns/mutations/spam_protection.rb index d765da23a4b..341067710b2 100644 --- a/app/graphql/mutations/concerns/mutations/spam_protection.rb +++ b/app/graphql/mutations/concerns/mutations/spam_protection.rb @@ -16,25 +16,6 @@ module Mutations private - # additional_spam_params -> hash - # - # Used from a spammable mutation's #resolve method to generate - # the required additional spam/CAPTCHA params which must be merged into the params - # passed to the constructor of a service, where they can then be used in the service - # to perform spam checking via SpamActionService. - # - # Also accesses the #context of the mutation's Resolver superclass to obtain the request. - # - # Example: - # - # existing_args.merge!(additional_spam_params) - def additional_spam_params - { - api: true, - request: context[:request] - } - end - def spam_action_response(object) fields = spam_action_response_fields(object) diff --git a/app/graphql/mutations/issues/create.rb b/app/graphql/mutations/issues/create.rb index 3a57e2434a5..7c4a851f8aa 100644 --- a/app/graphql/mutations/issues/create.rb +++ b/app/graphql/mutations/issues/create.rb @@ -73,7 +73,8 @@ module Mutations project = authorized_find!(project_path) params = build_create_issue_params(attributes.merge(author_id: current_user.id)) - issue = ::Issues::CreateService.new(project: project, current_user: current_user, params: params).execute + spam_params = ::Spam::SpamParams.new_from_request(request: context[:request]) + issue = ::Issues::CreateService.new(project: project, current_user: current_user, params: params, spam_params: spam_params).execute if issue.spam? issue.errors.add(:base, 'Spam detected.') diff --git a/app/graphql/mutations/issues/set_confidential.rb b/app/graphql/mutations/issues/set_confidential.rb index 8e88b31d9ed..cfee2420ee0 100644 --- a/app/graphql/mutations/issues/set_confidential.rb +++ b/app/graphql/mutations/issues/set_confidential.rb @@ -3,6 +3,8 @@ module Mutations module Issues class SetConfidential < Base + include Mutations::SpamProtection + graphql_name 'IssueSetConfidential' argument :confidential, @@ -13,9 +15,13 @@ module Mutations def resolve(project_path:, iid:, confidential:) issue = authorized_find!(project_path: project_path, iid: iid) project = issue.project + # Changing confidentiality affects spam checking rules, therefore we need to provide + # spam_params so a check can be performed. + spam_params = ::Spam::SpamParams.new_from_request(request: context[:request]) - ::Issues::UpdateService.new(project: project, current_user: current_user, params: { confidential: confidential }) + ::Issues::UpdateService.new(project: project, current_user: current_user, params: { confidential: confidential }, spam_params: spam_params) .execute(issue) + check_spam_action_response!(issue) { issue: issue, diff --git a/app/graphql/mutations/issues/update.rb b/app/graphql/mutations/issues/update.rb index eb16b7b38d0..1ceed868a6c 100644 --- a/app/graphql/mutations/issues/update.rb +++ b/app/graphql/mutations/issues/update.rb @@ -31,7 +31,8 @@ module Mutations issue = authorized_find!(project_path: project_path, iid: iid) project = issue.project - ::Issues::UpdateService.new(project: project, current_user: current_user, params: args).execute(issue) + spam_params = ::Spam::SpamParams.new_from_request(request: context[:request]) + ::Issues::UpdateService.new(project: project, current_user: current_user, params: args, spam_params: spam_params).execute(issue) { issue: issue, diff --git a/app/graphql/mutations/packages/destroy.rb b/app/graphql/mutations/packages/destroy.rb new file mode 100644 index 00000000000..979a54da6bd --- /dev/null +++ b/app/graphql/mutations/packages/destroy.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true + +module Mutations + module Packages + class Destroy < ::Mutations::BaseMutation + graphql_name 'DestroyPackage' + + authorize :destroy_package + + argument :id, + ::Types::GlobalIDType[::Packages::Package], + required: true, + description: 'ID of the Package.' + + def resolve(id:) + package = authorized_find!(id: id) + + result = ::Packages::DestroyPackageService.new(container: package, current_user: current_user).execute + + errors = result.error? ? Array.wrap(result[:message]) : [] + + { + errors: errors + } + end + + private + + def find_object(id:) + # TODO: remove this line when the compatibility layer is removed + # See: https://gitlab.com/gitlab-org/gitlab/-/issues/257883 + id = ::Types::GlobalIDType[::Packages::Package].coerce_isolated_input(id) + GitlabSchema.find_by_gid(id) + end + end + end +end diff --git a/app/graphql/mutations/release_asset_links/create.rb b/app/graphql/mutations/release_asset_links/create.rb index 02704efb47c..ff9d98d2c0f 100644 --- a/app/graphql/mutations/release_asset_links/create.rb +++ b/app/graphql/mutations/release_asset_links/create.rb @@ -33,6 +33,10 @@ module Mutations return { link: nil, errors: [message] } end + unless Ability.allowed?(current_user, :update_release, release) + raise_resource_not_available_error! + end + new_link = release.links.create(link_attrs) unless new_link.persisted? diff --git a/app/graphql/mutations/security/ci_configuration/base_security_analyzer.rb b/app/graphql/mutations/security/ci_configuration/base_security_analyzer.rb new file mode 100644 index 00000000000..090a9a4e0ef --- /dev/null +++ b/app/graphql/mutations/security/ci_configuration/base_security_analyzer.rb @@ -0,0 +1,44 @@ +# frozen_string_literal: true + +module Mutations + module Security + module CiConfiguration + class BaseSecurityAnalyzer < BaseMutation + include FindsProject + + argument :project_path, GraphQL::ID_TYPE, + required: true, + description: 'Full path of the project.' + + field :success_path, GraphQL::STRING_TYPE, null: true, + description: 'Redirect path to use when the response is successful.' + + field :branch, GraphQL::STRING_TYPE, null: true, + description: 'Branch that has the new/modified `.gitlab-ci.yml` file.' + + authorize :push_code + + def resolve(project_path:, **args) + project = authorized_find!(project_path) + + result = configure_analyzer(project, **args) + prepare_response(result) + end + + private + + def configure_analyzer(project, **args) + raise NotImplementedError + end + + def prepare_response(result) + { + branch: result.payload[:branch], + success_path: result.payload[:success_path], + errors: result.errors + } + end + end + end + end +end diff --git a/app/graphql/mutations/security/ci_configuration/configure_sast.rb b/app/graphql/mutations/security/ci_configuration/configure_sast.rb index 237aff1f052..7ce0bf83a4b 100644 --- a/app/graphql/mutations/security/ci_configuration/configure_sast.rb +++ b/app/graphql/mutations/security/ci_configuration/configure_sast.rb @@ -3,9 +3,7 @@ module Mutations module Security module CiConfiguration - class ConfigureSast < BaseMutation - include FindsProject - + class ConfigureSast < BaseSecurityAnalyzer graphql_name 'ConfigureSast' description <<~DESC Configure SAST for a project by enabling SAST in a new or modified @@ -13,37 +11,12 @@ module Mutations create a Merge Request are a part of the response. DESC - argument :project_path, GraphQL::ID_TYPE, - required: true, - description: 'Full path of the project.' - argument :configuration, ::Types::CiConfiguration::Sast::InputType, required: true, description: 'SAST CI configuration for the project.' - field :success_path, GraphQL::STRING_TYPE, null: true, - description: 'Redirect path to use when the response is successful.' - - field :branch, GraphQL::STRING_TYPE, null: true, - description: 'Branch that has the new/modified `.gitlab-ci.yml` file.' - - authorize :push_code - - def resolve(project_path:, configuration:) - project = authorized_find!(project_path) - - result = ::Security::CiConfiguration::SastCreateService.new(project, current_user, configuration).execute - prepare_response(result) - end - - private - - def prepare_response(result) - { - branch: result.payload[:branch], - success_path: result.payload[:success_path], - errors: result.errors - } + def configure_analyzer(project, **args) + ::Security::CiConfiguration::SastCreateService.new(project, current_user, args[:configuration]).execute end end end diff --git a/app/graphql/mutations/security/ci_configuration/configure_secret_detection.rb b/app/graphql/mutations/security/ci_configuration/configure_secret_detection.rb index 32ad670edaa..54322babb26 100644 --- a/app/graphql/mutations/security/ci_configuration/configure_secret_detection.rb +++ b/app/graphql/mutations/security/ci_configuration/configure_secret_detection.rb @@ -3,9 +3,7 @@ module Mutations module Security module CiConfiguration - class ConfigureSecretDetection < BaseMutation - include FindsProject - + class ConfigureSecretDetection < BaseSecurityAnalyzer graphql_name 'ConfigureSecretDetection' description <<~DESC Configure Secret Detection for a project by enabling Secret Detection @@ -14,33 +12,8 @@ module Mutations response. DESC - argument :project_path, GraphQL::ID_TYPE, - required: true, - description: 'Full path of the project.' - - field :success_path, GraphQL::STRING_TYPE, null: true, - description: 'Redirect path to use when the response is successful.' - - field :branch, GraphQL::STRING_TYPE, null: true, - description: 'Branch that has the new/modified `.gitlab-ci.yml` file.' - - authorize :push_code - - def resolve(project_path:) - project = authorized_find!(project_path) - - result = ::Security::CiConfiguration::SecretDetectionCreateService.new(project, current_user).execute - prepare_response(result) - end - - private - - def prepare_response(result) - { - branch: result.payload[:branch], - success_path: result.payload[:success_path], - errors: result.errors - } + def configure_analyzer(project, **_args) + ::Security::CiConfiguration::SecretDetectionCreateService.new(project, current_user).execute end end end diff --git a/app/graphql/mutations/snippets/create.rb b/app/graphql/mutations/snippets/create.rb index d1ad0697acd..765163e73a1 100644 --- a/app/graphql/mutations/snippets/create.rb +++ b/app/graphql/mutations/snippets/create.rb @@ -49,7 +49,9 @@ module Mutations process_args_for_params!(args) - service_response = ::Snippets::CreateService.new(project: project, current_user: current_user, params: args).execute + spam_params = ::Spam::SpamParams.new_from_request(request: context[:request]) + service = ::Snippets::CreateService.new(project: project, current_user: current_user, params: args, spam_params: spam_params) + service_response = service.execute # Only when the user is not an api user and the operation was successful if !api_user? && service_response.success? @@ -81,12 +83,6 @@ module Mutations # it's the expected key param args[:files] = args.delete(:uploaded_files) - if Feature.enabled?(:snippet_spam) - args.merge!(additional_spam_params) - else - args[:disable_spam_action_service] = true - end - # Return nil to make it explicit that this method is mutating the args parameter, and that # the return value is not relevant and is not to be used. nil diff --git a/app/graphql/mutations/snippets/update.rb b/app/graphql/mutations/snippets/update.rb index 2e1382e1cb1..792c631e5ca 100644 --- a/app/graphql/mutations/snippets/update.rb +++ b/app/graphql/mutations/snippets/update.rb @@ -34,7 +34,9 @@ module Mutations process_args_for_params!(args) - service_response = ::Snippets::UpdateService.new(project: snippet.project, current_user: current_user, params: args).execute(snippet) + spam_params = ::Spam::SpamParams.new_from_request(request: context[:request]) + service = ::Snippets::UpdateService.new(project: snippet.project, current_user: current_user, params: args, spam_params: spam_params) + service_response = service.execute(snippet) # TODO: DRY this up - From here down, this is all duplicated with Mutations::Snippets::Create#resolve, except for # `snippet.reset`, which is required in order to return the object in its non-dirty, unmodified, database state @@ -62,12 +64,6 @@ module Mutations def process_args_for_params!(args) convert_blob_actions_to_snippet_actions!(args) - if Feature.enabled?(:snippet_spam) - args.merge!(additional_spam_params) - else - args[:disable_spam_action_service] = true - end - # Return nil to make it explicit that this method is mutating the args parameter, and that # the return value is not relevant and is not to be used. nil -- cgit v1.2.3