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

     1  package compare
     2  
     3  import (
     4  	"strings"
     5  
     6  	"golang.org/x/xerrors"
     7  
     8  	"github.com/aquasecurity/go-version/pkg/version"
     9  	dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
    10  	"github.com/devseccon/trivy/pkg/log"
    11  )
    12  
    13  // Comparer is an interface for version comparison
    14  type Comparer interface {
    15  	IsVulnerable(currentVersion string, advisory dbTypes.Advisory) bool
    16  }
    17  
    18  type matchVersion func(currentVersion, constraint string) (bool, error)
    19  
    20  // IsVulnerable checks if the package version is vulnerable to the advisory.
    21  func IsVulnerable(pkgVer string, advisory dbTypes.Advisory, match matchVersion) bool {
    22  	// If one of vulnerable/patched versions is empty, we should detect it anyway.
    23  	for _, v := range append(advisory.VulnerableVersions, advisory.PatchedVersions...) {
    24  		if v == "" {
    25  			return true
    26  		}
    27  	}
    28  	var matched bool
    29  	var err error
    30  
    31  	if len(advisory.VulnerableVersions) != 0 {
    32  		matched, err = match(pkgVer, strings.Join(advisory.VulnerableVersions, " || "))
    33  		if err != nil {
    34  			log.Logger.Warn(err)
    35  			return false
    36  		} else if !matched {
    37  			// the version is not vulnerable
    38  			return false
    39  		}
    40  	}
    41  
    42  	secureVersions := append(advisory.PatchedVersions, advisory.UnaffectedVersions...)
    43  	if len(secureVersions) == 0 {
    44  		// the version matches vulnerable versions and patched/unaffected versions are not provided
    45  		// or all values are empty
    46  		return matched
    47  	}
    48  
    49  	matched, err = match(pkgVer, strings.Join(secureVersions, " || "))
    50  	if err != nil {
    51  		log.Logger.Warn(err)
    52  		return false
    53  	}
    54  	return !matched
    55  }
    56  
    57  // GenericComparer represents a comparer for semver-like versioning
    58  type GenericComparer struct{}
    59  
    60  // IsVulnerable checks if the package version is vulnerable to the advisory.
    61  func (v GenericComparer) IsVulnerable(ver string, advisory dbTypes.Advisory) bool {
    62  	return IsVulnerable(ver, advisory, v.matchVersion)
    63  }
    64  
    65  // matchVersion checks if the package version satisfies the given constraint.
    66  func (v GenericComparer) matchVersion(currentVersion, constraint string) (bool, error) {
    67  	ver, err := version.Parse(currentVersion)
    68  	if err != nil {
    69  		return false, xerrors.Errorf("version error (%s): %s", currentVersion, err)
    70  	}
    71  
    72  	c, err := version.NewConstraints(constraint)
    73  	if err != nil {
    74  		return false, xerrors.Errorf("constraint error (%s): %s", currentVersion, err)
    75  	}
    76  
    77  	return c.Check(ver), nil
    78  }