github.com/devseccon/trivy@v0.47.1-0.20231123133102-bd902a0bd996/pkg/detector/ospkg/chainguard/chainguard.go (about) 1 package chainguard 2 3 import ( 4 version "github.com/knqyf263/go-apk-version" 5 "golang.org/x/xerrors" 6 "k8s.io/utils/clock" 7 8 dbTypes "github.com/aquasecurity/trivy-db/pkg/types" 9 "github.com/aquasecurity/trivy-db/pkg/vulnsrc/chainguard" 10 ftypes "github.com/devseccon/trivy/pkg/fanal/types" 11 "github.com/devseccon/trivy/pkg/log" 12 "github.com/devseccon/trivy/pkg/scanner/utils" 13 "github.com/devseccon/trivy/pkg/types" 14 ) 15 16 type options struct { 17 clock clock.Clock 18 } 19 20 type option func(*options) 21 22 func WithClock(c clock.Clock) option { 23 return func(opts *options) { 24 opts.clock = c 25 } 26 } 27 28 // Scanner implements the Chainguard scanner 29 type Scanner struct { 30 vs chainguard.VulnSrc 31 *options 32 } 33 34 // NewScanner is the factory method for Scanner 35 func NewScanner(opts ...option) *Scanner { 36 o := &options{ 37 clock: clock.RealClock{}, 38 } 39 40 for _, opt := range opts { 41 opt(o) 42 } 43 return &Scanner{ 44 vs: chainguard.NewVulnSrc(), 45 options: o, 46 } 47 } 48 49 // Detect vulnerabilities in package using Chainguard scanner 50 func (s *Scanner) Detect(_ string, _ *ftypes.Repository, pkgs []ftypes.Package) ([]types.DetectedVulnerability, error) { 51 log.Logger.Info("Detecting Chainguard vulnerabilities...") 52 53 log.Logger.Debugf("chainguard: the number of packages: %d", len(pkgs)) 54 55 var vulns []types.DetectedVulnerability 56 for _, pkg := range pkgs { 57 srcName := pkg.SrcName 58 if srcName == "" { 59 srcName = pkg.Name 60 } 61 advisories, err := s.vs.Get("", srcName) 62 if err != nil { 63 return nil, xerrors.Errorf("failed to get Chainguard advisories: %w", err) 64 } 65 66 installed := utils.FormatVersion(pkg) 67 installedVersion, err := version.NewVersion(installed) 68 if err != nil { 69 log.Logger.Debugf("failed to parse Chainguard installed package version: %s", err) 70 continue 71 } 72 73 for _, adv := range advisories { 74 if !s.isVulnerable(installedVersion, adv) { 75 continue 76 } 77 vulns = append(vulns, types.DetectedVulnerability{ 78 VulnerabilityID: adv.VulnerabilityID, 79 PkgID: pkg.ID, 80 PkgName: pkg.Name, 81 InstalledVersion: installed, 82 FixedVersion: adv.FixedVersion, 83 Layer: pkg.Layer, 84 PkgRef: pkg.Ref, 85 Custom: adv.Custom, 86 DataSource: adv.DataSource, 87 }) 88 } 89 } 90 return vulns, nil 91 } 92 93 func (s *Scanner) isVulnerable(installedVersion version.Version, adv dbTypes.Advisory) bool { 94 // Compare versions for fixed vulnerabilities 95 fixedVersion, err := version.NewVersion(adv.FixedVersion) 96 if err != nil { 97 log.Logger.Debugf("failed to parse Chainguard fixed version: %s", err) 98 return false 99 } 100 101 // It means the fixed vulnerability 102 return installedVersion.LessThan(fixedVersion) 103 } 104 105 // IsSupportedVersion checks if the version is supported. 106 func (s *Scanner) IsSupportedVersion(_ ftypes.OSType, _ string) bool { 107 // Chainguard doesn't have versions, so there is no case where a given input yields a 108 // result of an unsupported Chainguard version. 109 110 return true 111 }