Commit 13f562bb authored by Pedro Pombeiro's avatar Pedro Pombeiro Committed by Douglas Barbosa Alexandre

Add audit logs when assigning CI runner to project

Changelog: added
EE: true
parent 62c7a73b
......@@ -3,9 +3,9 @@
module Ci
module Runners
class AssignRunnerService
# @param [Ci::Runner] runner the runner to assign to a project
# @param [Project] project the new project to assign the runner to
# @param [User] user the user performing the operation
# @param [Ci::Runner] runner: the runner to assign to a project
# @param [Project] project: the new project to assign the runner to
# @param [User] user: the user performing the operation
def initialize(runner, project, user)
@runner = runner
@project = project
......@@ -17,6 +17,12 @@ module Ci
@runner.assign_to(@project, @user)
end
private
attr_reader :runner, :project, :user
end
end
end
Ci::Runners::AssignRunnerService.prepend_mod
......@@ -19,6 +19,7 @@ module AuditEvents
target_type: runner.class.name,
target_details: runner_path
}
details.merge!(entity_id: @token_scope.id, entity_type: @token_scope.class.name) if @token_scope
if author.is_a?(String)
author = author[0...8]
......
# frozen_string_literal: true
module AuditEvents
class RunnerCustomAuditEventService < RunnerAuditEventService
# Logs an audit event with a custom message related to a runner event
#
# @param [Ci::Runner] runner
# @param [String, User] author: the entity initiating the operation (e.g. a runner registration or authentication token)
# @param [Group, Project, nil] token_scope: the scopes that the operation applies to (nil represents the instance)
# @param [String] custom_message: the message describing the event
def initialize(runner, author, token_scope, custom_message)
@custom_message = custom_message
super(runner, author, token_scope)
end
def message
@custom_message
end
end
end
# frozen_string_literal: true
module EE
module Ci
module Runners
module AssignRunnerService
extend ::Gitlab::Utils::Override
include ::Audit::Changes
override :execute
def execute
result = super
audit_log_event if result
result
end
private
AUDIT_MESSAGE = 'Assigned CI runner to project'
def audit_log_event
::AuditEvents::RunnerCustomAuditEventService.new(runner, user, project, AUDIT_MESSAGE).track_event
end
end
end
end
end
......@@ -116,6 +116,8 @@ RSpec.describe AuditEvents::RegisterRunnerAuditEventService do
author_name: author[0...8],
runner_registration_token: author[0...8],
custom_message: 'Registered group CI runner',
entity_id: entity.id,
entity_type: entity.class.name,
entity_path: entity.full_path,
target_details: target_details
}
......@@ -173,6 +175,8 @@ RSpec.describe AuditEvents::RegisterRunnerAuditEventService do
details: {
author_name: author[0...8],
runner_registration_token: author[0...8],
entity_id: entity.id,
entity_type: entity.class.name,
entity_path: entity.full_path,
target_details: target_details
}
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe AuditEvents::RunnerCustomAuditEventService do
describe '#security_event' do
let(:logger) { instance_double(Gitlab::AuditJsonLogger) }
let(:user) { create(:user) }
let(:entity) { create(:project) }
let(:target_details) { ::Gitlab::Routing.url_helpers.project_runner_path(entity, runner) }
let(:target_id) { runner.id }
let(:target_type) { 'Ci::Runner' }
let(:entity_type) { 'Project' }
let(:runner) { create(:ci_runner, :project, projects: [entity]) }
let(:custom_message) { 'Custom Event' }
let(:service) { described_class.new(runner, user, entity, custom_message) }
before do
stub_licensed_features(audit_events: true)
end
it 'logs the event to file' do
expect(service).to receive(:file_logger).and_return(logger)
expect(logger).to receive(:info).with(author_id: user.id,
author_name: user.name,
entity_id: entity.id,
entity_type: entity_type,
custom_message: custom_message,
target_details: target_details,
target_id: target_id,
target_type: target_type)
expect { service.security_event }.to change(AuditEvent, :count).by(1)
security_event = AuditEvent.last
expect(security_event.details).to eq(
author_name: user.name,
custom_message: custom_message,
entity_id: entity.id,
entity_type: entity_type,
target_details: target_details,
target_id: target_id,
target_type: target_type
)
expect(security_event.author_id).to eq(user.id)
expect(security_event.entity_id).to eq(entity.id)
expect(security_event.entity_type).to eq(entity_type)
end
end
end
......@@ -42,6 +42,8 @@ RSpec.describe AuditEvents::UnregisterRunnerAuditEventService do
target_details: target_details,
details: {
custom_message: "Unregistered #{entity_class_name&.downcase || 'instance'} CI runner",
entity_id: entity&.id || -1,
entity_type: entity ? entity_class_name : 'User',
entity_path: entity&.full_path,
target_details: target_details
}
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe ::Ci::Runners::AssignRunnerService, '#execute' do
let_it_be(:owner_project) { create(:project) }
let_it_be(:new_project) { create(:project) }
let_it_be(:project_runner) { create(:ci_runner, :project, projects: [owner_project]) }
let(:audit_service) { instance_double(::AuditEvents::RunnerCustomAuditEventService) }
subject { described_class.new(project_runner, new_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 assign_to return value', :aggregate_failures do
expect(project_runner).to receive(:assign_to).with(new_project, user).once.and_return('assign_to return value')
expect(::AuditEvents::RunnerCustomAuditEventService).to receive(:new)
.with(project_runner, user, new_project, 'Assigned CI runner to project')
.once.and_return(audit_service)
is_expected.to eq('assign_to return value')
end
end
end
......@@ -5,8 +5,8 @@ require 'spec_helper'
RSpec.describe ::Ci::Runners::AssignRunnerService, '#execute' do
subject { described_class.new(runner, project, user).execute }
let_it_be(:runner) { build(:ci_runner) }
let_it_be(:project) { build(:project) }
let_it_be(:runner) { create(:ci_runner, :project, projects: [project]) }
let_it_be(:project) { create(:project) }
context 'without user' do
let(:user) { nil }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment