diff --git a/app/services/ci/runners/unassign_runner_service.rb b/app/services/ci/runners/unassign_runner_service.rb index a38a41960213f7aedd5c25d2cfef9b25da389a14..1e46cf6add85e752d647933046eb83e664044833 100644 --- a/app/services/ci/runners/unassign_runner_service.rb +++ b/app/services/ci/runners/unassign_runner_service.rb @@ -6,8 +6,9 @@ class UnassignRunnerService # @param [Ci::RunnerProject] runner_project the runner/project association to destroy # @param [User] user the user performing the operation def initialize(runner_project, user) - @runner = runner_project.runner @runner_project = runner_project + @runner = runner_project.runner + @project = runner_project.project @user = user end @@ -16,6 +17,12 @@ def execute @runner_project.destroy end + + private + + attr_reader :runner, :project, :user end end end + +Ci::Runners::UnassignRunnerService.prepend_mod diff --git a/ee/app/services/ee/ci/runners/unassign_runner_service.rb b/ee/app/services/ee/ci/runners/unassign_runner_service.rb new file mode 100644 index 0000000000000000000000000000000000000000..e7a0440bea6a75254f2c67461279d8a5b4254cb8 --- /dev/null +++ b/ee/app/services/ee/ci/runners/unassign_runner_service.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +module EE + module Ci + module Runners + module UnassignRunnerService + extend ::Gitlab::Utils::Override + include ::Audit::Changes + + override :execute + def execute + result = super + + audit_log_event if result + + result + end + + private + + AUDIT_MESSAGE = 'Unassigned CI runner from project' + + def audit_log_event + ::AuditEvents::RunnerCustomAuditEventService.new(runner, user, project, AUDIT_MESSAGE).track_event + end + end + end + end +end diff --git a/ee/spec/services/ci/runners/unassign_runner_service_spec.rb b/ee/spec/services/ci/runners/unassign_runner_service_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..920a1ecf8995bd89805e7c4488db6ba8b1a78f36 --- /dev/null +++ b/ee/spec/services/ci/runners/unassign_runner_service_spec.rb @@ -0,0 +1,43 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe ::Ci::Runners::UnassignRunnerService, '#execute' do + let_it_be(:owner_project) { create(:project) } + let_it_be(:other_project) { create(:project) } + let_it_be(:project_runner) { create(:ci_runner, :project, projects: [owner_project, other_project]) } + + let(:runner_project) { project_runner.runner_projects.last } + + let(:audit_service) { instance_double(::AuditEvents::RunnerCustomAuditEventService) } + + subject { described_class.new(runner_project, user).execute } + + context 'with unauthorized user' do + let(:user) { build(:user) } + + it 'does not call assign_to on runner and returns false', :aggregate_failures do + expect(project_runner).not_to receive(:assign_to) + expect(::AuditEvents::RunnerCustomAuditEventService).not_to receive(:new) + + is_expected.to be_falsey + end + end + + context 'with admin user', :enable_admin_mode do + let(:user) { create_default(:admin) } + + before do + expect(audit_service).to receive(:track_event).once.and_return('track_event_return_value') + end + + it 'calls track_event on RunnerCustomAuditEventService and returns the runner_project', :aggregate_failures do + expect(runner_project).to receive(:destroy).once.and_call_original + expect(::AuditEvents::RunnerCustomAuditEventService).to receive(:new) + .with(project_runner, user, other_project, 'Unassigned CI runner from project') + .once.and_return(audit_service) + + is_expected.to eq(runner_project) + end + end +end