diff --git a/ee/lib/gitlab/vulnerability_scanning/advisory_scanner.rb b/ee/lib/gitlab/vulnerability_scanning/advisory_scanner.rb index b5443dd974a03e72d54d33223f76f6c12541f594..bd4be948a8de5ae107c6025d4ed75e0c6d7ee469 100644 --- a/ee/lib/gitlab/vulnerability_scanning/advisory_scanner.rb +++ b/ee/lib/gitlab/vulnerability_scanning/advisory_scanner.rb @@ -57,7 +57,7 @@ def execute private - SUPPORTED_CONTAINER_SCANNING_PURL_TYPES = %w[deb rpm].freeze + SUPPORTED_CONTAINER_SCANNING_PURL_TYPES = %w[deb rpm apk].freeze attr_reader :advisory, :possibly_affected_sbom_occurrences_count, :known_affected_sbom_occurrences_count @@ -79,7 +79,7 @@ def occurrence_is_affected?(purl_type:, range:, version:, distro:, source:, proj else matcher.affected?(version) end - rescue SemverDialects::InvalidVersionError => error + rescue SemverDialects::InvalidVersionError, SemverDialects::UnsupportedVersionError => error log_cannot_determine_if_occurence_is_affected(error: error, purl_type: purl_type, version: version, project_id: project_id) false diff --git a/ee/spec/lib/gitlab/vulnerability_scanning/advisory_scanner_spec.rb b/ee/spec/lib/gitlab/vulnerability_scanning/advisory_scanner_spec.rb index d8ff065fcb83f84e2d2c861f6e6158610ff436b0..116731debd92381e191d1e9fdf417ebc63581de2 100644 --- a/ee/spec/lib/gitlab/vulnerability_scanning/advisory_scanner_spec.rb +++ b/ee/spec/lib/gitlab/vulnerability_scanning/advisory_scanner_spec.rb @@ -306,21 +306,120 @@ end end - context 'when affected packages are not supported' do + context 'when affected package purl type is supported, but component version is not in the affected range' do + let(:affected_range) { '<1.2.3' } + let(:advisory) { create(:pm_advisory, source_xid: 'trivy-db') } + + shared_examples 'tracks event and expects no vulnerabilities' do |purl_type, package_name, distro_version| + before_all do + distro_name, distro_version_string = distro_version.split(' ', 2) + affected_version = create(:sbom_component_version, version: '1.2.4') + sbom_source = create(:sbom_source, source_type: :container_scanning, packager_name: purl_type, + source: { + 'category' => 'development', + 'image' => { 'name' => 'image-1', 'tag' => 'v1' }, + 'operating_system' => { 'name' => distro_name, + 'version' => distro_version_string } + }) + source_package = create(:sbom_source_package, purl_type: purl_type, name: package_name) + component = create(:sbom_component, name: "#{distro_name}_component", purl_type: purl_type.to_sym) + create(:sbom_occurrence, source_package: source_package, component: component, + component_version: affected_version, pipeline: affected_pipeline, source: sbom_source) + end + + let(:affected_package) do + create(:pm_affected_package, package_name: package_name, distro_version: distro_version, + purl_type: purl_type, advisory: advisory, affected_range: affected_range) + end + + it 'tracks an event with correct count' do + expect(Gitlab::VulnerabilityScanning::TrackCvsService).to have_received(:new).with( + advisory: affected_package.advisory, + start_time: Time.current.iso8601, + end_time: Time.current.iso8601, + counts: { + possibly_affected_projects: 1, + possibly_affected_sbom_occurrences: 1, + known_affected_projects: 0, + known_affected_sbom_occurrences: 0 + } + ) + end + + it 'expects no vulnerabilities to be created' do + expect(affected_project.vulnerabilities.count).to eq(0) + end + end + + context 'when purl type is rpm' do + it_behaves_like 'tracks event and expects no vulnerabilities', 'rpm', 'curl', 'Oracle Linux 8' + end + + context 'when purl type is apk' do + it_behaves_like 'tracks event and expects no vulnerabilities', 'apk', 'libssh', 'alpine 3.14' + end + end + + context 'when affected package purl type is not supported' do let(:advisory) { create(:pm_advisory, source_xid: 'trivy-db') } let(:affected_package) do create(:pm_affected_package, package_name: 'openssl', distro_version: 'wolfi', purl_type: 'wolfi', advisory: advisory) end - let(:finder) { instance_spy(::Sbom::PossiblyAffectedOccurrencesFinder) } + it 'tracks an event with no affected projects or occurences' do + expect(Gitlab::VulnerabilityScanning::TrackCvsService).to have_received(:new).with( + advisory: affected_package.advisory, + start_time: Time.current.iso8601, + end_time: Time.current.iso8601, + counts: { + possibly_affected_projects: 0, + possibly_affected_sbom_occurrences: 0, + known_affected_projects: 0, + known_affected_sbom_occurrences: 0 + } + ) + end - before do - allow(::Sbom::PossiblyAffectedOccurrencesFinder).to receive(:new).and_return(finder) + it 'expects no vulnerabilities to be created' do + expect(affected_project.vulnerabilities.count).to eq(0) + end + end + + context 'when affected package version is not supported' do + before_all do + affected_version = create(:sbom_component_version, version: '1.2.03') + sbom_source = create(:sbom_source, source_type: :container_scanning, packager_name: 'apk', + source: { + 'category' => 'development', + 'image' => { 'name' => 'image-1', 'tag' => 'v1' }, + 'operating_system' => { 'name' => 'alpine', + 'version' => '3.14' } + }) + source_package = create(:sbom_source_package, purl_type: 'apk', name: 'zlib') + component = create(:sbom_component, name: "alpine_component", purl_type: :apk) + create(:sbom_occurrence, source_package: source_package, component: component, + component_version: affected_version, pipeline: affected_pipeline, source: sbom_source) end - it 'does not attempt to scan for advisory affecting package' do - expect(finder).to have_received(:execute_in_batches).exactly(0).times + let(:advisory) { create(:pm_advisory, source_xid: 'trivy-db') } + let(:affected_package) do + create(:pm_affected_package, package_name: 'zlib', distro_version: 'alpine 3.14', + purl_type: 'apk', advisory: advisory, affected_range: '<1.2.4') + end + + it "captures and tracks the unsupported version error" do + # APK package versions containing leading zeros eg 1.2.03 are currently unsupported. https://gitlab.com/gitlab-org/gitlab/-/issues/471509 + advisory = affected_package.advisory + pipeline = affected_pipeline + expect(Gitlab::ErrorTracking).to have_received(:track_exception) + .with(a_kind_of(::SemverDialects::UnsupportedVersionError), + message: 'Cannot determine if component is affected', + purl_type: 'apk', + version: '1.2.03', + project_id: pipeline.project.id, + advisory_xid: advisory.advisory_xid, + source_xid: advisory.source_xid) end end end