From 6f7186c52af863637d445ac3c8f8f3005622effb Mon Sep 17 00:00:00 2001 From: Max Woolf Date: Fri, 2 Jul 2021 14:14:03 +0100 Subject: [PATCH] Adds audit event when compliance framework changed Adds a new audit event when a project adds, changes or removes a compliance framework. EE: true Changelog: added --- doc/administration/audit_events.md | 1 + .../compliance_framework/project_settings.rb | 2 + ee/lib/ee/audit/project_changes_auditor.rb | 37 ++++++++++++ .../ee/audit/project_changes_auditor_spec.rb | 59 +++++++++++++++++++ 4 files changed, 99 insertions(+) diff --git a/doc/administration/audit_events.md b/doc/administration/audit_events.md index ccf632b7d6ae75..ed9411cdcb732e 100644 --- a/doc/administration/audit_events.md +++ b/doc/administration/audit_events.md @@ -122,6 +122,7 @@ From there, you can see the following actions: - When default branch changes for a project ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/52339) in GitLab 13.9) - Created, updated, or deleted DAST profiles, DAST scanner profiles, and DAST site profiles ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/217872) in GitLab 14.1) +- Changed a project's compliance framework ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/329362) in GitLab 14.1) Project events can also be accessed via the [Project Audit Events API](../api/audit_events.md#project-audit-events). diff --git a/ee/app/models/compliance_management/compliance_framework/project_settings.rb b/ee/app/models/compliance_management/compliance_framework/project_settings.rb index 197554dae1880d..e1ca8680fae404 100644 --- a/ee/app/models/compliance_management/compliance_framework/project_settings.rb +++ b/ee/app/models/compliance_management/compliance_framework/project_settings.rb @@ -16,6 +16,8 @@ class ProjectSettings < ApplicationRecord belongs_to :compliance_management_framework, class_name: "ComplianceManagement::Framework", foreign_key: :framework_id validates :project, presence: true + + delegate :full_path, to: :project end end end diff --git a/ee/lib/ee/audit/project_changes_auditor.rb b/ee/lib/ee/audit/project_changes_auditor.rb index 6067052b79eb0c..d5cd69c37d27cd 100644 --- a/ee/lib/ee/audit/project_changes_auditor.rb +++ b/ee/lib/ee/audit/project_changes_auditor.rb @@ -15,14 +15,46 @@ def execute audit_changes(:merge_requests_disable_committers_approval, as: 'prevent merge request approval from reviewers', model: model) audit_project_feature_changes + audit_compliance_framework_changes end private + def audit_compliance_framework_changes + setting = model.compliance_framework_setting + + return if setting.blank? + + if setting.destroyed? + audit_context = { + author: @current_user, + scope: model, + target: model, + message: "Unassigned project compliance framework" + } + + ::Gitlab::Audit::Auditor.audit(audit_context) + else + audit_changes(:framework_id, as: 'compliance framework', model: model.compliance_framework_setting, entity: model) + end + end + def audit_project_feature_changes ::EE::Audit::ProjectFeatureChangesAuditor.new(@current_user, model.project_feature, model).execute end + def framework_changes + model.previous_changes["framework_id"] + end + + def old_framework_name + ComplianceManagement::Framework.find_by_id(framework_changes.first)&.name || "None" + end + + def new_framework_name + ComplianceManagement::Framework.find_by_id(framework_changes.last)&.name || "None" + end + def attributes_from_auditable_model(column) case column when :name @@ -50,6 +82,11 @@ def attributes_from_auditable_model(column) from: !model.previous_changes[column].first, to: !model.previous_changes[column].last } + when :framework_id + { + from: old_framework_name, + to: new_framework_name + } else { from: model.previous_changes[column].first, diff --git a/ee/spec/lib/ee/audit/project_changes_auditor_spec.rb b/ee/spec/lib/ee/audit/project_changes_auditor_spec.rb index 2bfac726798900..7d4103ed413637 100644 --- a/ee/spec/lib/ee/audit/project_changes_auditor_spec.rb +++ b/ee/spec/lib/ee/audit/project_changes_auditor_spec.rb @@ -33,6 +33,65 @@ end end + describe 'auditing compliance framework changes' do + context 'when a project has no compliance framework' do + context 'when the framework is changed' do + let_it_be(:framework) { create(:compliance_framework) } + + before do + project.update!(compliance_management_framework: framework) + end + + it 'adds an audit event' do + expect { foo_instance.execute }.to change { AuditEvent.count }.by(1) + expect(AuditEvent.last.details).to include({ + change: 'compliance framework', + from: 'None', + to: 'GDPR' + }) + end + + context 'when the framework is removed' do + before do + project.update!(compliance_management_framework: nil) + end + + it 'adds an audit event' do + expect { foo_instance.execute }.to change { AuditEvent.count }.by(1) + expect(AuditEvent.last.details).to include({ + custom_message: "Unassigned project compliance framework" + }) + end + end + + context 'when the framework is changed again' do + before do + project.update!(compliance_management_framework: create(:compliance_framework, namespace: project.namespace, name: 'SOX')) + end + + it 'adds an audit event' do + expect { foo_instance.execute }.to change { AuditEvent.count }.by(1) + expect(AuditEvent.last.details).to include({ + change: 'compliance framework', + from: 'GDPR', + to: 'SOX' + }) + end + end + end + + context 'when the framework is not changed' do + before do + project.update!(description: 'This is a description of a project') + end + + it 'does not add an audit event' do + expect { foo_instance.execute }.not_to change { AuditEvent.count } + end + end + end + end + describe 'audit changes' do it 'creates an event when the visibility change' do project.update!(visibility_level: 20) -- GitLab