github.com/devseccon/trivy@v0.47.1-0.20231123133102-bd902a0bd996/pkg/detector/ospkg/suse/suse.go (about)

     1  package suse
     2  
     3  import (
     4  	"time"
     5  
     6  	version "github.com/knqyf263/go-rpm-version"
     7  	"golang.org/x/xerrors"
     8  	"k8s.io/utils/clock"
     9  
    10  	susecvrf "github.com/aquasecurity/trivy-db/pkg/vulnsrc/suse-cvrf"
    11  	osver "github.com/devseccon/trivy/pkg/detector/ospkg/version"
    12  	ftypes "github.com/devseccon/trivy/pkg/fanal/types"
    13  	"github.com/devseccon/trivy/pkg/log"
    14  	"github.com/devseccon/trivy/pkg/scanner/utils"
    15  	"github.com/devseccon/trivy/pkg/types"
    16  )
    17  
    18  var (
    19  	slesEolDates = map[string]time.Time{
    20  		// Source: https://www.suse.com/lifecycle/
    21  		"10":   time.Date(2007, 12, 31, 23, 59, 59, 0, time.UTC),
    22  		"10.1": time.Date(2008, 11, 30, 23, 59, 59, 0, time.UTC),
    23  		"10.2": time.Date(2010, 4, 11, 23, 59, 59, 0, time.UTC),
    24  		"10.3": time.Date(2011, 10, 11, 23, 59, 59, 0, time.UTC),
    25  		"10.4": time.Date(2013, 7, 31, 23, 59, 59, 0, time.UTC),
    26  		"11":   time.Date(2010, 12, 31, 23, 59, 59, 0, time.UTC),
    27  		"11.1": time.Date(2012, 8, 31, 23, 59, 59, 0, time.UTC),
    28  		"11.2": time.Date(2014, 1, 31, 23, 59, 59, 0, time.UTC),
    29  		"11.3": time.Date(2016, 1, 31, 23, 59, 59, 0, time.UTC),
    30  		"11.4": time.Date(2019, 3, 31, 23, 59, 59, 0, time.UTC),
    31  		"12":   time.Date(2016, 6, 30, 23, 59, 59, 0, time.UTC),
    32  		"12.1": time.Date(2017, 5, 31, 23, 59, 59, 0, time.UTC),
    33  		"12.2": time.Date(2018, 3, 31, 23, 59, 59, 0, time.UTC),
    34  		"12.3": time.Date(2019, 1, 30, 23, 59, 59, 0, time.UTC),
    35  		"12.4": time.Date(2020, 6, 30, 23, 59, 59, 0, time.UTC),
    36  		"12.5": time.Date(2024, 10, 31, 23, 59, 59, 0, time.UTC),
    37  		"15":   time.Date(2019, 12, 31, 23, 59, 59, 0, time.UTC),
    38  		"15.1": time.Date(2021, 1, 31, 23, 59, 59, 0, time.UTC),
    39  		"15.2": time.Date(2021, 12, 31, 23, 59, 59, 0, time.UTC),
    40  		"15.3": time.Date(2022, 12, 31, 23, 59, 59, 0, time.UTC),
    41  		"15.4": time.Date(2023, 12, 31, 23, 59, 59, 0, time.UTC),
    42  		"15.5": time.Date(2028, 12, 31, 23, 59, 59, 0, time.UTC),
    43  		// 6 months after SLES 15 SP7 release
    44  		// "15.6": time.Date(2028, 12, 31, 23, 59, 59, 0, time.UTC),
    45  	}
    46  
    47  	opensuseEolDates = map[string]time.Time{
    48  		// Source: https://en.opensuse.org/Lifetime
    49  		"42.1": time.Date(2017, 5, 17, 23, 59, 59, 0, time.UTC),
    50  		"42.2": time.Date(2018, 1, 26, 23, 59, 59, 0, time.UTC),
    51  		"42.3": time.Date(2019, 6, 30, 23, 59, 59, 0, time.UTC),
    52  		"15.0": time.Date(2019, 12, 3, 23, 59, 59, 0, time.UTC),
    53  		"15.1": time.Date(2020, 11, 30, 23, 59, 59, 0, time.UTC),
    54  		"15.2": time.Date(2021, 11, 30, 23, 59, 59, 0, time.UTC),
    55  		"15.3": time.Date(2022, 11, 30, 23, 59, 59, 0, time.UTC),
    56  		"15.4": time.Date(2023, 11, 30, 23, 59, 59, 0, time.UTC),
    57  		"15.5": time.Date(2024, 12, 31, 23, 59, 59, 0, time.UTC),
    58  	}
    59  )
    60  
    61  type options struct {
    62  	clock clock.Clock
    63  }
    64  
    65  type option func(*options)
    66  
    67  func WithClock(c clock.Clock) option {
    68  	return func(opts *options) {
    69  		opts.clock = c
    70  	}
    71  }
    72  
    73  // Type defines SUSE type
    74  type Type int
    75  
    76  const (
    77  	// SUSEEnterpriseLinux is Linux Enterprise version
    78  	SUSEEnterpriseLinux Type = iota
    79  	// OpenSUSE for open versions
    80  	OpenSUSE
    81  )
    82  
    83  // Scanner implements the SUSE scanner
    84  type Scanner struct {
    85  	vs susecvrf.VulnSrc
    86  	*options
    87  }
    88  
    89  // NewScanner is the factory method for Scanner
    90  func NewScanner(t Type, opts ...option) *Scanner {
    91  	o := &options{
    92  		clock: clock.RealClock{},
    93  	}
    94  
    95  	for _, opt := range opts {
    96  		opt(o)
    97  	}
    98  
    99  	switch t {
   100  	case SUSEEnterpriseLinux:
   101  		return &Scanner{
   102  			vs:      susecvrf.NewVulnSrc(susecvrf.SUSEEnterpriseLinux),
   103  			options: o,
   104  		}
   105  	case OpenSUSE:
   106  		return &Scanner{
   107  			vs:      susecvrf.NewVulnSrc(susecvrf.OpenSUSE),
   108  			options: o,
   109  		}
   110  	}
   111  	return nil
   112  }
   113  
   114  // Detect scans and returns the vulnerabilities
   115  func (s *Scanner) Detect(osVer string, _ *ftypes.Repository, pkgs []ftypes.Package) ([]types.DetectedVulnerability, error) {
   116  	log.Logger.Info("Detecting SUSE vulnerabilities...")
   117  	log.Logger.Debugf("SUSE: os version: %s", osVer)
   118  	log.Logger.Debugf("SUSE: the number of packages: %d", len(pkgs))
   119  
   120  	var vulns []types.DetectedVulnerability
   121  	for _, pkg := range pkgs {
   122  		advisories, err := s.vs.Get(osVer, pkg.Name)
   123  		if err != nil {
   124  			return nil, xerrors.Errorf("failed to get SUSE advisory: %w", err)
   125  		}
   126  
   127  		installed := utils.FormatVersion(pkg)
   128  		installedVersion := version.NewVersion(installed)
   129  		for _, adv := range advisories {
   130  			fixedVersion := version.NewVersion(adv.FixedVersion)
   131  			vuln := types.DetectedVulnerability{
   132  				VulnerabilityID:  adv.VulnerabilityID,
   133  				PkgID:            pkg.ID,
   134  				PkgName:          pkg.Name,
   135  				InstalledVersion: installed,
   136  				PkgRef:           pkg.Ref,
   137  				Layer:            pkg.Layer,
   138  				Custom:           adv.Custom,
   139  				DataSource:       adv.DataSource,
   140  			}
   141  			if installedVersion.LessThan(fixedVersion) {
   142  				vuln.FixedVersion = adv.FixedVersion
   143  				vulns = append(vulns, vuln)
   144  			}
   145  		}
   146  	}
   147  	return vulns, nil
   148  }
   149  
   150  // IsSupportedVersion checks if OSFamily can be scanned using SUSE scanner
   151  func (s *Scanner) IsSupportedVersion(osFamily ftypes.OSType, osVer string) bool {
   152  	if osFamily == ftypes.SLES {
   153  		return osver.Supported(s.clock, slesEolDates, osFamily, osVer)
   154  	}
   155  	return osver.Supported(s.clock, opensuseEolDates, osFamily, osVer)
   156  }