From 768d16b3363c6a4e90647a040d9b0b3e78e23e5c Mon Sep 17 00:00:00 2001 From: "Alan (Maciej) Paruszewski" <mparuszewski@gitlab.com> Date: Mon, 27 Jun 2022 22:42:11 +0000 Subject: [PATCH] Fix resolving cluster image scanning vulnerabilities Changelog: fixed EE: true --- ee/app/models/ee/vulnerability.rb | 2 +- ee/app/models/vulnerabilities/finding.rb | 1 + ...starboard_vulnerability_resolve_service.rb | 5 ++++- ee/spec/factories/vulnerabilities.rb | 20 +++++++++++++++++++ .../models/vulnerabilities/finding_spec.rb | 10 ++++++++++ .../requests/api/internal/kubernetes_spec.rb | 2 +- ...oard_vulnerability_resolve_service_spec.rb | 18 ++++++++++++++++- 7 files changed, 54 insertions(+), 4 deletions(-) diff --git a/ee/app/models/ee/vulnerability.rb b/ee/app/models/ee/vulnerability.rb index 43498ae5d0df2..16f5795a22bcc 100644 --- a/ee/app/models/ee/vulnerability.rb +++ b/ee/app/models/ee/vulnerability.rb @@ -75,7 +75,7 @@ def with_vulnerability_links scope :with_findings, -> { includes(:findings) } scope :with_findings_by_uuid, -> (uuid) { with_findings.where(findings: { uuid: uuid }) } scope :with_findings_by_uuid_and_state, -> (uuid, state) { with_findings.where(findings: { uuid: uuid }, state: state) } - scope :with_findings_excluding_uuid, -> (uuid) { with_findings.where.not(findings: { uuid: uuid }) } + scope :with_findings_excluding_uuid, -> (uuid) { joins(:findings).merge(Vulnerabilities::Finding.excluding_uuids(uuid)) } scope :with_findings_scanner_and_identifiers, -> { includes(findings: [:scanner, :identifiers, finding_identifiers: :identifier]) } scope :with_created_issue_links_and_issues, -> { includes(created_issue_links: :issue) } diff --git a/ee/app/models/vulnerabilities/finding.rb b/ee/app/models/vulnerabilities/finding.rb index c99bd15c5a8bb..720bf8430e05c 100644 --- a/ee/app/models/vulnerabilities/finding.rb +++ b/ee/app/models/vulnerabilities/finding.rb @@ -91,6 +91,7 @@ class Finding < ApplicationRecord scope :by_location_fingerprints, -> (values) { where(location_fingerprint: values) } scope :by_project_fingerprints, -> (values) { where(project_fingerprint: values) } scope :by_uuid, -> (uuids) { where(uuid: uuids) } + scope :excluding_uuids, -> (uuids) { where.not(uuid: uuids) } scope :eager_load_comparison_entities, -> { includes(:scanner, :primary_identifier) } scope :all_preloaded, -> do diff --git a/ee/app/services/vulnerabilities/starboard_vulnerability_resolve_service.rb b/ee/app/services/vulnerabilities/starboard_vulnerability_resolve_service.rb index af6b206620997..3030077216dc3 100644 --- a/ee/app/services/vulnerabilities/starboard_vulnerability_resolve_service.rb +++ b/ee/app/services/vulnerabilities/starboard_vulnerability_resolve_service.rb @@ -8,11 +8,13 @@ class StarboardVulnerabilityResolveService STATES = Vulnerability::ACTIVE_STATES BATCH_SIZE = 250 - attr_reader :project, + attr_reader :agent, + :project, :author, :uuids def initialize(agent, uuids) + @agent = agent @project = agent.project @author = agent.created_by_user @uuids = uuids @@ -35,6 +37,7 @@ def undetected .with_states(STATES) .with_report_types(REPORT_TYPE) .with_findings_excluding_uuid(uuids) + .with_cluster_agent_ids([agent.id.to_s]) end def authorized? diff --git a/ee/spec/factories/vulnerabilities.rb b/ee/spec/factories/vulnerabilities.rb index 91831c859b64d..183a91525a880 100644 --- a/ee/spec/factories/vulnerabilities.rb +++ b/ee/spec/factories/vulnerabilities.rb @@ -99,6 +99,26 @@ end end + trait :with_cluster_image_scanning_finding do + transient do + agent_id { '46357' } + end + + after(:build) do |vulnerability, evaluator| + finding = build( + :vulnerabilities_finding, + :identifier, + :with_cluster_image_scanning_scanning_metadata, + agent_id: evaluator.agent_id, + vulnerability: vulnerability, + report_type: :cluster_image_scanning, + project: vulnerability.project + ) + + vulnerability.findings = [finding] + end + end + trait :with_remediation do after(:build) do |vulnerability| finding = build( diff --git a/ee/spec/models/vulnerabilities/finding_spec.rb b/ee/spec/models/vulnerabilities/finding_spec.rb index 90077f5c14c52..cafd1064d3526 100644 --- a/ee/spec/models/vulnerabilities/finding_spec.rb +++ b/ee/spec/models/vulnerabilities/finding_spec.rb @@ -1119,4 +1119,14 @@ it { is_expected.to contain_exactly(finding) } end + + describe '.excluding_uuids' do + let(:finding_1) { create(:vulnerabilities_finding) } + let(:finding_2) { create(:vulnerabilities_finding) } + let(:finding_3) { create(:vulnerabilities_finding) } + + subject { described_class.excluding_uuids([finding_1.uuid, finding_3.uuid]) } + + it { is_expected.to contain_exactly(finding_2) } + end end diff --git a/ee/spec/requests/api/internal/kubernetes_spec.rb b/ee/spec/requests/api/internal/kubernetes_spec.rb index fc6c460e6ebad..573fa367935ad 100644 --- a/ee/spec/requests/api/internal/kubernetes_spec.rb +++ b/ee/spec/requests/api/internal/kubernetes_spec.rb @@ -291,7 +291,7 @@ def send_request(headers: {}, params: {}) let_it_be(:agent) { agent_token.agent } let_it_be(:project) { agent.project } - let_it_be(:existing_vulnerabilities) { create_list(:vulnerability, 4, :detected, :with_finding, project: project, report_type: :cluster_image_scanning) } + let_it_be(:existing_vulnerabilities) { create_list(:vulnerability, 4, :detected, :with_cluster_image_scanning_finding, agent_id: agent.id.to_s, project: project, report_type: :cluster_image_scanning) } let_it_be(:detected_vulnerabilities) { existing_vulnerabilities.first(2) } let_it_be(:undetected_vulnerabilities) { existing_vulnerabilities - detected_vulnerabilities } let_it_be(:payload) { { uuids: detected_vulnerabilities.map { |vuln| vuln.finding.uuid } } } diff --git a/ee/spec/services/vulnerabilities/starboard_vulnerability_resolve_service_spec.rb b/ee/spec/services/vulnerabilities/starboard_vulnerability_resolve_service_spec.rb index 626404da1bc38..ac7aa7ad00498 100644 --- a/ee/spec/services/vulnerabilities/starboard_vulnerability_resolve_service_spec.rb +++ b/ee/spec/services/vulnerabilities/starboard_vulnerability_resolve_service_spec.rb @@ -4,10 +4,17 @@ RSpec.describe Vulnerabilities::StarboardVulnerabilityResolveService do let_it_be(:agent) { create(:cluster_agent) } + let_it_be(:other_agent) { create(:cluster_agent) } let_it_be(:project) { agent.project } let_it_be(:user) { agent.created_by_user } - let_it_be(:existing_vulnerabilities) { create_list(:vulnerability, 4, :detected, :with_finding, project: project, report_type: :cluster_image_scanning) } + let_it_be(:existing_vulnerabilities) do + create_list(:vulnerability, 4, + :detected, :with_cluster_image_scanning_finding, + agent_id: agent.id.to_s, project: project, report_type: :cluster_image_scanning + ) + end + let_it_be(:detected_vulnerabilities) { existing_vulnerabilities.first(2) } let_it_be(:undetected_vulnerabilities) { existing_vulnerabilities - detected_vulnerabilities } let_it_be(:uuids) { detected_vulnerabilities.map(&:finding).map(&:uuid) } @@ -57,6 +64,15 @@ expect { subject }.not_to change { Vulnerability.resolved.count } end + it "does not resolve vulnerabilities created by other agent" do + Vulnerabilities::Finding.all.each do |finding| + finding.location['kubernetes_resource']['agent_id'] = other_agent.id.to_s + finding.save! + end + + expect { subject }.not_to change { Vulnerability.resolved.count } + end + it 'does not resolve vulnerabilities in passive states' do EE::Vulnerability::PASSIVE_STATES.each do |state| Vulnerability.where(id: undetected_vulnerabilities).update_all(state: state) -- GitLab