From 5884d2353f0b8a2a14f8ce0ea8eece29c43d1822 Mon Sep 17 00:00:00 2001 From: Linjie Zhang Date: Thu, 23 Jun 2022 23:12:29 +0800 Subject: [PATCH] Stream audit event on project fork Stream audit event for project fork action. Changelog: added EE: true --- app/services/projects/fork_service.rb | 11 +++- doc/administration/audit_event_streaming.md | 49 +++++++++++++++ ee/app/services/ee/projects/fork_service.rb | 25 ++++++++ .../services/projects/fork_service_spec.rb | 59 +++++++++++++++++++ 4 files changed, 143 insertions(+), 1 deletion(-) create mode 100644 ee/app/services/ee/projects/fork_service.rb create mode 100644 ee/spec/services/projects/fork_service_spec.rb diff --git a/app/services/projects/fork_service.rb b/app/services/projects/fork_service.rb index 3e8d656370984a..02ae30db1c3226 100644 --- a/app/services/projects/fork_service.rb +++ b/app/services/projects/fork_service.rb @@ -5,7 +5,10 @@ class ForkService < BaseService def execute(fork_to_project = nil) forked_project = fork_to_project ? link_existing_project(fork_to_project) : fork_new_project - refresh_forks_count if forked_project&.saved? + if forked_project&.saved? + refresh_forks_count + stream_audit_event(forked_project) + end forked_project end @@ -133,5 +136,11 @@ def target_visibility_level def target_mr_default_target_self @target_mr_default_target_self ||= params[:mr_default_target_self] end + + def stream_audit_event(forked_project) + # Defined in EE + end end end + +Projects::ForkService.prepend_mod diff --git a/doc/administration/audit_event_streaming.md b/doc/administration/audit_event_streaming.md index 1e87b3c65bff0f..0135a59cba9ce8 100644 --- a/doc/administration/audit_event_streaming.md +++ b/doc/administration/audit_event_streaming.md @@ -555,3 +555,52 @@ X-Gitlab-Event-Streaming-Token: "event_type": "merge_request_create" } ``` + +## Audit event streaming on project fork actions + +> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/90916) in GitLab 15.2. + +Stream audit events that relate to project fork actions using the `/logs` endpoint. + +Send API requests that contain the `X-Gitlab-Audit-Event-Type` header with value `project_fork_operation`. GitLab responds with JSON payloads with an +`event_type` field set to `project_fork_operation`. + +### Headers + +Headers are formatted as follows: + +```plaintext +POST /logs HTTP/1.1 +Host: +Content-Type: application/x-www-form-urlencoded +X-Gitlab-Audit-Event-Type: project_fork_operation +X-Gitlab-Event-Streaming-Token: +``` + +### Example payload + +```json +{ + "id": 1, + "author_id": 1, + "entity_id": 24, + "entity_type": "Project", + "details": { + "author_name": "example_username", + "target_id": 24, + "target_type": "Project", + "target_details": "example-project", + "custom_message": "Forked project to another-group/example-project-forked", + "ip_address": "127.0.0.1", + "entity_path": "example-group/example-project" + }, + "ip_address": "127.0.0.1", + "author_name": "example_username", + "entity_path": "example-group/example-project", + "target_details": "example-project", + "created_at": "2022-06-30T03:43:35.384Z", + "target_type": "Project", + "target_id": 24, + "event_type": "project_fork_operation" +} +``` diff --git a/ee/app/services/ee/projects/fork_service.rb b/ee/app/services/ee/projects/fork_service.rb new file mode 100644 index 00000000000000..884546157ad430 --- /dev/null +++ b/ee/app/services/ee/projects/fork_service.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +module EE + module Projects + module ForkService + extend ::Gitlab::Utils::Override + + # rubocop:disable Gitlab/ModuleWithInstanceVariables + override :stream_audit_event + def stream_audit_event(forked_project) + audit_context = { + name: 'project_fork_operation', + stream_only: true, + author: current_user, + scope: @project, + target: @project, + message: "Forked project to #{forked_project.full_path}" + } + + ::Gitlab::Audit::Auditor.audit(audit_context) + end + # rubocop:enable Gitlab/ModuleWithInstanceVariables + end + end +end diff --git a/ee/spec/services/projects/fork_service_spec.rb b/ee/spec/services/projects/fork_service_spec.rb new file mode 100644 index 00000000000000..26d55e449cb8e0 --- /dev/null +++ b/ee/spec/services/projects/fork_service_spec.rb @@ -0,0 +1,59 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Projects::ForkService do + include ProjectForksHelper + + describe 'fork by user' do + let_it_be(:user) { create(:user) } + let_it_be(:group) { create(:group) } + let_it_be(:project) { create(:project, :repository, namespace: group) } + let_it_be(:event_type) { "project_fork_operation" } + + before do + project.add_member(user, :developer) + group.external_audit_event_destinations.create!(destination_url: 'http://example.com') + end + + subject(:execute) { described_class.new(project, user).execute } + + it 'call auditor with currect context' do + audit_context = { + name: event_type, + stream_only: true, + author: user, + scope: project, + target: project, + message: "Forked project to #{user.namespace.path}/#{project.path}" + } + expect(::Gitlab::Audit::Auditor).to receive(:audit).with(hash_including(audit_context)) + + subject + end + + context "with license feature external_audit_events" do + before do + stub_licensed_features(external_audit_events: true) + end + + it 'sends correct event type in audit event stream' do + expect(AuditEvents::AuditEventStreamingWorker).to receive(:perform_async).with(event_type, nil, anything) + + subject + end + end + + context "without license feature external_audit_events" do + before do + stub_licensed_features(external_audit_events: false) + end + + it 'not sends audit event stream' do + expect(AuditEvents::AuditEventStreamingWorker).not_to receive(:perform_async) + + subject + end + end + end +end -- GitLab