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