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

     1  package rocky
     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  	"github.com/aquasecurity/trivy-db/pkg/vulnsrc/rocky"
    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  	eolDates = map[string]time.Time{
    20  		// Source:
    21  		// https://endoflife.date/rocky-linux
    22  		"8": time.Date(2029, 5, 31, 23, 59, 59, 0, time.UTC),
    23  		"9": time.Date(2032, 5, 31, 23, 59, 59, 0, time.UTC),
    24  	}
    25  )
    26  
    27  type options struct {
    28  	clock clock.Clock
    29  }
    30  
    31  type option func(*options)
    32  
    33  func WithClock(c clock.Clock) option {
    34  	return func(opts *options) {
    35  		opts.clock = c
    36  	}
    37  }
    38  
    39  // Scanner implements the Rocky Linux scanner
    40  type Scanner struct {
    41  	vs *rocky.VulnSrc
    42  	*options
    43  }
    44  
    45  // NewScanner is the factory method for Scanner
    46  func NewScanner(opts ...option) *Scanner {
    47  	o := &options{
    48  		clock: clock.RealClock{},
    49  	}
    50  
    51  	for _, opt := range opts {
    52  		opt(o)
    53  	}
    54  	return &Scanner{
    55  		vs:      rocky.NewVulnSrc(),
    56  		options: o,
    57  	}
    58  }
    59  
    60  // Detect vulnerabilities in package using Rocky Linux scanner
    61  func (s *Scanner) Detect(osVer string, _ *ftypes.Repository, pkgs []ftypes.Package) ([]types.DetectedVulnerability, error) {
    62  	log.Logger.Info("Detecting Rocky Linux vulnerabilities...")
    63  
    64  	osVer = osver.Major(osVer)
    65  	log.Logger.Debugf("Rocky Linux: os version: %s", osVer)
    66  	log.Logger.Debugf("Rocky Linux: the number of packages: %d", len(pkgs))
    67  
    68  	var vulns []types.DetectedVulnerability
    69  	var skipPkgs []string
    70  	for _, pkg := range pkgs {
    71  		if pkg.Modularitylabel != "" {
    72  			skipPkgs = append(skipPkgs, pkg.Name)
    73  			continue
    74  		}
    75  		pkgName := addModularNamespace(pkg.Name, pkg.Modularitylabel)
    76  		advisories, err := s.vs.Get(osVer, pkgName, pkg.Arch)
    77  		if err != nil {
    78  			return nil, xerrors.Errorf("failed to get Rocky Linux advisories: %w", err)
    79  		}
    80  
    81  		installed := utils.FormatVersion(pkg)
    82  		installedVersion := version.NewVersion(installed)
    83  
    84  		for _, adv := range advisories {
    85  			fixedVersion := version.NewVersion(adv.FixedVersion)
    86  			if installedVersion.LessThan(fixedVersion) {
    87  				vuln := types.DetectedVulnerability{
    88  					VulnerabilityID:  adv.VulnerabilityID,
    89  					PkgID:            pkg.ID,
    90  					PkgName:          pkg.Name,
    91  					InstalledVersion: installed,
    92  					FixedVersion:     fixedVersion.String(),
    93  					PkgRef:           pkg.Ref,
    94  					Layer:            pkg.Layer,
    95  					DataSource:       adv.DataSource,
    96  					Custom:           adv.Custom,
    97  				}
    98  				vulns = append(vulns, vuln)
    99  			}
   100  		}
   101  	}
   102  	if len(skipPkgs) > 0 {
   103  		log.Logger.Infof("Skipped detection of these packages: %q because modular packages cannot be detected correctly due to a bug in Rocky Linux Errata. See also: https://forums.rockylinux.org/t/some-errata-missing-in-comparison-with-rhel-and-almalinux/3843", skipPkgs)
   104  	}
   105  
   106  	return vulns, nil
   107  }
   108  
   109  // IsSupportedVersion checks if the version is supported.
   110  func (s *Scanner) IsSupportedVersion(osFamily ftypes.OSType, osVer string) bool {
   111  	return osver.Supported(s.clock, eolDates, osFamily, osver.Major(osVer))
   112  }
   113  
   114  func addModularNamespace(name, label string) string {
   115  	// e.g. npm, nodejs:12:8030020201124152102:229f0a1c => nodejs:12::npm
   116  	var count int
   117  	for i, r := range label {
   118  		if r == ':' {
   119  			count++
   120  		}
   121  		if count == 2 {
   122  			return label[:i] + "::" + name
   123  		}
   124  	}
   125  	return name
   126  }