mirror of
https://github.com/anchore/syft.git
synced 2025-11-18 17:03:17 +01:00
Fix: Include version information in binary cataloger CPEs (#1310)
This commit is contained in:
parent
10464642e9
commit
3e99c4d7d8
@ -7,6 +7,7 @@ import (
|
|||||||
"regexp"
|
"regexp"
|
||||||
|
|
||||||
"github.com/anchore/syft/internal"
|
"github.com/anchore/syft/internal"
|
||||||
|
"github.com/anchore/syft/internal/log"
|
||||||
"github.com/anchore/syft/syft/artifact"
|
"github.com/anchore/syft/syft/artifact"
|
||||||
"github.com/anchore/syft/syft/file"
|
"github.com/anchore/syft/syft/file"
|
||||||
"github.com/anchore/syft/syft/pkg"
|
"github.com/anchore/syft/syft/pkg"
|
||||||
@ -22,10 +23,10 @@ type Classifier struct {
|
|||||||
// source location. If any of the patterns match, the file will be considered a candidate for parsing.
|
// source location. If any of the patterns match, the file will be considered a candidate for parsing.
|
||||||
// If no patterns are provided, the reader is automatically considered a candidate.
|
// If no patterns are provided, the reader is automatically considered a candidate.
|
||||||
FilepathPatterns []*regexp.Regexp
|
FilepathPatterns []*regexp.Regexp
|
||||||
// EvidencePattern is a list of regular expressions that will be used to match against the file contents of a
|
// EvidencePatterns is a list of regular expressions that will be used to match against the file contents of a
|
||||||
// given file in the source location. If any of the patterns match, the file will be considered a candidate for parsing.
|
// given file in the source location. If any of the patterns match, the file will be considered a candidate for parsing.
|
||||||
EvidencePatterns []*regexp.Regexp
|
EvidencePatterns []*regexp.Regexp
|
||||||
// CPE is the CPE we want to match against
|
// CPEs are the specific CPEs we want to include for this binary with updated version information
|
||||||
CPEs []pkg.CPE
|
CPEs []pkg.CPE
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,20 +46,33 @@ func (c Classifier) Examine(reader source.LocationReadCloser) (p *pkg.Package, r
|
|||||||
}
|
}
|
||||||
|
|
||||||
var classifiedPackage *pkg.Package
|
var classifiedPackage *pkg.Package
|
||||||
for _, patternTemplate := range c.EvidencePatterns {
|
for _, evidencePattern := range c.EvidencePatterns {
|
||||||
if !patternTemplate.Match(contents) {
|
if !evidencePattern.Match(contents) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
matchMetadata := internal.MatchNamedCaptureGroups(patternTemplate, string(contents))
|
matchMetadata := internal.MatchNamedCaptureGroups(evidencePattern, string(contents))
|
||||||
if classifiedPackage == nil {
|
version, ok := matchMetadata["version"]
|
||||||
|
if !ok {
|
||||||
|
log.Debugf("no version found in binary from pattern %v", evidencePattern)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
var cpes []pkg.CPE
|
||||||
|
for _, cpe := range c.CPEs {
|
||||||
|
cpe.Version = version
|
||||||
|
if err == nil {
|
||||||
|
cpes = append(cpes, cpe)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
classifiedPackage = &pkg.Package{
|
classifiedPackage = &pkg.Package{
|
||||||
Name: path.Base(reader.VirtualPath),
|
Name: path.Base(reader.VirtualPath),
|
||||||
Version: matchMetadata["version"],
|
Version: version,
|
||||||
Language: pkg.Binary,
|
Language: pkg.Binary,
|
||||||
Locations: source.NewLocationSet(reader.Location),
|
Locations: source.NewLocationSet(reader.Location),
|
||||||
Type: pkg.BinaryPkg,
|
Type: pkg.BinaryPkg,
|
||||||
CPEs: c.CPEs,
|
CPEs: cpes,
|
||||||
MetadataType: pkg.BinaryMetadataType,
|
MetadataType: pkg.BinaryMetadataType,
|
||||||
Metadata: pkg.BinaryMetadata{
|
Metadata: pkg.BinaryMetadata{
|
||||||
Classifier: c.Package,
|
Classifier: c.Package,
|
||||||
@ -68,7 +82,6 @@ func (c Classifier) Examine(reader source.LocationReadCloser) (p *pkg.Package, r
|
|||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return classifiedPackage, nil, nil
|
return classifiedPackage, nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
96
syft/pkg/cataloger/generic/classifier_test.go
Normal file
96
syft/pkg/cataloger/generic/classifier_test.go
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
package generic
|
||||||
|
|
||||||
|
import (
|
||||||
|
"regexp"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
|
"github.com/anchore/syft/syft/pkg"
|
||||||
|
"github.com/anchore/syft/syft/source"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_ClassifierCPEs(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
fixture string
|
||||||
|
classifier Classifier
|
||||||
|
cpes []string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "no CPEs",
|
||||||
|
fixture: "test-fixtures/version.txt",
|
||||||
|
classifier: Classifier{
|
||||||
|
Package: "some-app",
|
||||||
|
FilepathPatterns: []*regexp.Regexp{
|
||||||
|
regexp.MustCompile(".*/version.txt"),
|
||||||
|
},
|
||||||
|
EvidencePatterns: []*regexp.Regexp{
|
||||||
|
regexp.MustCompile(`(?m)my-verison:(?P<version>[0-9.]+)`),
|
||||||
|
},
|
||||||
|
CPEs: []pkg.CPE{},
|
||||||
|
},
|
||||||
|
cpes: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "one CPE",
|
||||||
|
fixture: "test-fixtures/version.txt",
|
||||||
|
classifier: Classifier{
|
||||||
|
Package: "some-app",
|
||||||
|
FilepathPatterns: []*regexp.Regexp{
|
||||||
|
regexp.MustCompile(".*/version.txt"),
|
||||||
|
},
|
||||||
|
EvidencePatterns: []*regexp.Regexp{
|
||||||
|
regexp.MustCompile(`(?m)my-verison:(?P<version>[0-9.]+)`),
|
||||||
|
},
|
||||||
|
CPEs: []pkg.CPE{
|
||||||
|
pkg.MustCPE("cpe:2.3:a:some:app:*:*:*:*:*:*:*:*"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
cpes: []string{
|
||||||
|
"cpe:2.3:a:some:app:1.8:*:*:*:*:*:*:*",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "multiple CPEs",
|
||||||
|
fixture: "test-fixtures/version.txt",
|
||||||
|
classifier: Classifier{
|
||||||
|
Package: "some-app",
|
||||||
|
FilepathPatterns: []*regexp.Regexp{
|
||||||
|
regexp.MustCompile(".*/version.txt"),
|
||||||
|
},
|
||||||
|
EvidencePatterns: []*regexp.Regexp{
|
||||||
|
regexp.MustCompile(`(?m)my-verison:(?P<version>[0-9.]+)`),
|
||||||
|
},
|
||||||
|
CPEs: []pkg.CPE{
|
||||||
|
pkg.MustCPE("cpe:2.3:a:some:app:*:*:*:*:*:*:*:*"),
|
||||||
|
pkg.MustCPE("cpe:2.3:a:some:apps:*:*:*:*:*:*:*:*"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
cpes: []string{
|
||||||
|
"cpe:2.3:a:some:app:1.8:*:*:*:*:*:*:*",
|
||||||
|
"cpe:2.3:a:some:apps:1.8:*:*:*:*:*:*:*",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
t.Run(test.name, func(t *testing.T) {
|
||||||
|
resolver := source.NewMockResolverForPaths(test.fixture)
|
||||||
|
locations, err := resolver.FilesByPath(test.fixture)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Len(t, locations, 1)
|
||||||
|
location := locations[0]
|
||||||
|
readCloser, err := resolver.FileContentsByLocation(location)
|
||||||
|
require.NoError(t, err)
|
||||||
|
p, _, err := test.classifier.Examine(source.NewLocationReadCloser(location, readCloser))
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
var cpes []string
|
||||||
|
for _, c := range p.CPEs {
|
||||||
|
cpes = append(cpes, pkg.CPEString(c))
|
||||||
|
}
|
||||||
|
require.Equal(t, test.cpes, cpes)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
1
syft/pkg/cataloger/generic/test-fixtures/version.txt
Normal file
1
syft/pkg/cataloger/generic/test-fixtures/version.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
my-verison:1.8
|
||||||
Loading…
x
Reference in New Issue
Block a user