Commit 8faf152a authored by Robert Hunt's avatar Robert Hunt

Add severity level to compliance violations table

- Added new migration to add the new column
- Added new enum to hold reasons and severity levels
- Updated modal to use the new enum
- Updated model to use and validate the severity level
- Updated violation types with their severity levels
- Updated violation types creation process to save the severity level
- Updated specs

Changelog: changed
MR: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/79523
parent 3ce528ae
# frozen_string_literal: true
class AddSeverityLevelToMergeRequestsComplianceViolations < Gitlab::Database::Migration[1.0]
def change
add_column :merge_requests_compliance_violations, :severity_level, :integer, limit: 2, null: false, default: 0
end
end
a0e9bb92512b9ddb3fd718e086b0fd116ec307be6acc5789a872b1d3004fdebd
\ No newline at end of file
...@@ -16489,7 +16489,8 @@ CREATE TABLE merge_requests_compliance_violations ( ...@@ -16489,7 +16489,8 @@ CREATE TABLE merge_requests_compliance_violations (
id bigint NOT NULL, id bigint NOT NULL,
violating_user_id bigint NOT NULL, violating_user_id bigint NOT NULL,
merge_request_id bigint NOT NULL, merge_request_id bigint NOT NULL,
reason smallint NOT NULL reason smallint NOT NULL,
severity_level smallint DEFAULT 0 NOT NULL
); );
CREATE SEQUENCE merge_requests_compliance_violations_id_seq CREATE SEQUENCE merge_requests_compliance_violations_id_seq
# frozen_string_literal: true
module Enums
module MergeRequests
module ComplianceViolation
# Reasons are defined by GitLab in our public documentation.
# https://docs.gitlab.com/ee/user/compliance/compliance_dashboard/#approval-status-and-separation-of-duties
def self.reasons
{
::Gitlab::ComplianceManagement::Violations::ApprovedByMergeRequestAuthor::REASON => 0,
::Gitlab::ComplianceManagement::Violations::ApprovedByCommitter::REASON => 1,
::Gitlab::ComplianceManagement::Violations::ApprovedByInsufficientUsers::REASON => 2
}.freeze
end
def self.severity_levels
{
info: 0,
low: 1,
medium: 2,
high: 3,
critical: 4
}.freeze
end
end
end
end
...@@ -6,13 +6,8 @@ module MergeRequests ...@@ -6,13 +6,8 @@ module MergeRequests
self.table_name = 'merge_requests_compliance_violations' self.table_name = 'merge_requests_compliance_violations'
# Reasons are defined by GitLab in our public documentation. enum reason: ::Enums::MergeRequests::ComplianceViolation.reasons
# https://docs.gitlab.com/ee/user/compliance/compliance_dashboard/#approval-status-and-separation-of-duties enum severity_level: ::Enums::MergeRequests::ComplianceViolation.severity_levels
enum reason: {
::Gitlab::ComplianceManagement::Violations::ApprovedByMergeRequestAuthor::REASON => 0,
::Gitlab::ComplianceManagement::Violations::ApprovedByCommitter::REASON => 1,
::Gitlab::ComplianceManagement::Violations::ApprovedByInsufficientUsers::REASON => 2
}
scope :approved_by_committer, -> { where(reason: ::Gitlab::ComplianceManagement::Violations::ApprovedByCommitter::REASON) } scope :approved_by_committer, -> { where(reason: ::Gitlab::ComplianceManagement::Violations::ApprovedByCommitter::REASON) }
...@@ -27,6 +22,7 @@ module MergeRequests ...@@ -27,6 +22,7 @@ module MergeRequests
message: -> (_object, _data) { _('compliance violation has already been recorded') } message: -> (_object, _data) { _('compliance violation has already been recorded') }
} }
validates :reason, presence: true validates :reason, presence: true
validates :severity_level, presence: true
# The below violations need to either ignore or handle their errors to help prevent the merge process failing # The below violations need to either ignore or handle their errors to help prevent the merge process failing
VIOLATIONS = [ VIOLATIONS = [
......
...@@ -5,6 +5,7 @@ module Gitlab ...@@ -5,6 +5,7 @@ module Gitlab
module Violations module Violations
class ApprovedByCommitter class ApprovedByCommitter
REASON = :approved_by_committer REASON = :approved_by_committer
SEVERITY_LEVEL = :high
def initialize(merge_request) def initialize(merge_request)
@merge_request = merge_request @merge_request = merge_request
...@@ -24,7 +25,8 @@ module Gitlab ...@@ -24,7 +25,8 @@ module Gitlab
violating_user_ids.map do |user_id| violating_user_ids.map do |user_id|
@merge_request.compliance_violations.new( @merge_request.compliance_violations.new(
violating_user_id: user_id, violating_user_id: user_id,
reason: REASON reason: REASON,
severity_level: SEVERITY_LEVEL
) )
end end
end end
......
...@@ -5,6 +5,7 @@ module Gitlab ...@@ -5,6 +5,7 @@ module Gitlab
module Violations module Violations
class ApprovedByInsufficientUsers class ApprovedByInsufficientUsers
REASON = :approved_by_insufficient_users REASON = :approved_by_insufficient_users
SEVERITY_LEVEL = :high
# The minimum number of approvers is defined by GitLab in our public documentation. # The minimum number of approvers is defined by GitLab in our public documentation.
# https://docs.gitlab.com/ee/user/compliance/compliance_dashboard/#approval-status-and-separation-of-duties # https://docs.gitlab.com/ee/user/compliance/compliance_dashboard/#approval-status-and-separation-of-duties
...@@ -18,7 +19,8 @@ module Gitlab ...@@ -18,7 +19,8 @@ module Gitlab
if violation? if violation?
@merge_request.compliance_violations.create( @merge_request.compliance_violations.create(
violating_user: @merge_request.metrics&.merged_by || @merge_request.merge_user, violating_user: @merge_request.metrics&.merged_by || @merge_request.merge_user,
reason: REASON reason: REASON,
severity_level: SEVERITY_LEVEL
) )
end end
end end
......
...@@ -5,6 +5,7 @@ module Gitlab ...@@ -5,6 +5,7 @@ module Gitlab
module Violations module Violations
class ApprovedByMergeRequestAuthor class ApprovedByMergeRequestAuthor
REASON = :approved_by_merge_request_author REASON = :approved_by_merge_request_author
SEVERITY_LEVEL = :high
def initialize(merge_request) def initialize(merge_request)
@merge_request = merge_request @merge_request = merge_request
...@@ -14,7 +15,8 @@ module Gitlab ...@@ -14,7 +15,8 @@ module Gitlab
if violation? if violation?
@merge_request.compliance_violations.create( @merge_request.compliance_violations.create(
violating_user: @merge_request.author, violating_user: @merge_request.author,
reason: REASON reason: REASON,
severity_level: SEVERITY_LEVEL
) )
end end
end end
......
...@@ -7,14 +7,17 @@ FactoryBot.define do ...@@ -7,14 +7,17 @@ FactoryBot.define do
trait :approved_by_merge_request_author do trait :approved_by_merge_request_author do
reason { :approved_by_merge_request_author } reason { :approved_by_merge_request_author }
severity_level { :high }
end end
trait :approved_by_committer do trait :approved_by_committer do
reason { :approved_by_committer } reason { :approved_by_committer }
severity_level { :high }
end end
trait :approved_by_insufficient_users do trait :approved_by_insufficient_users do
reason { :approved_by_insufficient_users } reason { :approved_by_insufficient_users }
severity_level { :high }
end end
end end
end end
...@@ -38,6 +38,7 @@ RSpec.describe Gitlab::ComplianceManagement::Violations::ApprovedByCommitter do ...@@ -38,6 +38,7 @@ RSpec.describe Gitlab::ComplianceManagement::Violations::ApprovedByCommitter do
violations = merge_request.compliance_violations.where(reason: described_class::REASON) violations = merge_request.compliance_violations.where(reason: described_class::REASON)
expect(violations.map(&:violating_user)).to contain_exactly(user, user2) expect(violations.map(&:violating_user)).to contain_exactly(user, user2)
expect(violations.map(&:severity_level)).to contain_exactly('high', 'high')
end end
context 'when called more than once with the same violations' do context 'when called more than once with the same violations' do
...@@ -54,6 +55,7 @@ RSpec.describe Gitlab::ComplianceManagement::Violations::ApprovedByCommitter do ...@@ -54,6 +55,7 @@ RSpec.describe Gitlab::ComplianceManagement::Violations::ApprovedByCommitter do
violations = merge_request.compliance_violations.where(reason: described_class::REASON) violations = merge_request.compliance_violations.where(reason: described_class::REASON)
expect(violations.map(&:violating_user)).to contain_exactly(user, user2, user3) expect(violations.map(&:violating_user)).to contain_exactly(user, user2, user3)
expect(violations.map(&:severity_level)).to contain_exactly('high', 'high', 'high')
end end
end end
end end
......
...@@ -33,6 +33,7 @@ RSpec.describe Gitlab::ComplianceManagement::Violations::ApprovedByInsufficientU ...@@ -33,6 +33,7 @@ RSpec.describe Gitlab::ComplianceManagement::Violations::ApprovedByInsufficientU
violations = merge_request.compliance_violations.where(reason: described_class::REASON) violations = merge_request.compliance_violations.where(reason: described_class::REASON)
expect(violations.map(&:violating_user)).to contain_exactly(user) expect(violations.map(&:violating_user)).to contain_exactly(user)
expect(violations.map(&:severity_level)).to contain_exactly('high')
end end
context 'when the merge requests merge user is within metrics' do context 'when the merge requests merge user is within metrics' do
...@@ -44,6 +45,7 @@ RSpec.describe Gitlab::ComplianceManagement::Violations::ApprovedByInsufficientU ...@@ -44,6 +45,7 @@ RSpec.describe Gitlab::ComplianceManagement::Violations::ApprovedByInsufficientU
violations = merge_request.compliance_violations.where(reason: described_class::REASON) violations = merge_request.compliance_violations.where(reason: described_class::REASON)
expect(violations.map(&:violating_user)).to contain_exactly(user) expect(violations.map(&:violating_user)).to contain_exactly(user)
expect(violations.map(&:severity_level)).to contain_exactly('high')
end end
end end
......
...@@ -16,6 +16,7 @@ RSpec.describe Gitlab::ComplianceManagement::Violations::ApprovedByMergeRequestA ...@@ -16,6 +16,7 @@ RSpec.describe Gitlab::ComplianceManagement::Violations::ApprovedByMergeRequestA
violations = merge_request.compliance_violations.where(reason: described_class::REASON) violations = merge_request.compliance_violations.where(reason: described_class::REASON)
expect(violations.map(&:violating_user)).to contain_exactly(author) expect(violations.map(&:violating_user)).to contain_exactly(author)
expect(violations.map(&:severity_level)).to contain_exactly('high')
end end
end end
......
...@@ -14,6 +14,7 @@ RSpec.describe MergeRequests::ComplianceViolation, type: :model do ...@@ -14,6 +14,7 @@ RSpec.describe MergeRequests::ComplianceViolation, type: :model do
it { is_expected.to validate_presence_of(:violating_user) } it { is_expected.to validate_presence_of(:violating_user) }
it { is_expected.to validate_presence_of(:merge_request) } it { is_expected.to validate_presence_of(:merge_request) }
it { is_expected.to validate_presence_of(:reason) } it { is_expected.to validate_presence_of(:reason) }
it { is_expected.to validate_presence_of(:severity_level) }
context "when a violation exists with the same reason and user for a merge request" do context "when a violation exists with the same reason and user for a merge request" do
let_it_be(:user) { create(:user) } let_it_be(:user) { create(:user) }
...@@ -35,15 +36,9 @@ RSpec.describe MergeRequests::ComplianceViolation, type: :model do ...@@ -35,15 +36,9 @@ RSpec.describe MergeRequests::ComplianceViolation, type: :model do
end end
describe "Enums" do describe "Enums" do
it { it { is_expected.to define_enum_for(:reason).with_values(::Enums::MergeRequests::ComplianceViolation.reasons) }
is_expected.to define_enum_for(:reason).with_values(
[ it { is_expected.to define_enum_for(:severity_level).with_values(::Enums::MergeRequests::ComplianceViolation.severity_levels) }
::Gitlab::ComplianceManagement::Violations::ApprovedByMergeRequestAuthor::REASON,
::Gitlab::ComplianceManagement::Violations::ApprovedByCommitter::REASON,
::Gitlab::ComplianceManagement::Violations::ApprovedByInsufficientUsers::REASON
]
)
}
end end
describe '#approved_by_committer' do describe '#approved_by_committer' do
......
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