github.com/quay/claircore@v1.5.28/java/matcher.go (about)

     1  package java
     2  
     3  import (
     4  	"context"
     5  	"github.com/quay/claircore"
     6  	"github.com/quay/claircore/libvuln/driver"
     7  	"github.com/quay/zlog"
     8  	"net/url"
     9  )
    10  
    11  // Matcher matches discovered Java Maven packages against advisories provided via OSV.
    12  type Matcher struct{}
    13  
    14  var (
    15  	_ driver.Matcher = (*Matcher)(nil)
    16  )
    17  
    18  // Name implements driver.Matcher.
    19  func (*Matcher) Name() string { return "java-maven" }
    20  
    21  func (*Matcher) Filter(r *claircore.IndexRecord) bool {
    22  	return r.Repository != nil &&
    23  		r.Repository.Name == Repository.Name
    24  }
    25  
    26  // Query implements driver.Matcher.
    27  func (*Matcher) Query() []driver.MatchConstraint {
    28  	return []driver.MatchConstraint{driver.RepositoryName}
    29  }
    30  
    31  func (*Matcher) Vulnerable(ctx context.Context, record *claircore.IndexRecord, vuln *claircore.Vulnerability) (bool, error) {
    32  	// TODO(ross): This is a common pattern for OSV vulnerabilities. This should be moved into
    33  	// a common place for all OSV vulnerability matchers.
    34  
    35  	if vuln.FixedInVersion == "" {
    36  		return true, nil
    37  	}
    38  
    39  	// Parse the package first. If it cannot be parsed, it cannot properly be analyzed for vulnerabilities.
    40  	rv, err := parseMavenVersion(record.Package.Version)
    41  	if err != nil {
    42  		return false, err
    43  	}
    44  
    45  	decodedVersions, err := url.ParseQuery(vuln.FixedInVersion)
    46  	if err != nil {
    47  		return false, err
    48  	}
    49  
    50  	introduced := decodedVersions.Get("introduced")
    51  	// If there is an introduced version, check if the package's version is lower.
    52  	if introduced != "" {
    53  		iv, err := parseMavenVersion(introduced)
    54  		if err != nil {
    55  			zlog.Warn(ctx).
    56  				Str("package", vuln.Package.Name).
    57  				Str("version", introduced).
    58  				Msg("unable to parse maven introduced version")
    59  			return false, err
    60  		}
    61  		// If the package's version is less than the introduced version, it's not vulnerable.
    62  		if rv.Compare(iv) < 0 {
    63  			return false, nil
    64  		}
    65  	}
    66  
    67  	fixedVersion := decodedVersions.Get("fixed")
    68  	lastAffected := decodedVersions.Get("lastAffected")
    69  	switch {
    70  	case fixedVersion != "":
    71  		fv, err := parseMavenVersion(fixedVersion)
    72  		if err != nil {
    73  			zlog.Warn(ctx).
    74  				Str("package", vuln.Package.Name).
    75  				Str("version", fixedVersion).
    76  				Msg("unable to parse maven fixed version")
    77  			return false, err
    78  		}
    79  		// The package is affected if its version is less than the fixed version.
    80  		return rv.Compare(fv) < 0, nil
    81  	case lastAffected != "":
    82  		la, err := parseMavenVersion(lastAffected)
    83  		if err != nil {
    84  			zlog.Warn(ctx).
    85  				Str("package", vuln.Package.Name).
    86  				Str("version", lastAffected).
    87  				Msg("unable to parse maven last_affected version")
    88  			return false, err
    89  		}
    90  		// The package is affected if its version is less than or equal to the last affected version.
    91  		return rv.Compare(la) <= 0, nil
    92  	}
    93  
    94  	// Just say the package is vulnerable, by default.
    95  	return true, nil
    96  }