diff --git a/app/services/ci/destroy_pipeline_service.rb b/app/services/ci/destroy_pipeline_service.rb index a9d2e17657e0d083f7c623342c04ab640be53d56..7adf573687a638819931e1d0d28c374c3a2cf1e7 100644 --- a/app/services/ci/destroy_pipeline_service.rb +++ b/app/services/ci/destroy_pipeline_service.rb @@ -28,3 +28,5 @@ def execute(pipeline) end end end + +Ci::DestroyPipelineService.prepend_mod diff --git a/doc/administration/audit_event_streaming/audit_event_types.md b/doc/administration/audit_event_streaming/audit_event_types.md index 6e1436284d051e76b42bccc40d7db51cefd28b57..ac630c187171f48ca77da2a264ee0624a5d01053 100644 --- a/doc/administration/audit_event_streaming/audit_event_types.md +++ b/doc/administration/audit_event_streaming/audit_event_types.md @@ -172,6 +172,7 @@ Audit event types belong to the following product categories. | [`ci_variable_created`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/91983) | Triggered when a CI variable is created at a project level| **{check-circle}** Yes | **{check-circle}** Yes | GitLab [15.2](https://gitlab.com/gitlab-org/gitlab/-/issues/363090) | | [`ci_variable_deleted`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/91983) | Triggered when a project's CI variable is deleted| **{check-circle}** Yes | **{check-circle}** Yes | GitLab [15.2](https://gitlab.com/gitlab-org/gitlab/-/issues/363090) | | [`ci_variable_updated`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/91983) | Triggered when a project's CI variable is updated| **{check-circle}** Yes | **{check-circle}** Yes | GitLab [15.2](https://gitlab.com/gitlab-org/gitlab/-/issues/363090) | +| [`destroy_pipeline`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/135255) | Event triggered when a pipeline is deleted| **{check-circle}** Yes | **{check-circle}** Yes | GitLab [16.6](https://gitlab.com/gitlab-org/gitlab/-/issues/339041) | ### Deployment management diff --git a/ee/app/services/ee/ci/destroy_pipeline_service.rb b/ee/app/services/ee/ci/destroy_pipeline_service.rb new file mode 100644 index 0000000000000000000000000000000000000000..789fb5ecaffb960f5c8039fe029163865bcbb18f --- /dev/null +++ b/ee/app/services/ee/ci/destroy_pipeline_service.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +module EE + module Ci + module DestroyPipelineService + extend ::Gitlab::Utils::Override + + override :execute + def execute(pipeline) + response = super(pipeline) + log_audit_event(pipeline) if response.success? + response + end + + private + + def log_audit_event(pipeline) + audit_context = { + name: "destroy_pipeline", + author: current_user, + scope: project, + target: pipeline, + target_details: pipeline.id.to_s, + message: "Deleted pipeline in #{pipeline.ref} with status #{pipeline.status} and SHA #{pipeline.sha}" + } + + ::Gitlab::Audit::Auditor.audit(audit_context) + end + end + end +end diff --git a/ee/config/audit_events/types/destroy_pipeline.yml b/ee/config/audit_events/types/destroy_pipeline.yml new file mode 100644 index 0000000000000000000000000000000000000000..58ad37239f1bbeddf60cd8329591bf004a06eee0 --- /dev/null +++ b/ee/config/audit_events/types/destroy_pipeline.yml @@ -0,0 +1,9 @@ +--- +name: destroy_pipeline +description: Event triggered when a pipeline is deleted +introduced_by_issue: https://gitlab.com/gitlab-org/gitlab/-/issues/339041 +introduced_by_mr: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/135255 +feature_category: continuous_integration +milestone: "16.6" +saved_to_database: true +streamed: true diff --git a/ee/spec/requests/api/ci/pipelines_spec.rb b/ee/spec/requests/api/ci/pipelines_spec.rb index 8480b753c4d18d919a3d09d98508b03ef053910b..f000d5b082fbe2ea3581344f6758228d8e3f6838 100644 --- a/ee/spec/requests/api/ci/pipelines_spec.rb +++ b/ee/spec/requests/api/ci/pipelines_spec.rb @@ -24,8 +24,8 @@ stub_licensed_features(extended_audit_events: true, admin_audit_log: true) end - it 'does not log an audit event' do - expect { delete api("/projects/#{project.id}/pipelines/#{pipeline.id}", owner) }.not_to change { AuditEvent.count } + it 'logs an audit event' do + expect { delete api("/projects/#{project.id}/pipelines/#{pipeline.id}", owner) }.to change { AuditEvent.count }.by(1) end end end diff --git a/ee/spec/services/ci/destroy_pipeline_service_spec.rb b/ee/spec/services/ci/destroy_pipeline_service_spec.rb index b0dd0c9c4c3ca01c239b92f928a5deffe59ba8ab..5e4bb7b78e7fb1da779e8c500ae9482cde942229 100644 --- a/ee/spec/services/ci/destroy_pipeline_service_spec.rb +++ b/ee/spec/services/ci/destroy_pipeline_service_spec.rb @@ -7,15 +7,39 @@ let!(:pipeline) { create(:ci_pipeline, project: project) } let(:user) { project.first_owner } - subject { described_class.new(project, user).execute(pipeline) } + subject(:service) { described_class.new(project, user) } - context 'when audit events is enabled' do - before do - stub_licensed_features(extended_audit_events: true, admin_audit_log: true) - end + describe '#execute' do + subject(:operation) { service.execute(pipeline) } + + context 'for audit events', :enable_admin_mode do + let(:audit_event_name) { "destroy_pipeline" } + let(:event_type) { "destroy_pipeline" } + + include_examples 'audit event logging' do + let(:operation) { service.execute(pipeline) } + + let(:fail_condition!) do + allow(pipeline).to receive(:destroy!).and_raise(ActiveRecord::RecordNotFound) + end - it 'does not log an audit event' do - expect { subject }.not_to change { AuditEvent.count } + let(:attributes) do + { + author_id: user.id, + entity_id: project.id, + entity_type: 'Project', + details: { + author_class: 'User', + author_name: user.name, + custom_message: "Deleted pipeline in #{pipeline.ref} with status " \ + "#{pipeline.status} and SHA #{pipeline.sha}", + target_details: pipeline.id.to_s, + target_id: pipeline.id, + target_type: 'Ci::Pipeline' + } + } + end + end end end end