Skip to content

Commit ff04129

Browse files
authored
feat: add vulnerability count to matched packages, enabled via flag --show-vuln-count (#507)
Signed-off-by: Rafael Mestre <rafael@herodevs.com>
1 parent 39c6a07 commit ff04129

File tree

15 files changed

+96
-25
lines changed

15 files changed

+96
-25
lines changed

cmd/xeol/cli/commands/root.go

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -244,12 +244,13 @@ func runXeol(app clio.Application, opts *options.Xeol, userInput string) error {
244244
}
245245

246246
if err := writer.Write(models.PresenterConfig{
247-
Matches: allMatches,
248-
Packages: packages,
249-
Context: pkgContext,
250-
SBOM: s,
251-
AppConfig: opts,
252-
DBStatus: status,
247+
Matches: allMatches,
248+
Packages: packages,
249+
Context: pkgContext,
250+
SBOM: s,
251+
AppConfig: opts,
252+
ShowVulnCount: opts.ShowVulnCount,
253+
DBStatus: status,
253254
}); err != nil {
254255
errs <- err
255256
}

cmd/xeol/cli/options/xeol.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ type Xeol struct {
3333
Registry registry `yaml:"registry" json:"registry" mapstructure:"registry"`
3434
Name string `yaml:"name" json:"name" mapstructure:"name"`
3535
DefaultImagePullSource string `yaml:"default-image-pull-source" json:"default-image-pull-source" mapstructure:"default-image-pull-source"`
36+
ShowVulnCount bool `yaml:"show-vuln-count" json:"show-vuln-count" mapstructure:"show-vuln-count"`
3637
}
3738

3839
var _ interface {
@@ -53,6 +54,7 @@ func DefaultXeol(id clio.Identification) *Xeol {
5354
ProjectName: project,
5455
CommitHash: commit,
5556
ImagePath: "Dockerfile",
57+
ShowVulnCount: false,
5658
}
5759
return config
5860
}
@@ -123,6 +125,11 @@ func (o *Xeol) AddFlags(flags clio.FlagSet) {
123125
"platform", "",
124126
"an optional platform specifier for container image sources (e.g. 'linux/arm64', 'linux/arm64/v8', 'arm64', 'linux')",
125127
)
128+
129+
flags.BoolVarP(&o.ShowVulnCount,
130+
"show-vuln-count", "",
131+
"show the number of vulnerabilities found for each package (default is false)",
132+
)
126133
}
127134

128135
func (o *Xeol) parseLookaheadOption() (err error) {

test/integration/db_mock_test.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ func (s *mockStore) GetCyclesByCpe(cpe string) ([]xeolDB.Cycle, error) {
1919
return s.backend[cpe], nil
2020
}
2121

22+
func (s *mockStore) GetVulnCountByPurlAndVersion(purl string, version string) (int, error) {
23+
return 0, nil
24+
}
25+
2226
func (s *mockStore) GetAllProducts() (*[]xeolDB.Product, error) {
2327
return nil, nil
2428
}

xeol/db/eol_provider.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,3 +83,17 @@ func (pr *EolProvider) GetByPackagePurl(p pkg.Package) ([]eol.Cycle, error) {
8383

8484
return cycles, nil
8585
}
86+
87+
func (pr *EolProvider) GetVulnCount(p pkg.Package) (int, error) {
88+
shortPurl, err := purl.ShortPurl(p)
89+
if err != nil {
90+
return 0, err
91+
}
92+
93+
vulnCount, err := pr.reader.GetVulnCountByPurlAndVersion(shortPurl, p.Version)
94+
if err != nil {
95+
return 0, err
96+
}
97+
98+
return vulnCount, nil
99+
}

xeol/db/v1/eol.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ type EolStore interface {
3636
type EolStoreReader interface {
3737
GetCyclesByPurl(purl string) ([]Cycle, error)
3838
GetCyclesByCpe(cpe string) ([]Cycle, error)
39+
GetVulnCountByPurlAndVersion(purl string, version string) (int, error)
3940
GetAllProducts() (*[]Product, error)
4041
}
4142

xeol/db/v1/store/store.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,3 +143,14 @@ func (s *store) GetCyclesByPurl(purl string) ([]v1.Cycle, error) {
143143
}
144144
return cycles, nil
145145
}
146+
147+
func (s *store) GetVulnCountByPurlAndVersion(purl string, version string) (int, error) {
148+
var vulnCount int
149+
if result := s.db.Table("vulns").
150+
Select("vulns.issue_count").
151+
Joins("JOIN purls ON vulns.product_id = purls.product_id").
152+
Where("purls.purl = ? AND vulns.version = ?", purl, version).Find(&vulnCount); result.Error != nil {
153+
return 0, result.Error
154+
}
155+
return vulnCount, nil
156+
}

xeol/eol/provider.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ type Provider interface {
1313

1414
type ProviderByPackagePurl interface {
1515
GetByPackagePurl(p pkg.Package) ([]Cycle, error)
16+
GetVulnCount(p pkg.Package) (int, error)
1617
}
1718

1819
type ProviderByDistroCpe interface {

xeol/match/fingerprint.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ type Fingerprint struct {
1313
eolDate string
1414
eolBool bool
1515
lts string
16+
version string
1617
}
1718

1819
func (m Fingerprint) String() string {

xeol/match/match.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,9 @@ var ErrCannotMerge = fmt.Errorf("unable to merge eol matches")
1111

1212
// Match represents a finding in the eol matching process, pairing a single package and a single eol object.
1313
type Match struct {
14-
Cycle eol.Cycle
15-
Package pkg.Package // The package used to search for a match.
14+
Cycle eol.Cycle
15+
Package pkg.Package // The package used to search for a match.
16+
VulnCount int
1617
}
1718

1819
// String is the string representation of select match fields.
@@ -32,6 +33,7 @@ func (m Match) Fingerprint() Fingerprint {
3233
eolDate: m.Cycle.Eol,
3334
eolBool: m.Cycle.EolBool,
3435
lts: m.Cycle.LTS,
36+
version: m.Package.Version,
3537
}
3638
}
3739

xeol/matcher/distro/matcher_test.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@ func (s *mockStore) GetCyclesByCpe(cpe string) ([]xeolDB.Cycle, error) {
2929
return s.backend[cpe], nil
3030
}
3131

32+
func (s *mockStore) GetVulnCountByPurlAndVersion(purl string, version string) (int, error) {
33+
return 0, nil
34+
}
35+
3236
func (s *mockStore) GetAllProducts() (*[]xeolDB.Product, error) {
3337
return nil, nil
3438
}

0 commit comments

Comments
 (0)