github.com/noqcks/syft@v0.0.0-20230920222752-a9e2c4e288e5/syft/pkg/cataloger/common/cpe/field_candidate.go (about) 1 package cpe 2 3 import ( 4 "strconv" 5 6 "github.com/scylladb/go-set/strset" 7 ) 8 9 // fieldCandidate represents a single "guess" for a specific field in a future CPE (vendor, product, target SW, etc). 10 // When generating these candidates depending on the field the value was sourced from there may be only a subset of 11 // transforms that should be applied (downstream of extraction). Expressing candidates in this struct allows for this 12 // flexibility such that downstream transforms can be elected into or skipped over. 13 type fieldCandidate struct { 14 value string 15 disallowSubSelections bool 16 disallowDelimiterVariations bool 17 } 18 19 type fieldCandidateSet map[fieldCandidate]struct{} 20 21 func newFieldCandidateSetFromSets(sets ...fieldCandidateSet) fieldCandidateSet { 22 s := newFieldCandidateSet() 23 for _, set := range sets { 24 s.add(set.list()...) 25 } 26 return s 27 } 28 29 func newFieldCandidateSet(values ...string) fieldCandidateSet { 30 s := make(fieldCandidateSet) 31 s.addValue(values...) 32 return s 33 } 34 35 func (s fieldCandidateSet) addValue(values ...string) { 36 for _, value := range values { 37 // default candidate as an allow-all 38 candidate := fieldCandidate{ 39 value: cleanCandidateField(value), 40 } 41 s[candidate] = struct{}{} 42 } 43 } 44 45 func (s fieldCandidateSet) add(candidates ...fieldCandidate) { 46 for _, candidate := range candidates { 47 candidate.value = cleanCandidateField(candidate.value) 48 s[candidate] = struct{}{} 49 } 50 } 51 52 func (s fieldCandidateSet) removeByValue(values ...string) { 53 for _, value := range values { 54 s.removeWhere(valueEquals(value)) 55 } 56 } 57 58 // removeWhere removes all entries from the fieldCandidateSet for which the condition function returns true. 59 func (s fieldCandidateSet) removeWhere(condition fieldCandidateCondition) { 60 for candidate := range s { 61 if condition(candidate) { 62 delete(s, candidate) 63 } 64 } 65 } 66 67 func (s fieldCandidateSet) clear() { 68 for k := range s { 69 delete(s, k) 70 } 71 } 72 73 func (s fieldCandidateSet) union(others ...fieldCandidateSet) { 74 for _, other := range others { 75 s.add(other.list()...) 76 } 77 } 78 79 func (s fieldCandidateSet) list() (results []fieldCandidate) { 80 for c := range s { 81 results = append(results, c) 82 } 83 84 return results 85 } 86 87 func (s fieldCandidateSet) values() (results []string) { 88 for _, c := range s.list() { 89 results = append(results, c.value) 90 } 91 92 return results 93 } 94 95 func (s fieldCandidateSet) uniqueValues() []string { 96 return strset.New(s.values()...).List() 97 } 98 99 func (s fieldCandidateSet) copy() fieldCandidateSet { 100 newSet := newFieldCandidateSet() 101 newSet.add(s.list()...) 102 103 return newSet 104 } 105 106 func cleanCandidateField(field string) string { 107 cleanedValue, err := strconv.Unquote(field) 108 if err != nil { 109 return field 110 } 111 return cleanedValue 112 }