From 0c393436c2bdca79b59eb9bed59204b0efadd139 Mon Sep 17 00:00:00 2001 From: Brian Williams <bwilliams@gitlab.com> Date: Tue, 4 Mar 2025 14:11:35 -0600 Subject: [PATCH] Don't auto-resolve dismissed vulnerabilities If the vulnerability is dismissed, the auto-resolve policy will transition it to resolved. This is not intended as dismissed vulnerabilities should stay dismissed. This change updates the auto-resolve service to exclude dismissed vulnerabilities. Changelog: fixed EE: true --- ee/app/models/vulnerabilities/read.rb | 1 - .../vulnerabilities/auto_resolve_service.rb | 12 ++++++++++-- ee/spec/models/vulnerabilities/read_spec.rb | 13 ------------- .../vulnerabilities/auto_resolve_service_spec.rb | 4 +++- 4 files changed, 13 insertions(+), 17 deletions(-) diff --git a/ee/app/models/vulnerabilities/read.rb b/ee/app/models/vulnerabilities/read.rb index 59be3639f2f74..3f17fc223a42e 100644 --- a/ee/app/models/vulnerabilities/read.rb +++ b/ee/app/models/vulnerabilities/read.rb @@ -75,7 +75,6 @@ class << self scope :traversal_ids_gteq, ->(traversal_ids) { where(arel_table[:traversal_ids].gteq(traversal_ids)) } scope :traversal_ids_lt, ->(traversal_ids) { where(arel_table[:traversal_ids].lt(traversal_ids)) } scope :unarchived, -> { where(archived: false) } - scope :unresolved, -> { with_states(::Enums::Vulnerability.vulnerability_states.except(:resolved).values) } scope :order_traversal_ids_asc, -> do reorder(Gitlab::Pagination::Keyset::Order.build([ Gitlab::Pagination::Keyset::ColumnOrderDefinition.new( diff --git a/ee/app/services/vulnerabilities/auto_resolve_service.rb b/ee/app/services/vulnerabilities/auto_resolve_service.rb index f782e98f888ee..6fece9ca2fe22 100644 --- a/ee/app/services/vulnerabilities/auto_resolve_service.rb +++ b/ee/app/services/vulnerabilities/auto_resolve_service.rb @@ -7,7 +7,7 @@ class AutoResolveService def initialize(project, vulnerability_ids, budget) @project = project - @vulnerability_reads = Vulnerabilities::Read.by_vulnerabilities(vulnerability_ids).unresolved + @vulnerability_ids = vulnerability_ids @budget = budget end @@ -25,7 +25,15 @@ def execute private - attr_reader :project, :vulnerability_reads, :budget + attr_reader :project, :vulnerability_ids, :budget + + def vulnerability_reads + Vulnerabilities::Read.by_vulnerabilities(vulnerability_ids).with_states(auto_resolve_states) + end + + def auto_resolve_states + ::Enums::Vulnerability.vulnerability_states.except(:resolved, :dismissed).values + end def vulnerabilities_to_resolve rules_by_vulnerability.keys.first(budget) diff --git a/ee/spec/models/vulnerabilities/read_spec.rb b/ee/spec/models/vulnerabilities/read_spec.rb index e777da9ca1b54..91a78e4b6ff2d 100644 --- a/ee/spec/models/vulnerabilities/read_spec.rb +++ b/ee/spec/models/vulnerabilities/read_spec.rb @@ -841,19 +841,6 @@ it { is_expected.to contain_exactly(unarchived_vulnerability_read) } end - describe '.unresolved' do - let_it_be(:resolved_vulnerability) { create(:vulnerability_read, state: :resolved, project: project) } - let_it_be(:unresolved_vulnerabilities) do - ::Enums::Vulnerability.vulnerability_states.except(:resolved).keys.map do |state| - create(:vulnerability_read, state: state, project: project) - end - end - - subject(:unresolved) { described_class.unresolved } - - it { is_expected.to match_array(unresolved_vulnerabilities) } - end - describe '.order_traversal_ids_asc' do let_it_be(:group_1) { create(:group) } let_it_be(:group_3) { create(:group) } diff --git a/ee/spec/services/vulnerabilities/auto_resolve_service_spec.rb b/ee/spec/services/vulnerabilities/auto_resolve_service_spec.rb index 201bb4e57dbd5..244c7f8890026 100644 --- a/ee/spec/services/vulnerabilities/auto_resolve_service_spec.rb +++ b/ee/spec/services/vulnerabilities/auto_resolve_service_spec.rb @@ -8,6 +8,7 @@ let_it_be_with_reload(:project) { create(:project, namespace: namespace) } let_it_be(:vulnerability) { create(:vulnerability, :with_findings, :detected, :high_severity, project: project) } let_it_be(:resolved_vulnerability) { create(:vulnerability, :with_findings, :resolved, project: project) } + let_it_be(:dismissed_vulnerability) { create(:vulnerability, :with_findings, :dismissed, project: project) } let_it_be(:policy) { create(:security_policy, :vulnerability_management_policy, linked_projects: [project]) } let_it_be(:policy_rule) do create(:vulnerability_management_policy_rule, @@ -41,7 +42,7 @@ end describe '#execute' do - it 'resolves unresolved vulnerabilities', :freeze_time do + it 'resolves vulnerabilities that are not resolved or dismissed', :freeze_time do service.execute vulnerability.reload @@ -54,6 +55,7 @@ # This causes the timestamp to be rounded down to the nearest microsecond when the record is reloaded. # We need to make the comparison in microseconds to avoid a false-negative. expect { resolved_vulnerability.reload }.not_to change { resolved_vulnerability.updated_at.floor(6) } + expect { dismissed_vulnerability.reload }.not_to change { dismissed_vulnerability.updated_at.floor(6) } end it 'inserts a state transition for each vulnerability' do -- GitLab