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

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