Refactor AffectedVersionRangeMatcher class to work with Container Scanning advisories
Proposal
Container Scanning advisories contain extra data compared to Dependency Scanning advisories, such as distro. Because of this, the current Gitlab::VulnerabilityScanning::AffectedVersionRangeMatcher#affected? is not sufficient to handle Container Scanning advisories.
The purpose of this issue is to refactor the Gitlab::VulnerabilityScanning::AffectedVersionRangeMatcher class so it works with both Dependency and Container Scanning advisories.
Implementation Plan
-
Create a factory class Gitlab::VulnerabilityScanning::AffectedVersionRangeMatcherFactorymodule Gitlab module VulnerabilityScanning class AffectedVersionRangeMatcherFactory def self.create(purl_type:, range:, version:, distro: nil, source: nil) if distro return Gitlab::VulnerabilityScanning::ContainerScanning::AffectedVersionRangeMatcher.new( purl_type: purl_type, range: range, version: version, distro: distro, source: source) end Gitlab::VulnerabilityScanning::DependencyScanning::AffectedVersionRangeMatcher.new( purl_type: purl_type, range: range, version: version) end attr_reader :purl_type, :range, :version, :distro, :source def initialize(purl_type:, range:, version:, distro: nil, source: nil) @purl_type = purl_type @range = range @version = version @distro = distro @source = source end def affected? raise NotImplementedError end end end end -
Move Gitlab::VulnerabilityScanning::AffectedVersionRangeMatcher to Gitlab::VulnerabilityScanning::DependencyScanning::AffectedVersionRangeMatcherand update it to work with the new factory class added in step1.above. -
Create a new class Gitlab::VulnerabilityScanning::ContainerScanning::AffectedVersionRangeMatcherand implement theaffected?method:module Gitlab module VulnerabilityScanning module ContainerScanning class AffectedVersionRangeMatcher < Gitlab::VulnerabilityScanning::AffectedVersionRangeMatcherFactory def affected? # could also move the following logic to source.matches_distro?(distro) distro_name, distro_version = distro.split(" ") return false unless distro_name == source.operating_system_name && distro_version == sanitize_operating_system_version(source.operating_system_name, source.operating_system_version) return true if range == '*' # the following requires code implemented by https://gitlab.com/gitlab-org/gitlab/-/issues/427961 SemverDialects::VersionChecker.version_sat?(purl_type, version, range) end private def sanitize_operating_system_version(operating_system_name, operating_system_version) # add code to convert the operating system version to a trivy bucket version end end end end endThe behaviour of the
sanitize_operating_system_versionmethod differs depending upon theoperating_system_name. Please see Operating System Version Sanitizing Logic for details. -
Add unit tests for the above logic -
Perform benchmarking to ensure the new code for Container Scanning advisories is as efficient as the existing code for Dependency Scanning advisories. Operating System Version Sanitizing Logic
Click for
sanitize_operating_system_versionimplementation detailstrivy uses the following logic to convert operating system version values to trivy-db compatible version values:
-
alpineParses the version from the file
/etc/apk/repositorieson the Docker container. For example, if this file contains:http://dl-cdn.alpinelinux.org/alpine/v3.12/main http://dl-cdn.alpinelinux.org/alpine/v3.12/communityThen the returned version will be
3.12If the version cannot be parsed from the
/etc/apk/repositoriesfile, thentrivywill use the minor version.In order to simplify this process, we'll always use the
minor version, for example,3.7.3will become3.7.Example:
image name trivy OS name OS name from SBOM OS version from SBOM parsed version alpine:3.7 alpine alpine 3.7.3 3.7 alpine:20230901 alpine alpine 3.19_alpha20230901 edge -
debianExample:
image name trivy OS name OS name from SBOM OS version from SBOM parsed version debian:testing-20230522-slim debian debian 12.0 12 -
rockyExample:
image name trivy OS name OS name from SBOM OS version from SBOM parsed version rockylinux:9 rocky rocky 9.2 9 -
openSUSE LeapUses the OS version as given
Example:
image name trivy OS name OS name from SBOM OS version from SBOM parsed version opensuse/leap:15.5 opensuse.leap openSUSE Leap 15.5 15.5 opensuse/leap:15.2.1 opensuse.leap openSUSE Leap 15.2.1 15.2.1 -
SUSE Linux EnterpriseUses the OS version as given
Example:
image name trivy OS name OS name from SBOM OS version from SBOM parsed version registry.suse.com/suse/sles12sp5:5.2.257 suse linux enterprise server SUSE Linux Enterprise 12.5 12.5 -
almaUses the major version
Example:
image name trivy OS name OS name from SBOM OS version from SBOM parsed version almalinux:9.3-minimal-20231124 alma alma 9.3 9 -
wolfi(chainguard)Version is ignored (notice that no
osVerparameter is passed in the Detect function)Example:
image name trivy OS name OS name from SBOM OS version from SBOM parsed version cgr.dev/chainguard/go:latest wolfi wolfi 20230201 -
amazon linuxUses the following logic to extract the version value.
Example:
image name trivy OS name OS name from SBOM OS version from SBOM parsed version amazonlinux:2023 amazon amazon linux 2023 (Amazon Linux) 2023 amazonlinux:2.0.20201218.1 amazon amazon linux 2 (Karoo) 2 amazonlinux:2016.09.0.20161028 amazon amazon linux AMI release 2016.09 1 amazonlinux:1 amazon amazon linux AMI release 2018.03 1 -
Photon OSUses the OS version as given
Example:
image name trivy OS name OS name from SBOM OS version from SBOM parsed version photon:1.0-20210409 photon Photon OS 1.0 1.0 -
Oracle LinuxUses the major version.
Example:
image name trivy OS name OS name from SBOM OS version from SBOM parsed version oraclelinux:8.2 oracle Oracle Linux 8.2 8 -
CBL-MarinerUses the minor version, for example:
2.0Example:
image name trivy OS name OS name from SBOM OS version from SBOM parsed version mcr.microsoft.com/cbl-mariner/base/core:2.0 cbl-mariner CBL-Mariner 2.0.20230303 2.0 -
ubuntuVersion is used as-is, however,
trivyhas additional logic for versions that end in-ESM. If the version ends in-ESMand it does not appear in the list of eolDates, thentrivyremoves the-ESMsuffix and attempts to use the non-ESM version from theeolDates. If this version still does not appear in the list ofeolDates, then the version is passed back as-isExample:
image name trivy OS name OS name from SBOM OS version from SBOM parsed version ubuntu:bionic-20210222 ubuntu ubuntu 18.04 18.04 ? (couldn't find an image to demonstrate this) ubuntu ubuntu 18.02-ESM 18.02-ESM ? (couldn't find an image to demonstrate this) ubuntu ubuntu 16.04-ESM 16.04-ESM ? (couldn't find an image to demonstrate this) ubuntu ubuntu 19.04-ESM 19.04
-
Auto-Summary 🤖
Discoto Usage
Points
Discussion points are declared by headings, list items, and single lines that start with the text (case-insensitive)
point:. For example, the following are all valid points:
#### POINT: This is a point* point: This is a point+ Point: This is a point- pOINT: This is a pointpoint: This is a **point**Note that any markdown used in the point text will also be propagated into the topic summaries.
Topics
Topics can be stand-alone and contained within an issuable (epic, issue, MR), or can be inline.
Inline topics are defined by creating a new thread (discussion) where the first line of the first comment is a heading that starts with (case-insensitive)
topic:. For example, the following are all valid topics:
# Topic: Inline discussion topic 1## TOPIC: **{+A Green, bolded topic+}**### tOpIc: Another topicQuick Actions
Action Description /discuss sub-topic TITLECreate an issue for a sub-topic. Does not work in epics /discuss link ISSUABLE-LINKLink an issuable as a child of this discussion
Last updated by this job
Discoto Settings
---
summary:
max_items: -1
sort_by: created
sort_direction: ascending
See the settings schema for details.