github.com/anchore/syft@v1.4.2-0.20240516191711-1bec1fc5d397/syft/cpe/by_specificity.go (about) 1 package cpe 2 3 import ( 4 "sort" 5 ) 6 7 var _ sort.Interface = (*BySpecificity)(nil) 8 9 type BySpecificity []Attributes 10 11 func (c BySpecificity) Len() int { return len(c) } 12 13 func (c BySpecificity) Swap(i, j int) { c[i], c[j] = c[j], c[i] } 14 15 func (c BySpecificity) Less(i, j int) bool { 16 return isMoreSpecific(c[i], c[j]) 17 } 18 19 // Returns true if i is more specific than j, with some 20 // tie breaking mechanisms to make sorting equally-specific cpe Attributes 21 // deterministic. 22 func isMoreSpecific(i, j Attributes) bool { 23 iScore := weightedCountForSpecifiedFields(i) 24 jScore := weightedCountForSpecifiedFields(j) 25 26 // check weighted sort first 27 if iScore != jScore { 28 return iScore > jScore 29 } 30 31 // sort longer fields to top 32 if countFieldLength(i) != countFieldLength(j) { 33 return countFieldLength(i) > countFieldLength(j) 34 } 35 36 // if score and length are equal then text sort 37 // note that we are not using String from the syft pkg 38 // as we are not encoding/decoding this Attributes string so we don't 39 // need the proper quoted version of the Attributes. 40 return i.BindToFmtString() < j.BindToFmtString() 41 } 42 43 func countFieldLength(cpe Attributes) int { 44 return len(cpe.Part + cpe.Vendor + cpe.Product + cpe.Version + cpe.TargetSW) 45 } 46 47 func weightedCountForSpecifiedFields(cpe Attributes) int { 48 checksForSpecifiedField := []func(cpe Attributes) (bool, int){ 49 func(cpe Attributes) (bool, int) { return cpe.Part != "", 2 }, 50 func(cpe Attributes) (bool, int) { return cpe.Vendor != "", 3 }, 51 func(cpe Attributes) (bool, int) { return cpe.Product != "", 4 }, 52 func(cpe Attributes) (bool, int) { return cpe.Version != "", 1 }, 53 func(cpe Attributes) (bool, int) { return cpe.TargetSW != "", 1 }, 54 } 55 56 weightedCount := 0 57 for _, fieldIsSpecified := range checksForSpecifiedField { 58 isSpecified, weight := fieldIsSpecified(cpe) 59 if isSpecified { 60 weightedCount += weight 61 } 62 } 63 64 return weightedCount 65 }