Commit 3f34e45e authored by Stan Hu's avatar Stan Hu

Audit log: Add audit events for group setting changes

This adds audit logging for permission changes (e.g. who can create
projects, 2FA enforcement, etc.)

Closes https://gitlab.com/gitlab-org/gitlab-ee/issues/8051
parent 21bfce0c
...@@ -41,6 +41,8 @@ You need Owner [permissions] to view the group Audit Events page. ...@@ -41,6 +41,8 @@ You need Owner [permissions] to view the group Audit Events page.
To view a group's audit events, navigate to **Group > Settings > Audit Events**. To view a group's audit events, navigate to **Group > Settings > Audit Events**.
From there, you can see the following actions: From there, you can see the following actions:
- Group name/path changed
- Group repository size limit changed
- Group created/deleted - Group created/deleted
- Group changed visibility - Group changed visibility
- User was added to group and with which [permissions] - User was added to group and with which [permissions]
...@@ -51,6 +53,12 @@ From there, you can see the following actions: ...@@ -51,6 +53,12 @@ From there, you can see the following actions:
- [Project shared with group](../user/project/members/share_project_with_groups.md) - [Project shared with group](../user/project/members/share_project_with_groups.md)
and with which [permissions] and with which [permissions]
- Removal of a previously shared group with a project - Removal of a previously shared group with a project
- LFS enabled/disabled
- Shared runners minutes limit changed
- Membership lock enabled/disabled
- Request access enabled/disabled
- 2FA enforcement/grace period changed
- Roles allowed to create project changed
### Project events ### Project events
......
---
title: 'Audit log: Add audit events for group setting changes'
merge_request: 7987
author:
type: added
module EE module EE
module Audit module Audit
class GroupChangesAuditor < ProjectChangesAuditor class GroupChangesAuditor < BaseChangesAuditor
COLUMNS = %i(name path repository_size_limit visibility_level
request_access_enabled membership_lock lfs_enabled
shared_runners_minutes_limit
require_two_factor_authentication
two_factor_grace_period plan_id
project_creation_level).freeze
COLUMN_HUMAN_NAME = {
plan_id: 'plan',
visibility_level: 'visibility'
}.freeze
def execute def execute
audit_changes(:visibility_level, as: 'visibility', model: model) COLUMNS.each do |column|
audit_changes(column, as: column_human_name(column), model: model)
end
end
def attributes_from_auditable_model(column)
old = model.previous_changes[column].first
new = model.previous_changes[column].last
case column
when :visibility_level
{
from: ::Gitlab::VisibilityLevel.level_name(old),
to: ::Gitlab::VisibilityLevel.level_name(new)
}
when :project_creation_level
{
from: ::EE::Gitlab::Access.level_name(old),
to: ::EE::Gitlab::Access.level_name(new)
}
when :plan_id
{
from: plan_name(old),
to: plan_name(new)
}
else
{
from: old,
to: new
}
end
end
private
def plan_name(plan_id)
return 'none' unless plan_id.present?
Plan.find_by_id(plan_id.to_i)&.name || 'unknown'
end
def column_human_name(column)
COLUMN_HUMAN_NAME.fetch(column, column.to_s)
end end
end end
end end
......
...@@ -20,6 +20,10 @@ module EE ...@@ -20,6 +20,10 @@ module EE
s_('ProjectCreationLevel|Developers + Maintainers') => DEVELOPER_MAINTAINER_PROJECT_ACCESS s_('ProjectCreationLevel|Developers + Maintainers') => DEVELOPER_MAINTAINER_PROJECT_ACCESS
} }
end end
def level_name(name)
project_creation_options.key(name)
end
end end
end end
end end
...@@ -12,7 +12,7 @@ describe EE::Audit::GroupChangesAuditor do ...@@ -12,7 +12,7 @@ describe EE::Audit::GroupChangesAuditor do
describe 'non audit changes' do describe 'non audit changes' do
it 'does not call the audit event service' do it 'does not call the audit event service' do
group.update!(name: 'new name') group.update!(runners_token: 'new token')
expect { foo_instance.execute }.not_to change { SecurityEvent.count } expect { foo_instance.execute }.not_to change { SecurityEvent.count }
end end
...@@ -25,6 +25,58 @@ describe EE::Audit::GroupChangesAuditor do ...@@ -25,6 +25,58 @@ describe EE::Audit::GroupChangesAuditor do
expect { foo_instance.execute }.to change { SecurityEvent.count }.by(1) expect { foo_instance.execute }.to change { SecurityEvent.count }.by(1)
expect(SecurityEvent.last.details[:change]).to eq 'visibility' expect(SecurityEvent.last.details[:change]).to eq 'visibility'
end end
it 'creates an event for project creation level change' do
group.update!(project_creation_level: 0)
expect { foo_instance.execute }.to change { SecurityEvent.count }.by(1)
event = SecurityEvent.last
expect(event.details[:from]).to eq 'Maintainers'
expect(event.details[:to]).to eq 'No one'
expect(event.details[:change]).to eq 'project_creation_level'
end
it 'creates an event when the group plan changes' do
new_plan = create(:free_plan, name: 'plan-1')
group.update!(plan_id: new_plan.id)
expect { foo_instance.execute }.to change { SecurityEvent.count }.by(1)
event = SecurityEvent.last
expect(event.details[:from]).to eq 'none'
expect(event.details[:to]).to eq 'plan-1'
expect(event.details[:change]).to eq 'plan'
end
it 'creates an event when attributes change' do
# Exclude special cases covered from above
columns = described_class::COLUMNS - described_class::COLUMN_HUMAN_NAME.keys - [:project_creation_level]
columns.each do |column|
data = group.attributes[column.to_s]
value =
case Group.type_for_attribute(column.to_s).type
when :integer
data.present? ? data + 1 : 0
when :boolean
!data
else
"#{data}-next"
end
group.update_attribute(column, value)
expect { foo_instance.execute }.to change { SecurityEvent.count }.by(1)
event = SecurityEvent.last
expect(event.details[:from]).to eq data
expect(event.details[:to]).to eq value
expect(event.details[:change]).to eq column.to_s
end
end
end end
end end
end end
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