Projects STRLCPY syft Commits 64be0a10
🤬
Revision indexing in progress... (symbol navigation in revisions will be accurate after indexed)
  • ■ ■ ■ ■ ■ ■
    syft/pkg/cpe_by_specificity.go syft/cpe/by_specificity.go
    1  -package pkg
     1 +package cpe
    2 2   
    3 3  import (
    4 4   "sort"
    skipped 1 lines
    6 6   "github.com/facebookincubator/nvdtools/wfn"
    7 7  )
    8 8   
    9  -var _ sort.Interface = (*CPEBySpecificity)(nil)
     9 +var _ sort.Interface = (*BySpecificity)(nil)
    10 10   
    11  -type CPEBySpecificity []wfn.Attributes
     11 +type BySpecificity []wfn.Attributes
    12 12   
    13  -func (c CPEBySpecificity) Len() int { return len(c) }
     13 +func (c BySpecificity) Len() int { return len(c) }
    14 14   
    15  -func (c CPEBySpecificity) Swap(i, j int) { c[i], c[j] = c[j], c[i] }
     15 +func (c BySpecificity) Swap(i, j int) { c[i], c[j] = c[j], c[i] }
    16 16   
    17  -func (c CPEBySpecificity) Less(i, j int) bool {
     17 +func (c BySpecificity) Less(i, j int) bool {
    18 18   iScore := weightedCountForSpecifiedFields(c[i])
    19 19   jScore := weightedCountForSpecifiedFields(c[j])
    20 20   
    skipped 8 lines
    29 29   }
    30 30   
    31 31   // if score and length are equal then text sort
    32  - // note that we are not using CPEString from the syft pkg
     32 + // note that we are not using String from the syft pkg
    33 33   // as we are not encoding/decoding this CPE string so we don't
    34 34   // need the proper quoted version of the CPE.
    35 35   return c[i].BindToFmtString() < c[j].BindToFmtString()
    skipped 26 lines
  • ■ ■ ■ ■ ■ ■
    syft/cpe/by_specificity_test.go
     1 +package cpe
     2 + 
     3 +import (
     4 + "sort"
     5 + "testing"
     6 + 
     7 + "github.com/stretchr/testify/assert"
     8 +)
     9 + 
     10 +func Test_BySpecificity(t *testing.T) {
     11 + tests := []struct {
     12 + name string
     13 + input []CPE
     14 + expected []CPE
     15 + }{
     16 + {
     17 + name: "sort strictly by wfn *",
     18 + input: []CPE{
     19 + Must("cpe:2.3:a:*:package:1:*:*:*:*:*:*:*"),
     20 + Must("cpe:2.3:a:some:package:1:*:*:*:*:*:*:*"),
     21 + Must("cpe:2.3:a:*:package:1:*:*:*:*:some:*:*"),
     22 + Must("cpe:2.3:a:some:package:1:*:*:*:*:some:*:*"),
     23 + Must("cpe:2.3:a:some:package:*:*:*:*:*:*:*:*"),
     24 + },
     25 + expected: []CPE{
     26 + Must("cpe:2.3:a:some:package:1:*:*:*:*:some:*:*"),
     27 + Must("cpe:2.3:a:some:package:1:*:*:*:*:*:*:*"),
     28 + Must("cpe:2.3:a:some:package:*:*:*:*:*:*:*:*"),
     29 + Must("cpe:2.3:a:*:package:1:*:*:*:*:some:*:*"),
     30 + Must("cpe:2.3:a:*:package:1:*:*:*:*:*:*:*"),
     31 + },
     32 + },
     33 + {
     34 + name: "sort strictly by field length",
     35 + input: []CPE{
     36 + Must("cpe:2.3:a:1:22:1:*:*:*:*:1:*:*"),
     37 + Must("cpe:2.3:a:55555:1:1:*:*:*:*:1:*:*"),
     38 + Must("cpe:2.3:a:1:1:333:*:*:*:*:1:*:*"),
     39 + Must("cpe:2.3:a:1:666666:1:*:*:*:*:1:*:*"),
     40 + Must("cpe:2.3:a:1:1:1:*:*:*:*:1:*:*"),
     41 + Must("cpe:2.3:a:1:1:1:*:*:*:*:4444:*:*"),
     42 + },
     43 + expected: []CPE{
     44 + Must("cpe:2.3:a:1:666666:1:*:*:*:*:1:*:*"),
     45 + Must("cpe:2.3:a:55555:1:1:*:*:*:*:1:*:*"),
     46 + Must("cpe:2.3:a:1:1:1:*:*:*:*:4444:*:*"),
     47 + Must("cpe:2.3:a:1:1:333:*:*:*:*:1:*:*"),
     48 + Must("cpe:2.3:a:1:22:1:*:*:*:*:1:*:*"),
     49 + Must("cpe:2.3:a:1:1:1:*:*:*:*:1:*:*"),
     50 + },
     51 + },
     52 + {
     53 + name: "sort by mix of field length and specificity",
     54 + input: []CPE{
     55 + Must("cpe:2.3:a:1:666666:*:*:*:*:*:1:*:*"),
     56 + Must("cpe:2.3:a:*:1:1:*:*:*:*:4444:*:*"),
     57 + Must("cpe:2.3:a:1:*:333:*:*:*:*:*:*:*"),
     58 + Must("cpe:2.3:a:1:1:1:*:*:*:*:1:*:*"),
     59 + Must("cpe:2.3:a:1:22:1:*:*:*:*:1:*:*"),
     60 + Must("cpe:2.3:a:55555:1:1:*:*:*:*:1:*:*"),
     61 + },
     62 + expected: []CPE{
     63 + Must("cpe:2.3:a:55555:1:1:*:*:*:*:1:*:*"),
     64 + Must("cpe:2.3:a:1:22:1:*:*:*:*:1:*:*"),
     65 + Must("cpe:2.3:a:1:1:1:*:*:*:*:1:*:*"),
     66 + Must("cpe:2.3:a:1:666666:*:*:*:*:*:1:*:*"),
     67 + Must("cpe:2.3:a:*:1:1:*:*:*:*:4444:*:*"),
     68 + Must("cpe:2.3:a:1:*:333:*:*:*:*:*:*:*"),
     69 + },
     70 + },
     71 + {
     72 + name: "sort by mix of field length, specificity, dash",
     73 + input: []CPE{
     74 + Must("cpe:2.3:a:alpine:alpine_keys:2.3-r1:*:*:*:*:*:*:*"),
     75 + Must("cpe:2.3:a:alpine_keys:alpine_keys:2.3-r1:*:*:*:*:*:*:*"),
     76 + Must("cpe:2.3:a:alpine-keys:alpine_keys:2.3-r1:*:*:*:*:*:*:*"),
     77 + Must("cpe:2.3:a:alpine:alpine-keys:2.3-r1:*:*:*:*:*:*:*"),
     78 + Must("cpe:2.3:a:alpine-keys:alpine-keys:2.3-r1:*:*:*:*:*:*:*"),
     79 + Must("cpe:2.3:a:alpine_keys:alpine-keys:2.3-r1:*:*:*:*:*:*:*"),
     80 + },
     81 + expected: []CPE{
     82 + Must("cpe:2.3:a:alpine-keys:alpine-keys:2.3-r1:*:*:*:*:*:*:*"),
     83 + Must("cpe:2.3:a:alpine-keys:alpine_keys:2.3-r1:*:*:*:*:*:*:*"),
     84 + Must("cpe:2.3:a:alpine_keys:alpine-keys:2.3-r1:*:*:*:*:*:*:*"),
     85 + Must("cpe:2.3:a:alpine_keys:alpine_keys:2.3-r1:*:*:*:*:*:*:*"),
     86 + Must("cpe:2.3:a:alpine:alpine-keys:2.3-r1:*:*:*:*:*:*:*"),
     87 + Must("cpe:2.3:a:alpine:alpine_keys:2.3-r1:*:*:*:*:*:*:*"),
     88 + },
     89 + },
     90 + }
     91 + 
     92 + for _, test := range tests {
     93 + t.Run(test.name, func(t *testing.T) {
     94 + sort.Sort(BySpecificity(test.input))
     95 + assert.Equal(t, test.expected, test.input)
     96 + })
     97 + }
     98 +}
     99 + 
  • ■ ■ ■ ■ ■ ■
    syft/pkg/cpe.go syft/cpe/cpe.go
    1  -package pkg
     1 +package cpe
    2 2   
    3 3  import (
    4 4   "fmt"
    skipped 19 lines
    24 24   
    25 25  var cpeRegex = regexp.MustCompile(cpeRegexString)
    26 26   
    27  -// NewCPE will parse a formatted CPE string and return a CPE object. Some input, such as the existence of whitespace
     27 +// New will parse a formatted CPE string and return a CPE object. Some input, such as the existence of whitespace
    28 28  // characters is allowed, however, a more strict validation is done after this sanitization process.
    29  -func NewCPE(cpeStr string) (CPE, error) {
     29 +func New(cpeStr string) (CPE, error) {
    30 30   // get a CPE object based on the given string --don't validate yet since it may be possible to escape select cases on the callers behalf
    31  - c, err := newCPEWithoutValidation(cpeStr)
     31 + c, err := newWithoutValidation(cpeStr)
    32 32   if err != nil {
    33 33   return CPE{}, fmt.Errorf("unable to parse CPE string: %w", err)
    34 34   }
    35 35   
    36 36   // ensure that this CPE can be validated after being fully sanitized
    37  - if ValidateCPEString(CPEString(c)) != nil {
     37 + if ValidateString(String(c)) != nil {
    38 38   return CPE{}, err
    39 39   }
    40 40   
    skipped 2 lines
    43 43   return c, nil
    44 44  }
    45 45   
    46  -func ValidateCPEString(cpeStr string) error {
     46 +// Must returns a CPE or panics if the provided string is not valid
     47 +func Must(cpeStr string) CPE {
     48 + c, err := New(cpeStr)
     49 + if err != nil {
     50 + panic(err)
     51 + }
     52 + return c
     53 +}
     54 + 
     55 +func ValidateString(cpeStr string) error {
    47 56   // We should filter out all CPEs that do not match the official CPE regex
    48 57   // The facebook nvdtools parser can sometimes incorrectly parse invalid CPE strings
    49 58   if !cpeRegex.MatchString(cpeStr) {
    skipped 2 lines
    52 61   return nil
    53 62  }
    54 63   
    55  -func newCPEWithoutValidation(cpeStr string) (CPE, error) {
     64 +func newWithoutValidation(cpeStr string) (CPE, error) {
    56 65   value, err := wfn.Parse(cpeStr)
    57 66   if err != nil {
    58 67   return CPE{}, fmt.Errorf("failed to parse CPE=%q: %w", cpeStr, err)
    skipped 4 lines
    63 72   }
    64 73   
    65 74   // we need to compare the raw data since we are constructing CPEs in other locations
    66  - value.Vendor = normalizeCpeField(value.Vendor)
    67  - value.Product = normalizeCpeField(value.Product)
    68  - value.Language = normalizeCpeField(value.Language)
    69  - value.Version = normalizeCpeField(value.Version)
    70  - value.TargetSW = normalizeCpeField(value.TargetSW)
    71  - value.Part = normalizeCpeField(value.Part)
    72  - value.Edition = normalizeCpeField(value.Edition)
    73  - value.Other = normalizeCpeField(value.Other)
    74  - value.SWEdition = normalizeCpeField(value.SWEdition)
    75  - value.TargetHW = normalizeCpeField(value.TargetHW)
    76  - value.Update = normalizeCpeField(value.Update)
     75 + value.Vendor = normalizeField(value.Vendor)
     76 + value.Product = normalizeField(value.Product)
     77 + value.Language = normalizeField(value.Language)
     78 + value.Version = normalizeField(value.Version)
     79 + value.TargetSW = normalizeField(value.TargetSW)
     80 + value.Part = normalizeField(value.Part)
     81 + value.Edition = normalizeField(value.Edition)
     82 + value.Other = normalizeField(value.Other)
     83 + value.SWEdition = normalizeField(value.SWEdition)
     84 + value.TargetHW = normalizeField(value.TargetHW)
     85 + value.Update = normalizeField(value.Update)
    77 86   
    78 87   return *value, nil
    79 88  }
    80 89   
    81  -func MustCPE(cpeStr string) CPE {
    82  - c, err := NewCPE(cpeStr)
    83  - if err != nil {
    84  - panic(err)
    85  - }
    86  - return c
    87  -}
    88  - 
    89  -func normalizeCpeField(field string) string {
     90 +func normalizeField(field string) string {
    90 91   // replace spaces with underscores (per section 5.3.2 of the CPE spec v 2.3)
    91 92   field = strings.ReplaceAll(field, " ", "_")
    92 93   
    skipped 19 lines
    112 113   return sb.String()
    113 114  }
    114 115   
    115  -func CPEString(c CPE) string {
     116 +func String(c CPE) string {
    116 117   output := CPE{}
    117 118   output.Vendor = sanitize(c.Vendor)
    118 119   output.Product = sanitize(c.Product)
    skipped 37 lines
  • ■ ■ ■ ■ ■ ■
    syft/pkg/cpe_test.go syft/cpe/cpe_test.go
    1  -package pkg
     1 +package cpe
    2 2   
    3 3  import (
    4 4   "encoding/json"
    skipped 6 lines
    11 11   "github.com/stretchr/testify/require"
    12 12  )
    13 13   
    14  -func must(c CPE, e error) CPE {
    15  - if e != nil {
    16  - panic(e)
    17  - }
    18  - return c
    19  -}
    20  - 
    21  -func TestNewCPE(t *testing.T) {
     14 +func Test_New(t *testing.T) {
    22 15   tests := []struct {
    23 16   name string
    24 17   input string
    skipped 2 lines
    27 20   {
    28 21   name: "gocase",
    29 22   input: `cpe:/a:10web:form_maker:1.0.0::~~~wordpress~~`,
    30  - expected: must(NewCPE(`cpe:2.3:a:10web:form_maker:1.0.0:*:*:*:*:wordpress:*:*`)),
     23 + expected: Must(`cpe:2.3:a:10web:form_maker:1.0.0:*:*:*:*:wordpress:*:*`),
    31 24   },
    32 25   {
    33 26   name: "dashes",
    34 27   input: `cpe:/a:7-zip:7-zip:4.56:beta:~~~windows~~`,
    35  - expected: must(NewCPE(`cpe:2.3:a:7-zip:7-zip:4.56:beta:*:*:*:windows:*:*`)),
     28 + expected: Must(`cpe:2.3:a:7-zip:7-zip:4.56:beta:*:*:*:windows:*:*`),
    36 29   },
    37 30   {
    38 31   name: "URL escape characters",
    39 32   input: `cpe:/a:%240.99_kindle_books_project:%240.99_kindle_books:6::~~~android~~`,
    40  - expected: must(NewCPE(`cpe:2.3:a:\$0.99_kindle_books_project:\$0.99_kindle_books:6:*:*:*:*:android:*:*`)),
     33 + expected: Must(`cpe:2.3:a:\$0.99_kindle_books_project:\$0.99_kindle_books:6:*:*:*:*:android:*:*`),
    41 34   },
    42 35   }
    43 36   
    44 37   for _, test := range tests {
    45 38   t.Run(test.name, func(t *testing.T) {
    46  - actual, err := NewCPE(test.input)
     39 + actual, err := New(test.input)
    47 40   if err != nil {
    48 41   t.Fatalf("got an error while creating CPE: %+v", err)
    49 42   }
    50 43   
    51  - if CPEString(actual) != CPEString(test.expected) {
    52  - t.Errorf("mismatched entries:\n\texpected:%+v\n\t actual:%+v\n", CPEString(test.expected), CPEString(actual))
     44 + if String(actual) != String(test.expected) {
     45 + t.Errorf("mismatched entries:\n\texpected:%+v\n\t actual:%+v\n", String(test.expected), String(actual))
    53 46   }
    54 47   
    55 48   })
    skipped 25 lines
    81 74   }
    82 75   for _, test := range tests {
    83 76   t.Run(test.field, func(t *testing.T) {
    84  - assert.Equal(t, test.expected, normalizeCpeField(test.field))
     77 + assert.Equal(t, test.expected, normalizeField(test.field))
    85 78   })
    86 79   }
    87 80  }
    skipped 10 lines
    98 91   
    99 92   for _, test := range testCases {
    100 93   t.Run(test.CPEString, func(t *testing.T) {
    101  - c1, err := NewCPE(test.CPEString)
     94 + c1, err := New(test.CPEString)
    102 95   assert.NoError(t, err)
    103  - c2, err := NewCPE(test.CPEUrl)
     96 + c2, err := New(test.CPEUrl)
    104 97   assert.NoError(t, err)
    105 98   assert.Equal(t, c1, c2)
    106 99   assert.Equal(t, c1, test.WFN)
    107 100   assert.Equal(t, c2, test.WFN)
    108  - assert.Equal(t, CPEString(test.WFN), test.CPEString)
     101 + assert.Equal(t, String(test.WFN), test.CPEString)
    109 102   })
    110 103   }
    111 104  }
    skipped 55 lines
    167 160   
    168 161   for _, test := range tests {
    169 162   t.Run(test.name, func(t *testing.T) {
    170  - c, err := NewCPE(test.in)
     163 + c, err := New(test.in)
    171 164   if test.expectedErr {
    172 165   assert.Error(t, err)
    173 166   if t.Failed() {
    174  - t.Logf("got CPE: %q details: %+v", CPEString(c), c)
     167 + t.Logf("got CPE: %q details: %+v", String(c), c)
    175 168   }
    176 169   return
    177 170   }
    178 171   require.NoError(t, err)
    179  - assert.Equal(t, test.expected, CPEString(c))
     172 + assert.Equal(t, test.expected, String(c))
    180 173   })
    181 174   }
    182 175  }
    skipped 39 lines
    222 215   for _, test := range tests {
    223 216   t.Run(test.name, func(t *testing.T) {
    224 217   // CPE string must be preserved through a round trip
    225  - assert.Equal(t, test.cpe, CPEString(MustCPE(test.cpe)))
     218 + assert.Equal(t, test.cpe, String(Must(test.cpe)))
    226 219   // The parsed CPE must be the same after a round trip
    227  - assert.Equal(t, MustCPE(test.cpe), MustCPE(CPEString(MustCPE(test.cpe))))
     220 + assert.Equal(t, Must(test.cpe), Must(String(Must(test.cpe))))
    228 221   // The test case parsed CPE must be the same after parsing the input string
    229  - assert.Equal(t, test.parsedCPE, MustCPE(test.cpe))
     222 + assert.Equal(t, test.parsedCPE, Must(test.cpe))
    230 223   // The test case parsed CPE must produce the same string as the input cpe
    231  - assert.Equal(t, CPEString(test.parsedCPE), test.cpe)
     224 + assert.Equal(t, String(test.parsedCPE), test.cpe)
    232 225   })
    233 226   }
    234 227  }
    skipped 1 lines
  • ■ ■ ■ ■ ■ ■
    syft/pkg/merge_cpes.go syft/cpe/merge_cpes.go
    1  -package pkg
     1 +package cpe
    2 2   
    3 3  import (
    4 4   "sort"
    5 5  )
    6 6   
    7  -func mergeCPEs(a, b []CPE) (result []CPE) {
     7 +func Merge(a, b []CPE) (result []CPE) {
    8 8   aCPEs := make(map[string]CPE)
    9 9   
    10 10   // keep all CPEs from a and create a quick string-based lookup
    skipped 9 lines
    20 20   }
    21 21   }
    22 22   
    23  - sort.Sort(CPEBySpecificity(result))
     23 + sort.Sort(BySpecificity(result))
    24 24   return result
    25 25  }
    26 26   
  • ■ ■ ■ ■ ■ ■
    syft/cpe/merge_cpes_test.go
     1 +package cpe
     2 + 
     3 +import (
     4 + "testing"
     5 + 
     6 + "github.com/stretchr/testify/assert"
     7 +)
     8 + 
     9 +func Test_Merge(t *testing.T) {
     10 + tests := []struct {
     11 + name string
     12 + input [][]CPE
     13 + expected []CPE
     14 + }{
     15 + {
     16 + name: "merge, removing duplicates and ordered",
     17 + input: [][]CPE{
     18 + {
     19 + Must("cpe:2.3:a:*:package:1:*:*:*:*:*:*:*"),
     20 + Must("cpe:2.3:a:some:package:*:*:*:*:*:*:*:*"),
     21 + },
     22 + {
     23 + Must("cpe:2.3:a:some:package:1:*:*:*:*:*:*:*"),
     24 + Must("cpe:2.3:a:some:package:*:*:*:*:*:*:*:*"),
     25 + },
     26 + },
     27 + expected: []CPE{
     28 + Must("cpe:2.3:a:some:package:1:*:*:*:*:*:*:*"),
     29 + Must("cpe:2.3:a:some:package:*:*:*:*:*:*:*:*"),
     30 + Must("cpe:2.3:a:*:package:1:*:*:*:*:*:*:*"),
     31 + },
     32 + },
     33 + }
     34 + 
     35 + for _, test := range tests {
     36 + t.Run(test.name, func(t *testing.T) {
     37 + out := Merge(test.input[0], test.input[1])
     38 + assert.Equal(t, test.expected, out)
     39 + })
     40 + }
     41 +}
     42 + 
  • syft/pkg/test-fixtures/cpe-data.json syft/cpe/test-fixtures/cpe-data.json
    Content is identical
  • ■ ■ ■ ■ ■ ■
    syft/formats/common/cyclonedxhelpers/cpe.go
    skipped 3 lines
    4 4   "github.com/CycloneDX/cyclonedx-go"
    5 5   
    6 6   "github.com/anchore/syft/internal/log"
     7 + "github.com/anchore/syft/syft/cpe"
    7 8   "github.com/anchore/syft/syft/pkg"
    8 9  )
    9 10   
    skipped 1 lines
    11 12   // Since the CPEs in a package are sorted by specificity
    12 13   // we can extract the first CPE as the one to output in cyclonedx
    13 14   if len(p.CPEs) > 0 {
    14  - return pkg.CPEString(p.CPEs[0])
     15 + return cpe.String(p.CPEs[0])
    15 16   }
    16 17   return ""
    17 18  }
    skipped 6 lines
    24 25   }
    25 26   out = append(out, cyclonedx.Property{
    26 27   Name: "syft:cpe23",
    27  - Value: pkg.CPEString(c),
     28 + Value: cpe.String(c),
    28 29   })
    29 30   }
    30 31   return
    31 32  }
    32 33   
    33  -func decodeCPEs(c *cyclonedx.Component) (out []pkg.CPE) {
     34 +func decodeCPEs(c *cyclonedx.Component) (out []cpe.CPE) {
    34 35   if c.CPE != "" {
    35  - cp, err := pkg.NewCPE(c.CPE)
     36 + cp, err := cpe.New(c.CPE)
    36 37   if err != nil {
    37 38   log.Warnf("invalid CPE: %s", c.CPE)
    38 39   } else {
    skipped 4 lines
    43 44   if c.Properties != nil {
    44 45   for _, p := range *c.Properties {
    45 46   if p.Name == "syft:cpe23" {
    46  - cp, err := pkg.NewCPE(p.Value)
     47 + cp, err := cpe.New(p.Value)
    47 48   if err != nil {
    48 49   log.Warnf("invalid CPE: %s", p.Value)
    49 50   } else {
    skipped 9 lines
  • ■ ■ ■ ■ ■ ■
    syft/formats/common/cyclonedxhelpers/cpe_test.go
    skipped 4 lines
    5 5   
    6 6   "github.com/stretchr/testify/assert"
    7 7   
     8 + "github.com/anchore/syft/syft/cpe"
    8 9   "github.com/anchore/syft/syft/pkg"
    9 10  )
    10 11   
    11 12  func Test_encodeCPE(t *testing.T) {
    12  - testCPE := pkg.MustCPE("cpe:2.3:a:name:name:3.2:*:*:*:*:*:*:*")
    13  - testCPE2 := pkg.MustCPE("cpe:2.3:a:name:name2:3.2:*:*:*:*:*:*:*")
     13 + testCPE := cpe.Must("cpe:2.3:a:name:name:3.2:*:*:*:*:*:*:*")
     14 + testCPE2 := cpe.Must("cpe:2.3:a:name:name2:3.2:*:*:*:*:*:*:*")
    14 15   tests := []struct {
    15 16   name string
    16 17   input pkg.Package
    skipped 3 lines
    20 21   // note: since this is an optional field, no value is preferred over NONE or NOASSERTION
    21 22   name: "no metadata",
    22 23   input: pkg.Package{
    23  - CPEs: []pkg.CPE{},
     24 + CPEs: []cpe.CPE{},
    24 25   },
    25 26   expected: "",
    26 27   },
    27 28   {
    28 29   name: "single CPE",
    29 30   input: pkg.Package{
    30  - CPEs: []pkg.CPE{
     31 + CPEs: []cpe.CPE{
    31 32   testCPE,
    32 33   },
    33 34   },
    skipped 2 lines
    36 37   {
    37 38   name: "multiple CPEs",
    38 39   input: pkg.Package{
    39  - CPEs: []pkg.CPE{
     40 + CPEs: []cpe.CPE{
    40 41   testCPE2,
    41 42   testCPE,
    42 43   },
    skipped 17 lines
  • ■ ■ ■ ■ ■
    syft/formats/common/cyclonedxhelpers/format.go
    skipped 8 lines
    9 9   "github.com/anchore/syft/internal"
    10 10   "github.com/anchore/syft/internal/log"
    11 11   "github.com/anchore/syft/syft/artifact"
     12 + "github.com/anchore/syft/syft/cpe"
    12 13   "github.com/anchore/syft/syft/linux"
    13 14   "github.com/anchore/syft/syft/pkg"
    14 15   "github.com/anchore/syft/syft/sbom"
    skipped 85 lines
    100 101  }
    101 102   
    102 103  func formatCPE(cpeString string) string {
    103  - cpe, err := pkg.NewCPE(cpeString)
     104 + c, err := cpe.New(cpeString)
    104 105   if err != nil {
    105 106   log.Debugf("skipping invalid CPE: %s", cpeString)
    106 107   return ""
    107 108   }
    108  - return pkg.CPEString(cpe)
     109 + return cpe.String(c)
    109 110  }
    110 111   
    111 112  // NewBomDescriptor returns a new BomDescriptor tailored for the current time and "syft" tool details.
    skipped 95 lines
  • ■ ■ ■ ■ ■
    syft/formats/common/spdxhelpers/external_refs.go
    1 1  package spdxhelpers
    2 2   
    3 3  import (
     4 + "github.com/anchore/syft/syft/cpe"
    4 5   "github.com/anchore/syft/syft/pkg"
    5 6  )
    6 7   
    skipped 3 lines
    10 11   for _, c := range p.CPEs {
    11 12   externalRefs = append(externalRefs, ExternalRef{
    12 13   ReferenceCategory: SecurityReferenceCategory,
    13  - ReferenceLocator: pkg.CPEString(c),
     14 + ReferenceLocator: cpe.String(c),
    14 15   ReferenceType: Cpe23ExternalRefType,
    15 16   })
    16 17   }
    skipped 12 lines
  • ■ ■ ■ ■ ■ ■
    syft/formats/common/spdxhelpers/external_refs_test.go
    skipped 4 lines
    5 5   
    6 6   "github.com/stretchr/testify/assert"
    7 7   
     8 + "github.com/anchore/syft/syft/cpe"
    8 9   "github.com/anchore/syft/syft/pkg"
    9 10  )
    10 11   
    11 12  func Test_ExternalRefs(t *testing.T) {
    12  - testCPE := pkg.MustCPE("cpe:2.3:a:name:name:3.2:*:*:*:*:*:*:*")
     13 + testCPE := cpe.Must("cpe:2.3:a:name:name:3.2:*:*:*:*:*:*:*")
    13 14   tests := []struct {
    14 15   name string
    15 16   input pkg.Package
    skipped 2 lines
    18 19   {
    19 20   name: "cpe + purl",
    20 21   input: pkg.Package{
    21  - CPEs: []pkg.CPE{
     22 + CPEs: []cpe.CPE{
    22 23   testCPE,
    23 24   },
    24 25   PURL: "a-purl",
    skipped 1 lines
    26 27   expected: []ExternalRef{
    27 28   {
    28 29   ReferenceCategory: SecurityReferenceCategory,
    29  - ReferenceLocator: pkg.CPEString(testCPE),
     30 + ReferenceLocator: cpe.String(testCPE),
    30 31   ReferenceType: Cpe23ExternalRefType,
    31 32   },
    32 33   {
    skipped 14 lines
  • ■ ■ ■ ■ ■ ■
    syft/formats/common/spdxhelpers/to_syft_model.go
    skipped 10 lines
    11 11   "github.com/anchore/packageurl-go"
    12 12   "github.com/anchore/syft/internal/log"
    13 13   "github.com/anchore/syft/syft/artifact"
     14 + "github.com/anchore/syft/syft/cpe"
    14 15   "github.com/anchore/syft/syft/file"
    15 16   "github.com/anchore/syft/syft/formats/common/util"
    16 17   "github.com/anchore/syft/syft/linux"
    skipped 364 lines
    381 382   return ""
    382 383  }
    383 384   
    384  -func extractCPEs(p *spdx.Package) (cpes []pkg.CPE) {
     385 +func extractCPEs(p *spdx.Package) (cpes []cpe.CPE) {
    385 386   for _, r := range p.PackageExternalReferences {
    386 387   if r.RefType == string(Cpe23ExternalRefType) {
    387  - cpe, err := pkg.NewCPE(r.Locator)
     388 + c, err := cpe.New(r.Locator)
    388 389   if err != nil {
    389 390   log.Warnf("unable to extract SPDX CPE=%q: %+v", r.Locator, err)
    390 391   continue
    391 392   }
    392  - cpes = append(cpes, cpe)
     393 + cpes = append(cpes, c)
    393 394   }
    394 395   }
    395 396   return cpes
    skipped 9 lines
  • ■ ■ ■ ■ ■ ■
    syft/formats/common/testutils/utils.go
    skipped 15 lines
    16 16   "github.com/anchore/stereoscope/pkg/image"
    17 17   "github.com/anchore/stereoscope/pkg/imagetest"
    18 18   "github.com/anchore/syft/syft/artifact"
     19 + "github.com/anchore/syft/syft/cpe"
    19 20   "github.com/anchore/syft/syft/linux"
    20 21   "github.com/anchore/syft/syft/pkg"
    21 22   "github.com/anchore/syft/syft/sbom"
    skipped 157 lines
    179 180   Version: "1.0.1",
    180 181   },
    181 182   PURL: "a-purl-1", // intentionally a bad pURL for test fixtures
    182  - CPEs: []pkg.CPE{
    183  - pkg.MustCPE("cpe:2.3:*:some:package:1:*:*:*:*:*:*:*"),
     183 + CPEs: []cpe.CPE{
     184 + cpe.Must("cpe:2.3:*:some:package:1:*:*:*:*:*:*:*"),
    184 185   },
    185 186   })
    186 187   catalog.Add(pkg.Package{
    skipped 10 lines
    197 198   Version: "2.0.1",
    198 199   },
    199 200   PURL: "pkg:deb/debian/[email protected]",
    200  - CPEs: []pkg.CPE{
    201  - pkg.MustCPE("cpe:2.3:*:some:package:2:*:*:*:*:*:*:*"),
     201 + CPEs: []cpe.CPE{
     202 + cpe.Must("cpe:2.3:*:some:package:2:*:*:*:*:*:*:*"),
    202 203   },
    203 204   })
    204 205  }
    skipped 54 lines
    259 260   },
    260 261   },
    261 262   PURL: "a-purl-2", // intentionally a bad pURL for test fixtures
    262  - CPEs: []pkg.CPE{
    263  - pkg.MustCPE("cpe:2.3:*:some:package:2:*:*:*:*:*:*:*"),
     263 + CPEs: []cpe.CPE{
     264 + cpe.Must("cpe:2.3:*:some:package:2:*:*:*:*:*:*:*"),
    264 265   },
    265 266   })
    266 267   catalog.Add(pkg.Package{
    skipped 10 lines
    277 278   Version: "2.0.1",
    278 279   },
    279 280   PURL: "pkg:deb/debian/[email protected]",
    280  - CPEs: []pkg.CPE{
    281  - pkg.MustCPE("cpe:2.3:*:some:package:2:*:*:*:*:*:*:*"),
     281 + CPEs: []cpe.CPE{
     282 + cpe.Must("cpe:2.3:*:some:package:2:*:*:*:*:*:*:*"),
    282 283   },
    283 284   })
    284 285   
    skipped 25 lines
  • ■ ■ ■ ■ ■ ■
    syft/formats/syftjson/encoder_test.go
    skipped 4 lines
    5 5   "testing"
    6 6   
    7 7   "github.com/anchore/syft/syft/artifact"
     8 + "github.com/anchore/syft/syft/cpe"
    8 9   "github.com/anchore/syft/syft/file"
    9 10   "github.com/anchore/syft/syft/formats/common/testutils"
    10 11   "github.com/anchore/syft/syft/linux"
    skipped 48 lines
    59 60   Files: []pkg.PythonFileRecord{},
    60 61   },
    61 62   PURL: "a-purl-1",
    62  - CPEs: []pkg.CPE{
    63  - pkg.MustCPE("cpe:2.3:*:some:package:1:*:*:*:*:*:*:*"),
     63 + CPEs: []cpe.CPE{
     64 + cpe.Must("cpe:2.3:*:some:package:1:*:*:*:*:*:*:*"),
    64 65   },
    65 66   }
    66 67   
    skipped 16 lines
    83 84   Files: []pkg.DpkgFileRecord{},
    84 85   },
    85 86   PURL: "a-purl-2",
    86  - CPEs: []pkg.CPE{
    87  - pkg.MustCPE("cpe:2.3:*:some:package:2:*:*:*:*:*:*:*"),
     87 + CPEs: []cpe.CPE{
     88 + cpe.Must("cpe:2.3:*:some:package:2:*:*:*:*:*:*:*"),
    88 89   },
    89 90   }
    90 91   
    skipped 117 lines
  • ■ ■ ■ ■ ■
    syft/formats/syftjson/to_format_model.go
    skipped 7 lines
    8 8   "github.com/anchore/syft/internal"
    9 9   "github.com/anchore/syft/internal/log"
    10 10   "github.com/anchore/syft/syft/artifact"
     11 + "github.com/anchore/syft/syft/cpe"
    11 12   "github.com/anchore/syft/syft/file"
    12 13   "github.com/anchore/syft/syft/formats/syftjson/model"
    13 14   "github.com/anchore/syft/syft/linux"
    skipped 145 lines
    159 160  func toPackageModel(p pkg.Package) model.Package {
    160 161   var cpes = make([]string, len(p.CPEs))
    161 162   for i, c := range p.CPEs {
    162  - cpes[i] = pkg.CPEString(c)
     163 + cpes[i] = cpe.String(c)
    163 164   }
    164 165   
    165 166   var licenses = make([]string, 0)
    skipped 86 lines
  • ■ ■ ■ ■ ■
    syft/formats/syftjson/to_syft_model.go
    skipped 6 lines
    7 7   
    8 8   "github.com/anchore/syft/internal/log"
    9 9   "github.com/anchore/syft/syft/artifact"
     10 + "github.com/anchore/syft/syft/cpe"
    10 11   "github.com/anchore/syft/syft/formats/syftjson/model"
    11 12   "github.com/anchore/syft/syft/linux"
    12 13   "github.com/anchore/syft/syft/pkg"
    skipped 161 lines
    174 175  }
    175 176   
    176 177  func toSyftPackage(p model.Package, idAliases map[string]string) pkg.Package {
    177  - var cpes []pkg.CPE
     178 + var cpes []cpe.CPE
    178 179   for _, c := range p.CPEs {
    179  - value, err := pkg.NewCPE(c)
     180 + value, err := cpe.New(c)
    180 181   if err != nil {
    181 182   log.Warnf("excluding invalid CPE %q: %v", c, err)
    182 183   continue
    skipped 38 lines
  • ■ ■ ■ ■ ■
    syft/pkg/catalog_test.go
    skipped 7 lines
    8 8   "github.com/stretchr/testify/require"
    9 9   
    10 10   "github.com/anchore/syft/syft/artifact"
     11 + "github.com/anchore/syft/syft/cpe"
    11 12   "github.com/anchore/syft/syft/source"
    12 13  )
    13 14   
    skipped 310 lines
    324 325   name: "multiple Locations with shared path",
    325 326   pkgs: []Package{
    326 327   {
    327  - CPEs: []CPE{MustCPE("cpe:2.3:a:package:1:1:*:*:*:*:*:*:*")},
     328 + CPEs: []cpe.CPE{cpe.Must("cpe:2.3:a:package:1:1:*:*:*:*:*:*:*")},
    328 329   Locations: source.NewLocationSet(
    329 330   source.Location{
    330 331   Coordinates: source.Coordinates{
    skipped 6 lines
    337 338   Type: RpmPkg,
    338 339   },
    339 340   {
    340  - CPEs: []CPE{MustCPE("cpe:2.3:b:package:1:1:*:*:*:*:*:*:*")},
     341 + CPEs: []cpe.CPE{cpe.Must("cpe:2.3:b:package:1:1:*:*:*:*:*:*:*")},
    341 342   Locations: source.NewLocationSet(
    342 343   source.Location{
    343 344   Coordinates: source.Coordinates{
    skipped 78 lines
  • ■ ■ ■ ■ ■ ■
    syft/pkg/cataloger/binary/classifier.go
    skipped 9 lines
    10 10   
    11 11   "github.com/anchore/packageurl-go"
    12 12   "github.com/anchore/syft/internal"
     13 + "github.com/anchore/syft/syft/cpe"
    13 14   "github.com/anchore/syft/syft/pkg"
    14 15   "github.com/anchore/syft/syft/pkg/cataloger/internal/unionreader"
    15 16   "github.com/anchore/syft/syft/source"
    skipped 28 lines
    44 45   PURL packageurl.PackageURL
    45 46   
    46 47   // CPEs are the specific CPEs we want to include for this binary with updated version information
    47  - CPEs []pkg.CPE
     48 + CPEs []cpe.CPE
    48 49  }
    49 50   
    50 51  // evidenceMatcher is a function called to catalog Packages that match some sort of evidence
    skipped 63 lines
    114 115   
    115 116   update := matchMetadata["update"]
    116 117   
    117  - var cpes []pkg.CPE
    118  - for _, cpe := range classifier.CPEs {
    119  - cpe.Version = version
    120  - cpe.Update = update
    121  - cpes = append(cpes, cpe)
     118 + var cpes []cpe.CPE
     119 + for _, c := range classifier.CPEs {
     120 + c.Version = version
     121 + c.Update = update
     122 + cpes = append(cpes, c)
    122 123   }
    123 124   
    124 125   p := pkg.Package{
    skipped 47 lines
    172 173  }
    173 174   
    174 175  // singleCPE returns a []pkg.CPE based on the cpe string or panics if the CPE is invalid
    175  -func singleCPE(cpe string) []pkg.CPE {
    176  - return []pkg.CPE{
    177  - pkg.MustCPE(cpe),
     176 +func singleCPE(cpeString string) []cpe.CPE {
     177 + return []cpe.CPE{
     178 + cpe.Must(cpeString),
    178 179   }
    179 180  }
    180 181   
  • ■ ■ ■ ■ ■ ■
    syft/pkg/cataloger/binary/classifier_test.go
    skipped 4 lines
    5 5   
    6 6   "github.com/stretchr/testify/require"
    7 7   
    8  - "github.com/anchore/syft/syft/pkg"
     8 + "github.com/anchore/syft/syft/cpe"
    9 9   "github.com/anchore/syft/syft/source"
    10 10  )
    11 11   
    skipped 11 lines
    23 23   Package: "some-app",
    24 24   FileGlob: ".*/version.txt",
    25 25   EvidenceMatcher: fileContentsVersionMatcher(`(?m)my-verison:(?P<version>[0-9.]+)`),
    26  - CPEs: []pkg.CPE{},
     26 + CPEs: []cpe.CPE{},
    27 27   },
    28 28   cpes: nil,
    29 29   },
    skipped 4 lines
    34 34   Package: "some-app",
    35 35   FileGlob: ".*/version.txt",
    36 36   EvidenceMatcher: fileContentsVersionMatcher(`(?m)my-verison:(?P<version>[0-9.]+)`),
    37  - CPEs: []pkg.CPE{
    38  - pkg.MustCPE("cpe:2.3:a:some:app:*:*:*:*:*:*:*:*"),
     37 + CPEs: []cpe.CPE{
     38 + cpe.Must("cpe:2.3:a:some:app:*:*:*:*:*:*:*:*"),
    39 39   },
    40 40   },
    41 41   cpes: []string{
    skipped 7 lines
    49 49   Package: "some-app",
    50 50   FileGlob: ".*/version.txt",
    51 51   EvidenceMatcher: fileContentsVersionMatcher(`(?m)my-verison:(?P<version>[0-9.]+)`),
    52  - CPEs: []pkg.CPE{
    53  - pkg.MustCPE("cpe:2.3:a:some:app:*:*:*:*:*:*:*:*"),
    54  - pkg.MustCPE("cpe:2.3:a:some:apps:*:*:*:*:*:*:*:*"),
     52 + CPEs: []cpe.CPE{
     53 + cpe.Must("cpe:2.3:a:some:app:*:*:*:*:*:*:*:*"),
     54 + cpe.Must("cpe:2.3:a:some:apps:*:*:*:*:*:*:*:*"),
    55 55   },
    56 56   },
    57 57   cpes: []string{
    skipped 21 lines
    79 79   
    80 80   var cpes []string
    81 81   for _, c := range p.CPEs {
    82  - cpes = append(cpes, pkg.CPEString(c))
     82 + cpes = append(cpes, cpe.String(c))
    83 83   }
    84 84   require.Equal(t, test.cpes, cpes)
    85 85   })
    skipped 3 lines
  • ■ ■ ■ ■ ■ ■
    syft/pkg/cataloger/common/cpe/filter.go
    skipped 4 lines
    5 5   
    6 6   "github.com/facebookincubator/nvdtools/wfn"
    7 7   
     8 + "github.com/anchore/syft/syft/cpe"
    8 9   "github.com/anchore/syft/syft/pkg"
    9 10  )
    10 11   
    11 12  const jenkinsName = "jenkins"
    12 13   
    13 14  // filterFn instances should return true if the given CPE should be removed from a collection for the given package
    14  -type filterFn func(cpe pkg.CPE, p pkg.Package) bool
     15 +type filterFn func(cpe cpe.CPE, p pkg.Package) bool
    15 16   
    16 17  var cpeFilters = []filterFn{
    17 18   disallowJiraClientServerMismatch,
    skipped 2 lines
    20 21   disallowNonParseableCPEs,
    21 22  }
    22 23   
    23  -func filter(cpes []pkg.CPE, p pkg.Package, filters ...filterFn) (result []pkg.CPE) {
     24 +func filter(cpes []cpe.CPE, p pkg.Package, filters ...filterFn) (result []cpe.CPE) {
    24 25  cpeLoop:
    25  - for _, cpe := range cpes {
     26 + for _, c := range cpes {
    26 27   for _, fn := range filters {
    27  - if fn(cpe, p) {
     28 + if fn(c, p) {
    28 29   continue cpeLoop
    29 30   }
    30 31   }
    31 32   // all filter functions passed on filtering this CPE
    32  - result = append(result, cpe)
     33 + result = append(result, c)
    33 34   }
    34 35   return result
    35 36  }
    36 37   
    37  -func disallowNonParseableCPEs(cpe pkg.CPE, _ pkg.Package) bool {
    38  - v := pkg.CPEString(cpe)
    39  - _, err := pkg.NewCPE(v)
     38 +func disallowNonParseableCPEs(c cpe.CPE, _ pkg.Package) bool {
     39 + v := cpe.String(c)
     40 + _, err := cpe.New(v)
    40 41   
    41 42   cannotParse := err != nil
    42 43   
    skipped 1 lines
    44 45  }
    45 46   
    46 47  // jenkins plugins should not match against jenkins
    47  -func disallowJenkinsServerCPEForPluginPackage(cpe pkg.CPE, p pkg.Package) bool {
     48 +func disallowJenkinsServerCPEForPluginPackage(cpe cpe.CPE, p pkg.Package) bool {
    48 49   if p.Type == pkg.JenkinsPluginPkg && cpe.Product == jenkinsName {
    49 50   return true
    50 51   }
    skipped 1 lines
    52 53  }
    53 54   
    54 55  // filter to account that packages that are not for jenkins but have a CPE generated that will match against jenkins
    55  -func disallowJenkinsCPEsNotAssociatedWithJenkins(cpe pkg.CPE, p pkg.Package) bool {
     56 +func disallowJenkinsCPEsNotAssociatedWithJenkins(cpe cpe.CPE, p pkg.Package) bool {
    56 57   // jenkins server should only match against a product with the name jenkins
    57 58   if cpe.Product == jenkinsName && !strings.Contains(strings.ToLower(p.Name), jenkinsName) {
    58 59   if cpe.Vendor == wfn.Any || cpe.Vendor == jenkinsName || cpe.Vendor == "cloudbees" {
    skipped 4 lines
    63 64  }
    64 65   
    65 66  // filter to account for packages which are jira client packages but have a CPE that will match against jira
    66  -func disallowJiraClientServerMismatch(cpe pkg.CPE, p pkg.Package) bool {
     67 +func disallowJiraClientServerMismatch(cpe cpe.CPE, p pkg.Package) bool {
    67 68   // jira / atlassian should not apply to clients
    68 69   if cpe.Product == "jira" && strings.Contains(strings.ToLower(p.Name), "client") {
    69 70   if cpe.Vendor == wfn.Any || cpe.Vendor == "jira" || cpe.Vendor == "atlassian" {
    skipped 6 lines
  • ■ ■ ■ ■ ■ ■
    syft/pkg/cataloger/common/cpe/filter_test.go
    skipped 4 lines
    5 5   
    6 6   "github.com/stretchr/testify/assert"
    7 7   
     8 + "github.com/anchore/syft/syft/cpe"
    8 9   "github.com/anchore/syft/syft/pkg"
    9 10  )
    10 11   
    11 12  func Test_disallowJenkinsServerCPEForPluginPackage(t *testing.T) {
    12 13   tests := []struct {
    13 14   name string
    14  - cpe pkg.CPE
     15 + cpe cpe.CPE
    15 16   pkg pkg.Package
    16 17   expected bool
    17 18   }{
    18 19   {
    19 20   name: "go case (filter out)",
    20  - cpe: pkg.MustCPE("cpe:2.3:a:name:jenkins:3.2:*:*:*:*:*:*:*"),
     21 + cpe: cpe.Must("cpe:2.3:a:name:jenkins:3.2:*:*:*:*:*:*:*"),
    21 22   pkg: pkg.Package{
    22 23   Type: pkg.JenkinsPluginPkg,
    23 24   },
    skipped 1 lines
    25 26   },
    26 27   {
    27 28   name: "ignore jenkins plugins with unique name",
    28  - cpe: pkg.MustCPE("cpe:2.3:a:name:ci-jenkins:3.2:*:*:*:*:*:*:*"),
     29 + cpe: cpe.Must("cpe:2.3:a:name:ci-jenkins:3.2:*:*:*:*:*:*:*"),
    29 30   pkg: pkg.Package{
    30 31   Type: pkg.JenkinsPluginPkg,
    31 32   },
    skipped 1 lines
    33 34   },
    34 35   {
    35 36   name: "ignore java packages",
    36  - cpe: pkg.MustCPE("cpe:2.3:a:name:jenkins:3.2:*:*:*:*:*:*:*"),
     37 + cpe: cpe.Must("cpe:2.3:a:name:jenkins:3.2:*:*:*:*:*:*:*"),
    37 38   pkg: pkg.Package{
    38 39   Type: pkg.JavaPkg,
    39 40   },
    skipped 10 lines
    50 51  func Test_disallowJenkinsCPEsNotAssociatedWithJenkins(t *testing.T) {
    51 52   tests := []struct {
    52 53   name string
    53  - cpe pkg.CPE
     54 + cpe cpe.CPE
    54 55   pkg pkg.Package
    55 56   expected bool
    56 57   }{
    57 58   {
    58 59   name: "filter out mismatched name (cloudbees vendor)",
    59  - cpe: pkg.MustCPE("cpe:2.3:a:cloudbees:jenkins:3.2:*:*:*:*:*:*:*"),
     60 + cpe: cpe.Must("cpe:2.3:a:cloudbees:jenkins:3.2:*:*:*:*:*:*:*"),
    60 61   pkg: pkg.Package{
    61 62   Name: "not-j*nkins",
    62 63   Type: pkg.JavaPkg,
    skipped 2 lines
    65 66   },
    66 67   {
    67 68   name: "filter out mismatched name (jenkins vendor)",
    68  - cpe: pkg.MustCPE("cpe:2.3:a:jenkins:jenkins:3.2:*:*:*:*:*:*:*"),
     69 + cpe: cpe.Must("cpe:2.3:a:jenkins:jenkins:3.2:*:*:*:*:*:*:*"),
    69 70   pkg: pkg.Package{
    70 71   Name: "not-j*nkins",
    71 72   Type: pkg.JavaPkg,
    skipped 2 lines
    74 75   },
    75 76   {
    76 77   name: "filter out mismatched name (any vendor)",
    77  - cpe: pkg.MustCPE("cpe:2.3:a:*:jenkins:3.2:*:*:*:*:*:*:*"),
     78 + cpe: cpe.Must("cpe:2.3:a:*:jenkins:3.2:*:*:*:*:*:*:*"),
    78 79   pkg: pkg.Package{
    79 80   Name: "not-j*nkins",
    80 81   Type: pkg.JavaPkg,
    skipped 2 lines
    83 84   },
    84 85   {
    85 86   name: "ignore packages with the name jenkins",
    86  - cpe: pkg.MustCPE("cpe:2.3:a:*:jenkins:3.2:*:*:*:*:*:*:*"),
     87 + cpe: cpe.Must("cpe:2.3:a:*:jenkins:3.2:*:*:*:*:*:*:*"),
    87 88   pkg: pkg.Package{
    88 89   Name: "jenkins-thing",
    89 90   Type: pkg.JavaPkg,
    skipped 2 lines
    92 93   },
    93 94   {
    94 95   name: "ignore product names that are not exactly 'jenkins'",
    95  - cpe: pkg.MustCPE("cpe:2.3:a:*:jenkins-something-else:3.2:*:*:*:*:*:*:*"),
     96 + cpe: cpe.Must("cpe:2.3:a:*:jenkins-something-else:3.2:*:*:*:*:*:*:*"),
    96 97   pkg: pkg.Package{
    97 98   Name: "not-j*nkins",
    98 99   Type: pkg.JavaPkg,
    skipped 11 lines
    110 111  func Test_disallowJiraClientServerMismatch(t *testing.T) {
    111 112   tests := []struct {
    112 113   name string
    113  - cpe pkg.CPE
     114 + cpe cpe.CPE
    114 115   pkg pkg.Package
    115 116   expected bool
    116 117   }{
    117 118   {
    118 119   name: "filter out mismatched name (atlassian vendor)",
    119  - cpe: pkg.MustCPE("cpe:2.3:a:atlassian:jira:3.2:*:*:*:*:*:*:*"),
     120 + cpe: cpe.Must("cpe:2.3:a:atlassian:jira:3.2:*:*:*:*:*:*:*"),
    120 121   pkg: pkg.Package{
    121 122   Name: "something-client",
    122 123   Type: pkg.JavaPkg,
    skipped 2 lines
    125 126   },
    126 127   {
    127 128   name: "filter out mismatched name (jira vendor)",
    128  - cpe: pkg.MustCPE("cpe:2.3:a:jira:jira:3.2:*:*:*:*:*:*:*"),
     129 + cpe: cpe.Must("cpe:2.3:a:jira:jira:3.2:*:*:*:*:*:*:*"),
    129 130   pkg: pkg.Package{
    130 131   Name: "something-client",
    131 132   Type: pkg.JavaPkg,
    skipped 2 lines
    134 135   },
    135 136   {
    136 137   name: "filter out mismatched name (any vendor)",
    137  - cpe: pkg.MustCPE("cpe:2.3:a:*:jira:3.2:*:*:*:*:*:*:*"),
     138 + cpe: cpe.Must("cpe:2.3:a:*:jira:3.2:*:*:*:*:*:*:*"),
    138 139   pkg: pkg.Package{
    139 140   Name: "something-client",
    140 141   Type: pkg.JavaPkg,
    skipped 2 lines
    143 144   },
    144 145   {
    145 146   name: "ignore package names that do not have 'client'",
    146  - cpe: pkg.MustCPE("cpe:2.3:a:*:jira:3.2:*:*:*:*:*:*:*"),
     147 + cpe: cpe.Must("cpe:2.3:a:*:jira:3.2:*:*:*:*:*:*:*"),
    147 148   pkg: pkg.Package{
    148 149   Name: "jira-thing",
    149 150   Type: pkg.JavaPkg,
    skipped 2 lines
    152 153   },
    153 154   {
    154 155   name: "ignore product names that are not exactly 'jira'",
    155  - cpe: pkg.MustCPE("cpe:2.3:a:*:jira-something-else:3.2:*:*:*:*:*:*:*"),
     156 + cpe: cpe.Must("cpe:2.3:a:*:jira-something-else:3.2:*:*:*:*:*:*:*"),
    156 157   pkg: pkg.Package{
    157 158   Name: "not-j*ra",
    158 159   Type: pkg.JavaPkg,
    skipped 11 lines
  • ■ ■ ■ ■ ■ ■
    syft/pkg/cataloger/common/cpe/generate.go
    skipped 9 lines
    10 10   "github.com/facebookincubator/nvdtools/wfn"
    11 11   
    12 12   "github.com/anchore/syft/internal"
     13 + "github.com/anchore/syft/syft/cpe"
    13 14   "github.com/anchore/syft/syft/pkg"
    14 15  )
    15 16   
    16 17  func newCPE(product, vendor, version, targetSW string) *wfn.Attributes {
    17  - cpe := *(wfn.NewAttributesWithAny())
    18  - cpe.Part = "a"
    19  - cpe.Product = product
    20  - cpe.Vendor = vendor
    21  - cpe.Version = version
    22  - cpe.TargetSW = targetSW
    23  - if pkg.ValidateCPEString(pkg.CPEString(cpe)) != nil {
     18 + c := *(wfn.NewAttributesWithAny())
     19 + c.Part = "a"
     20 + c.Product = product
     21 + c.Vendor = vendor
     22 + c.Version = version
     23 + c.TargetSW = targetSW
     24 + if cpe.ValidateString(cpe.String(c)) != nil {
    24 25   return nil
    25 26   }
    26  - return &cpe
     27 + return &c
    27 28  }
    28 29   
    29 30  // Generate Create a list of CPEs for a given package, trying to guess the vendor, product tuple. We should be trying to
    30 31  // generate the minimal set of representative CPEs, which implies that optional fields should not be included
    31 32  // (such as target SW).
    32  -func Generate(p pkg.Package) []pkg.CPE {
     33 +func Generate(p pkg.Package) []cpe.CPE {
    33 34   vendors := candidateVendors(p)
    34 35   products := candidateProducts(p)
    35 36   if len(products) == 0 {
    skipped 1 lines
    37 38   }
    38 39   
    39 40   keys := internal.NewStringSet()
    40  - cpes := make([]pkg.CPE, 0)
     41 + cpes := make([]cpe.CPE, 0)
    41 42   for _, product := range products {
    42 43   for _, vendor := range vendors {
    43 44   // prevent duplicate entries...
    skipped 3 lines
    47 48   }
    48 49   keys.Add(key)
    49 50   // add a new entry...
    50  - if cpe := newCPE(product, vendor, p.Version, wfn.Any); cpe != nil {
    51  - cpes = append(cpes, *cpe)
     51 + if c := newCPE(product, vendor, p.Version, wfn.Any); c != nil {
     52 + cpes = append(cpes, *c)
    52 53   }
    53 54   }
    54 55   }
    skipped 1 lines
    56 57   // filter out any known combinations that don't accurately represent this package
    57 58   cpes = filter(cpes, p, cpeFilters...)
    58 59   
    59  - sort.Sort(pkg.CPEBySpecificity(cpes))
     60 + sort.Sort(cpe.BySpecificity(cpes))
    60 61   
    61 62   return cpes
    62 63  }
    skipped 190 lines
  • ■ ■ ■ ■ ■
    syft/pkg/cataloger/common/cpe/generate_test.go
    skipped 9 lines
    10 10   "github.com/scylladb/go-set/strset"
    11 11   "github.com/stretchr/testify/assert"
    12 12   
     13 + "github.com/anchore/syft/syft/cpe"
    13 14   "github.com/anchore/syft/syft/pkg"
    14 15  )
    15 16   
    skipped 680 lines
    696 697   expectedCpeSet := set.NewStringSet(test.expected...)
    697 698   actualCpeSet := set.NewStringSet()
    698 699   for _, a := range actual {
    699  - actualCpeSet.Add(pkg.CPEString(a))
     700 + actualCpeSet.Add(cpe.String(a))
    700 701   }
    701 702   
    702 703   extra := strset.Difference(actualCpeSet, expectedCpeSet).List()
    skipped 228 lines
  • ■ ■ ■ ■ ■ ■
    syft/pkg/cataloger/sbom/cataloger_test.go
    skipped 5 lines
    6 6   "github.com/stretchr/testify/require"
    7 7   
    8 8   "github.com/anchore/syft/syft/artifact"
     9 + "github.com/anchore/syft/syft/cpe"
    9 10   "github.com/anchore/syft/syft/formats/syftjson"
    10 11   "github.com/anchore/syft/syft/pkg"
    11 12   "github.com/anchore/syft/syft/pkg/cataloger/internal/pkgtest"
    skipped 1 lines
    13 14   "github.com/anchore/syft/syft/source"
    14 15  )
    15 16   
    16  -func mustCPEs(s ...string) (c []pkg.CPE) {
     17 +func mustCPEs(s ...string) (c []cpe.CPE) {
    17 18   for _, i := range s {
    18 19   c = append(c, mustCPE(i))
    19 20   }
    20 21   return
    21 22  }
    22 23   
    23  -func mustCPE(c string) pkg.CPE {
    24  - return must(pkg.NewCPE(c))
     24 +func mustCPE(c string) cpe.CPE {
     25 + return must(cpe.New(c))
    25 26  }
    26  -func must(c pkg.CPE, e error) pkg.CPE {
     27 +func must(c cpe.CPE, e error) cpe.CPE {
    27 28   if e != nil {
    28 29   panic(e)
    29 30   }
    skipped 263 lines
  • ■ ■ ■ ■ ■ ■
    syft/pkg/cpe_by_specificity_test.go
    1  -package pkg
    2  - 
    3  -import (
    4  - "sort"
    5  - "testing"
    6  - 
    7  - "github.com/stretchr/testify/assert"
    8  -)
    9  - 
    10  -func mustCPE(c string) CPE {
    11  - return must(NewCPE(c))
    12  -}
    13  - 
    14  -func TestCPESpecificity(t *testing.T) {
    15  - tests := []struct {
    16  - name string
    17  - input []CPE
    18  - expected []CPE
    19  - }{
    20  - {
    21  - name: "sort strictly by wfn *",
    22  - input: []CPE{
    23  - mustCPE("cpe:2.3:a:*:package:1:*:*:*:*:*:*:*"),
    24  - mustCPE("cpe:2.3:a:some:package:1:*:*:*:*:*:*:*"),
    25  - mustCPE("cpe:2.3:a:*:package:1:*:*:*:*:some:*:*"),
    26  - mustCPE("cpe:2.3:a:some:package:1:*:*:*:*:some:*:*"),
    27  - mustCPE("cpe:2.3:a:some:package:*:*:*:*:*:*:*:*"),
    28  - },
    29  - expected: []CPE{
    30  - mustCPE("cpe:2.3:a:some:package:1:*:*:*:*:some:*:*"),
    31  - mustCPE("cpe:2.3:a:some:package:1:*:*:*:*:*:*:*"),
    32  - mustCPE("cpe:2.3:a:some:package:*:*:*:*:*:*:*:*"),
    33  - mustCPE("cpe:2.3:a:*:package:1:*:*:*:*:some:*:*"),
    34  - mustCPE("cpe:2.3:a:*:package:1:*:*:*:*:*:*:*"),
    35  - },
    36  - },
    37  - {
    38  - name: "sort strictly by field length",
    39  - input: []CPE{
    40  - mustCPE("cpe:2.3:a:1:22:1:*:*:*:*:1:*:*"),
    41  - mustCPE("cpe:2.3:a:55555:1:1:*:*:*:*:1:*:*"),
    42  - mustCPE("cpe:2.3:a:1:1:333:*:*:*:*:1:*:*"),
    43  - mustCPE("cpe:2.3:a:1:666666:1:*:*:*:*:1:*:*"),
    44  - mustCPE("cpe:2.3:a:1:1:1:*:*:*:*:1:*:*"),
    45  - mustCPE("cpe:2.3:a:1:1:1:*:*:*:*:4444:*:*"),
    46  - },
    47  - expected: []CPE{
    48  - mustCPE("cpe:2.3:a:1:666666:1:*:*:*:*:1:*:*"),
    49  - mustCPE("cpe:2.3:a:55555:1:1:*:*:*:*:1:*:*"),
    50  - mustCPE("cpe:2.3:a:1:1:1:*:*:*:*:4444:*:*"),
    51  - mustCPE("cpe:2.3:a:1:1:333:*:*:*:*:1:*:*"),
    52  - mustCPE("cpe:2.3:a:1:22:1:*:*:*:*:1:*:*"),
    53  - mustCPE("cpe:2.3:a:1:1:1:*:*:*:*:1:*:*"),
    54  - },
    55  - },
    56  - {
    57  - name: "sort by mix of field length and specificity",
    58  - input: []CPE{
    59  - mustCPE("cpe:2.3:a:1:666666:*:*:*:*:*:1:*:*"),
    60  - mustCPE("cpe:2.3:a:*:1:1:*:*:*:*:4444:*:*"),
    61  - mustCPE("cpe:2.3:a:1:*:333:*:*:*:*:*:*:*"),
    62  - mustCPE("cpe:2.3:a:1:1:1:*:*:*:*:1:*:*"),
    63  - mustCPE("cpe:2.3:a:1:22:1:*:*:*:*:1:*:*"),
    64  - mustCPE("cpe:2.3:a:55555:1:1:*:*:*:*:1:*:*"),
    65  - },
    66  - expected: []CPE{
    67  - mustCPE("cpe:2.3:a:55555:1:1:*:*:*:*:1:*:*"),
    68  - mustCPE("cpe:2.3:a:1:22:1:*:*:*:*:1:*:*"),
    69  - mustCPE("cpe:2.3:a:1:1:1:*:*:*:*:1:*:*"),
    70  - mustCPE("cpe:2.3:a:1:666666:*:*:*:*:*:1:*:*"),
    71  - mustCPE("cpe:2.3:a:*:1:1:*:*:*:*:4444:*:*"),
    72  - mustCPE("cpe:2.3:a:1:*:333:*:*:*:*:*:*:*"),
    73  - },
    74  - },
    75  - {
    76  - name: "sort by mix of field length, specificity, dash",
    77  - input: []CPE{
    78  - mustCPE("cpe:2.3:a:alpine:alpine_keys:2.3-r1:*:*:*:*:*:*:*"),
    79  - mustCPE("cpe:2.3:a:alpine_keys:alpine_keys:2.3-r1:*:*:*:*:*:*:*"),
    80  - mustCPE("cpe:2.3:a:alpine-keys:alpine_keys:2.3-r1:*:*:*:*:*:*:*"),
    81  - mustCPE("cpe:2.3:a:alpine:alpine-keys:2.3-r1:*:*:*:*:*:*:*"),
    82  - mustCPE("cpe:2.3:a:alpine-keys:alpine-keys:2.3-r1:*:*:*:*:*:*:*"),
    83  - mustCPE("cpe:2.3:a:alpine_keys:alpine-keys:2.3-r1:*:*:*:*:*:*:*"),
    84  - },
    85  - expected: []CPE{
    86  - mustCPE("cpe:2.3:a:alpine-keys:alpine-keys:2.3-r1:*:*:*:*:*:*:*"),
    87  - mustCPE("cpe:2.3:a:alpine-keys:alpine_keys:2.3-r1:*:*:*:*:*:*:*"),
    88  - mustCPE("cpe:2.3:a:alpine_keys:alpine-keys:2.3-r1:*:*:*:*:*:*:*"),
    89  - mustCPE("cpe:2.3:a:alpine_keys:alpine_keys:2.3-r1:*:*:*:*:*:*:*"),
    90  - mustCPE("cpe:2.3:a:alpine:alpine-keys:2.3-r1:*:*:*:*:*:*:*"),
    91  - mustCPE("cpe:2.3:a:alpine:alpine_keys:2.3-r1:*:*:*:*:*:*:*"),
    92  - },
    93  - },
    94  - }
    95  - 
    96  - for _, test := range tests {
    97  - t.Run(test.name, func(t *testing.T) {
    98  - sort.Sort(CPEBySpecificity(test.input))
    99  - assert.Equal(t, test.expected, test.input)
    100  - })
    101  - }
    102  - 
    103  -}
    104  - 
  • ■ ■ ■ ■ ■
    syft/pkg/package.go
    skipped 9 lines
    10 10   
    11 11   "github.com/anchore/syft/internal/log"
    12 12   "github.com/anchore/syft/syft/artifact"
     13 + "github.com/anchore/syft/syft/cpe"
    13 14   "github.com/anchore/syft/syft/source"
    14 15  )
    15 16   
    skipped 8 lines
    24 25   Licenses []string // licenses discovered with the package metadata
    25 26   Language Language `hash:"ignore" cyclonedx:"language"` // the language ecosystem this package belongs to (e.g. JavaScript, Python, etc)
    26 27   Type Type `cyclonedx:"type"` // the package type (e.g. Npm, Yarn, Python, Rpm, Deb, etc)
    27  - CPEs []CPE `hash:"ignore"` // all possible Common Platform Enumerators (note: this is NOT included in the definition of the ID since all fields on a CPE are derived from other fields)
     28 + CPEs []cpe.CPE `hash:"ignore"` // all possible Common Platform Enumerators (note: this is NOT included in the definition of the ID since all fields on a CPE are derived from other fields)
    28 29   PURL string `hash:"ignore"` // the Package URL (see https://github.com/package-url/purl-spec)
    29 30   MetadataType MetadataType `cyclonedx:"metadataType"` // the shape of the additional data in the "metadata" field
    30 31   Metadata interface{} // additional data found while parsing the package source
    skipped 33 lines
    64 65   
    65 66   p.Locations.Add(other.Locations.ToSlice()...)
    66 67   
    67  - p.CPEs = mergeCPEs(p.CPEs, other.CPEs)
     68 + p.CPEs = cpe.Merge(p.CPEs, other.CPEs)
    68 69   
    69 70   if p.PURL == "" {
    70 71   p.PURL = other.PURL
    skipped 56 lines
  • ■ ■ ■ ■ ■ ■
    syft/pkg/package_test.go
    skipped 7 lines
    8 8   "github.com/stretchr/testify/require"
    9 9   
    10 10   "github.com/anchore/stereoscope/pkg/file"
     11 + "github.com/anchore/syft/syft/cpe"
    11 12   "github.com/anchore/syft/syft/source"
    12 13  )
    13 14   
    skipped 18 lines
    32 33   },
    33 34   Language: "math",
    34 35   Type: PythonPkg,
    35  - CPEs: []CPE{
    36  - must(NewCPE(`cpe:2.3:a:Archimedes:pi:3.14:*:*:*:*:math:*:*`)),
     36 + CPEs: []cpe.CPE{
     37 + cpe.Must(`cpe:2.3:a:Archimedes:pi:3.14:*:*:*:*:math:*:*`),
    37 38   },
    38 39   PURL: "pkg:pypi/[email protected]",
    39 40   MetadataType: PythonPackageMetadataType,
    skipped 129 lines
    169 170   {
    170 171   name: "CPEs is ignored",
    171 172   transform: func(pkg Package) Package {
    172  - pkg.CPEs = []CPE{}
     173 + pkg.CPEs = []cpe.CPE{}
    173 174   return pkg
    174 175   },
    175 176   expectedIDComparison: assert.Equal,
    skipped 93 lines
    269 270   },
    270 271   Language: "math",
    271 272   Type: PythonPkg,
    272  - CPEs: []CPE{
    273  - must(NewCPE(`cpe:2.3:a:Archimedes:pi:3.14:*:*:*:*:math:*:*`)),
     273 + CPEs: []cpe.CPE{
     274 + cpe.Must(`cpe:2.3:a:Archimedes:pi:3.14:*:*:*:*:math:*:*`),
    274 275   },
    275 276   PURL: "pkg:pypi/[email protected]",
    276 277   MetadataType: PythonPackageMetadataType,
    skipped 20 lines
    297 298   },
    298 299   Language: "math",
    299 300   Type: PythonPkg,
    300  - CPEs: []CPE{
    301  - must(NewCPE(`cpe:2.3:a:DIFFERENT:pi:3.14:*:*:*:*:math:*:*`)), // NOTE: difference
     301 + CPEs: []cpe.CPE{
     302 + cpe.Must(`cpe:2.3:a:DIFFERENT:pi:3.14:*:*:*:*:math:*:*`), // NOTE: difference
    302 303   },
    303 304   PURL: "pkg:pypi/[email protected]",
    304 305   MetadataType: PythonPackageMetadataType,
    skipped 21 lines
    326 327   },
    327 328   Language: "math",
    328 329   Type: PythonPkg,
    329  - CPEs: []CPE{
    330  - must(NewCPE(`cpe:2.3:a:Archimedes:pi:3.14:*:*:*:*:math:*:*`)),
    331  - must(NewCPE(`cpe:2.3:a:DIFFERENT:pi:3.14:*:*:*:*:math:*:*`)), // NOTE: merge!
     330 + CPEs: []cpe.CPE{
     331 + cpe.Must(`cpe:2.3:a:Archimedes:pi:3.14:*:*:*:*:math:*:*`),
     332 + cpe.Must(`cpe:2.3:a:DIFFERENT:pi:3.14:*:*:*:*:math:*:*`), // NOTE: merge!
    332 333   },
    333 334   PURL: "pkg:pypi/[email protected]",
    334 335   MetadataType: PythonPackageMetadataType,
    skipped 23 lines
    358 359   },
    359 360   Language: "math",
    360 361   Type: PythonPkg,
    361  - CPEs: []CPE{
    362  - must(NewCPE(`cpe:2.3:a:Archimedes:pi:3.14:*:*:*:*:math:*:*`)),
     362 + CPEs: []cpe.CPE{
     363 + cpe.Must(`cpe:2.3:a:Archimedes:pi:3.14:*:*:*:*:math:*:*`),
    363 364   },
    364 365   PURL: "pkg:pypi/[email protected]",
    365 366   MetadataType: PythonPackageMetadataType,
    skipped 20 lines
    386 387   },
    387 388   Language: "math",
    388 389   Type: PythonPkg,
    389  - CPEs: []CPE{
    390  - must(NewCPE(`cpe:2.3:a:Archimedes:pi:3.14:*:*:*:*:math:*:*`)),
     390 + CPEs: []cpe.CPE{
     391 + cpe.Must(`cpe:2.3:a:Archimedes:pi:3.14:*:*:*:*:math:*:*`),
    391 392   },
    392 393   PURL: "pkg:pypi/[email protected]",
    393 394   MetadataType: PythonPackageMetadataType,
    skipped 73 lines
Please wait...
Page is in error, reload to recover