-
Notifications
You must be signed in to change notification settings - Fork 554
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add nodejs-binary package classifier (#1296)
- Loading branch information
Showing
20 changed files
with
209 additions
and
12 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package pkg | ||
|
||
type BinaryMetadata struct { | ||
Classifier string | ||
RealPath string | ||
VirtualPath string | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
package generic | ||
|
||
import ( | ||
"fmt" | ||
"io" | ||
"path" | ||
"regexp" | ||
|
||
"github.com/anchore/syft/internal" | ||
"github.com/anchore/syft/syft/artifact" | ||
"github.com/anchore/syft/syft/file" | ||
"github.com/anchore/syft/syft/pkg" | ||
"github.com/anchore/syft/syft/pkg/cataloger/internal/unionreader" | ||
"github.com/anchore/syft/syft/source" | ||
) | ||
|
||
// Classifier is a generic package classifier that can be used to match a package definition | ||
// to a file that meets the given content criteria of the EvidencePatternTemplates. | ||
type Classifier struct { | ||
Package string | ||
// FilepathPatterns is a list of regular expressions that will be used to match against the file path of a given | ||
// 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. | ||
FilepathPatterns []*regexp.Regexp | ||
// EvidencePattern 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. | ||
EvidencePatterns []*regexp.Regexp | ||
// CPE is the CPE we want to match against | ||
CPEs []pkg.CPE | ||
} | ||
|
||
func (c Classifier) Examine(reader source.LocationReadCloser) (p *pkg.Package, r *artifact.Relationship, err error) { | ||
doesFilepathMatch := true | ||
if len(c.FilepathPatterns) > 0 { | ||
doesFilepathMatch, _ = file.FilepathMatches(c.FilepathPatterns, reader.Location) | ||
} | ||
|
||
if !doesFilepathMatch { | ||
return nil, nil, fmt.Errorf("location: %s did not match any patterns for package=%q", reader.Location, c.Package) | ||
} | ||
|
||
contents, err := getContents(reader) | ||
if err != nil { | ||
return nil, nil, fmt.Errorf("unable to get read contents for file: %+v", err) | ||
} | ||
|
||
var classifiedPackage *pkg.Package | ||
for _, patternTemplate := range c.EvidencePatterns { | ||
if !patternTemplate.Match(contents) { | ||
continue | ||
} | ||
|
||
matchMetadata := internal.MatchNamedCaptureGroups(patternTemplate, string(contents)) | ||
if classifiedPackage == nil { | ||
classifiedPackage = &pkg.Package{ | ||
Name: path.Base(reader.VirtualPath), | ||
Version: matchMetadata["version"], | ||
Language: pkg.Binary, | ||
Locations: source.NewLocationSet(reader.Location), | ||
Type: pkg.BinaryPkg, | ||
CPEs: c.CPEs, | ||
MetadataType: pkg.BinaryMetadataType, | ||
Metadata: pkg.BinaryMetadata{ | ||
Classifier: c.Package, | ||
RealPath: reader.RealPath, | ||
VirtualPath: reader.VirtualPath, | ||
}, | ||
} | ||
break | ||
} | ||
} | ||
return classifiedPackage, nil, nil | ||
} | ||
|
||
func getContents(reader source.LocationReadCloser) ([]byte, error) { | ||
unionReader, err := unionreader.GetUnionReader(reader.ReadCloser) | ||
if err != nil { | ||
return nil, fmt.Errorf("unable to get union reader for file: %+v", err) | ||
} | ||
|
||
contents, err := io.ReadAll(unionReader) | ||
if err != nil { | ||
return nil, fmt.Errorf("unable to get contents for file: %+v", err) | ||
} | ||
|
||
return contents, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
package javascript | ||
|
||
import ( | ||
"regexp" | ||
|
||
"github.com/anchore/syft/internal/log" | ||
"github.com/anchore/syft/syft/artifact" | ||
"github.com/anchore/syft/syft/pkg" | ||
"github.com/anchore/syft/syft/pkg/cataloger/generic" | ||
"github.com/anchore/syft/syft/source" | ||
) | ||
|
||
var nodeClassifier = generic.Classifier{ | ||
Package: "node.js", // Note: this purposely matches the "node.js" string to aid nvd vuln matching | ||
FilepathPatterns: []*regexp.Regexp{ | ||
// note: should we just parse all files resolved with executable mimetypes | ||
// regexp that matches node binary | ||
regexp.MustCompile(`(.*/|^)node$`), | ||
}, | ||
EvidencePatterns: []*regexp.Regexp{ | ||
// regex that matches node.js/vx.y.z | ||
regexp.MustCompile(`(?m)node\.js\/v(?P<version>[0-9]+\.[0-9]+\.[0-9]+)`), | ||
}, | ||
CPEs: []pkg.CPE{ | ||
pkg.MustCPE("cpe:2.3:a:nodejs:node.js:*:*:*:*:*:*:*:*"), | ||
}, | ||
} | ||
|
||
func parseNodeBinary(_ source.FileResolver, _ *generic.Environment, reader source.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) { | ||
p, _, err := nodeClassifier.Examine(reader) | ||
if err != nil { | ||
log.Trace("failed to find node.js package: %+v", err) | ||
return nil, nil, nil // we can silently fail here to reduce warning noise | ||
} | ||
|
||
// TODO add node specific metadata to the packages to help with vulnerability matching | ||
if p != nil { | ||
p.Language = pkg.JavaScript | ||
return []pkg.Package{*p}, nil, nil | ||
} | ||
p.SetID() | ||
return nil, nil, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.