Skip to content

Commit

Permalink
basic matcher in place
Browse files Browse the repository at this point in the history
Signed-off-by: Alex Goodman <[email protected]>
  • Loading branch information
wagoodman committed Sep 13, 2024
1 parent 19a7170 commit 7c9bbf2
Show file tree
Hide file tree
Showing 12 changed files with 139 additions and 12 deletions.
4 changes: 2 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ bin/
/.task

# changelog generation
CHANGELOG.md
VERSION
/CHANGELOG.md
/VERSION

# IDE configuration
.vscode/
Expand Down
4 changes: 4 additions & 0 deletions cmd/grype/cli/commands/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package commands
import (
"errors"
"fmt"
"github.com/anchore/grype/grype/matcher/jvm"
"strings"

"github.com/spf13/cobra"
Expand Down Expand Up @@ -285,6 +286,9 @@ func getMatchers(opts *options.Grype) []matcher.Matcher {
ExternalSearchConfig: opts.ExternalSources.ToJavaMatcherConfig(),
UseCPEs: opts.Match.Java.UseCPEs,
},
JVM: jvm.MatcherConfig{
UseCPEs: opts.Match.JVM.UseCPEs,
},
Ruby: ruby.MatcherConfig(opts.Match.Ruby),
Python: python.MatcherConfig(opts.Match.Python),
Dotnet: dotnet.MatcherConfig(opts.Match.Dotnet),
Expand Down
2 changes: 2 additions & 0 deletions cmd/grype/cli/options/match.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import "github.com/anchore/clio"
// matchConfig contains all matching-related configuration options available to the user via the application config.
type matchConfig struct {
Java matcherConfig `yaml:"java" json:"java" mapstructure:"java"` // settings for the java matcher
JVM matcherConfig `yaml:"jvm" json:"jvm" mapstructure:"jvm"` // settings for the jvm matcher
Dotnet matcherConfig `yaml:"dotnet" json:"dotnet" mapstructure:"dotnet"` // settings for the dotnet matcher
Golang golangConfig `yaml:"golang" json:"golang" mapstructure:"golang"` // settings for the golang matcher
Javascript matcherConfig `yaml:"javascript" json:"javascript" mapstructure:"javascript"` // settings for the javascript matcher
Expand Down Expand Up @@ -43,6 +44,7 @@ func defaultMatchConfig() matchConfig {
dontUseCpe := matcherConfig{UseCPEs: false}
return matchConfig{
Java: dontUseCpe,
JVM: useCpe,
Dotnet: dontUseCpe,
Golang: defaultGolangConfig(),
Javascript: dontUseCpe,
Expand Down
11 changes: 6 additions & 5 deletions grype/internal/packagemetadata/names.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,12 @@ import (
// not the same it may be important to select different names. This design decision has been deferred, for now
// the same metadata types that have been used in the past should be used here.
var jsonNameFromType = map[reflect.Type][]string{
reflect.TypeOf(pkg.ApkMetadata{}): nameList("ApkMetadata"),
reflect.TypeOf(pkg.GolangBinMetadata{}): nameList("GolangBinMetadata"),
reflect.TypeOf(pkg.GolangModMetadata{}): nameList("GolangModMetadata"),
reflect.TypeOf(pkg.JavaMetadata{}): nameList("JavaMetadata"),
reflect.TypeOf(pkg.RpmMetadata{}): nameList("RpmMetadata"),
reflect.TypeOf(pkg.ApkMetadata{}): nameList("ApkMetadata"),
reflect.TypeOf(pkg.GolangBinMetadata{}): nameList("GolangBinMetadata"),
reflect.TypeOf(pkg.GolangModMetadata{}): nameList("GolangModMetadata"),
reflect.TypeOf(pkg.JavaMetadata{}): nameList("JavaMetadata"),
reflect.TypeOf(pkg.RpmMetadata{}): nameList("RpmMetadata"),
reflect.TypeOf(pkg.JavaVMInstallationMetadata{}): nameList("JavaVMInstallationMetadata"),
}

//nolint:unparam
Expand Down
2 changes: 2 additions & 0 deletions grype/match/matcher_type.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ const (
GoModuleMatcher MatcherType = "go-module-matcher"
OpenVexMatcher MatcherType = "openvex-matcher"
RustMatcher MatcherType = "rust-matcher"
JVMMatcher MatcherType = "jvm-matcher"
)

var AllMatcherTypes = []MatcherType{
Expand All @@ -32,6 +33,7 @@ var AllMatcherTypes = []MatcherType{
GoModuleMatcher,
OpenVexMatcher,
RustMatcher,
JVMMatcher,
}

type MatcherType string
50 changes: 50 additions & 0 deletions grype/matcher/jvm/matcher.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package jvm

import (
"fmt"
"github.com/anchore/grype/grype/distro"
"github.com/anchore/grype/grype/match"
"github.com/anchore/grype/grype/pkg"
"github.com/anchore/grype/grype/search"
"github.com/anchore/grype/grype/vulnerability"
syftPkg "github.com/anchore/syft/syft/pkg"
)

type MatcherConfig struct {
UseCPEs bool
}

type Matcher struct {
cfg MatcherConfig
}

func NewJVMMatcher(cfg MatcherConfig) *Matcher {
return &Matcher{
cfg: cfg,
}
}

func (m *Matcher) PackageTypes() []syftPkg.Type {
return []syftPkg.Type{syftPkg.BinaryPkg}
}

func (m *Matcher) Type() match.MatcherType {
return match.JVMMatcher
}

func (m *Matcher) Match(store vulnerability.Provider, d *distro.Distro, p pkg.Package) ([]match.Match, error) {
if !pkg.IsJvmPackage(p) {
return nil, nil
}

criteria := search.CommonCriteria
if m.cfg.UseCPEs {
criteria = append(criteria, search.ByCPE)
}
matches, err := search.ByCriteria(store, d, p, m.Type(), criteria...)
if err != nil {
return nil, fmt.Errorf("failed to match by exact package: %w", err)
}

return matches, nil
}
3 changes: 3 additions & 0 deletions grype/matcher/matchers.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"github.com/anchore/grype/grype/matcher/golang"
"github.com/anchore/grype/grype/matcher/java"
"github.com/anchore/grype/grype/matcher/javascript"
"github.com/anchore/grype/grype/matcher/jvm"
"github.com/anchore/grype/grype/matcher/msrc"
"github.com/anchore/grype/grype/matcher/portage"
"github.com/anchore/grype/grype/matcher/python"
Expand All @@ -19,6 +20,7 @@ import (
// Config contains values used by individual matcher structs for advanced configuration
type Config struct {
Java java.MatcherConfig
JVM jvm.MatcherConfig
Ruby ruby.MatcherConfig
Python python.MatcherConfig
Dotnet dotnet.MatcherConfig
Expand All @@ -36,6 +38,7 @@ func NewDefaultMatchers(mc Config) []Matcher {
dotnet.NewDotnetMatcher(mc.Dotnet),
&rpm.Matcher{},
java.NewJavaMatcher(mc.Java),
jvm.NewJVMMatcher(mc.JVM),
javascript.NewJavascriptMatcher(mc.Javascript),
&apk.Matcher{},
golang.NewGolangMatcher(mc.Golang),
Expand Down
8 changes: 8 additions & 0 deletions grype/matcher/stock/matcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,17 @@ func (m *Matcher) Type() match.MatcherType {
}

func (m *Matcher) Match(store vulnerability.Provider, d *distro.Distro, p pkg.Package) ([]match.Match, error) {
if !inboundsForMatcher(p) {
return nil, nil
}

criteria := search.CommonCriteria
if m.cfg.UseCPEs {
criteria = append(criteria, search.ByCPE)
}
return search.ByCriteria(store, d, p, m.Type(), criteria...)
}

func inboundsForMatcher(p pkg.Package) bool {
return !pkg.IsJvmPackage(p)
}
30 changes: 30 additions & 0 deletions grype/pkg/java_metadata.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
package pkg

import (
"github.com/anchore/syft/syft/pkg"
"strings"
)

type JavaMetadata struct {
VirtualPath string `json:"virtualPath"`
PomArtifactID string `json:"pomArtifactID"`
Expand All @@ -12,3 +17,28 @@ type Digest struct {
Algorithm string `json:"algorithm"`
Value string `json:"value"`
}

type JavaVMInstallationMetadata struct {
Release JavaVMReleaseMetadata `json:"release,omitempty"`
}

type JavaVMReleaseMetadata struct {
JavaRuntimeVersion string `json:"javaRuntimeVersion,omitempty"`
JavaVersion string `json:"javaVersion,omitempty"`
FullVersion string `json:"fullVersion,omitempty"`
SemanticVersion string `json:"semanticVersion,omitempty"`
}

func IsJvmPackage(p Package) bool {
if p.Type == pkg.BinaryPkg {
if strings.Contains(p.Name, "jdk") || strings.Contains(p.Name, "jre") || strings.Contains(p.Name, "java") {
return true
}
}

if _, ok := p.Metadata.(JavaVMInstallationMetadata); ok {
return true
}

return false
}
17 changes: 17 additions & 0 deletions grype/pkg/package.go
Original file line number Diff line number Diff line change
Expand Up @@ -214,10 +214,27 @@ func dataFromPkg(p pkg.Package) (interface{}, []UpstreamPackage) {
case pkg.ApkDBEntry:
metadata = apkMetadataFromPkg(p)
upstreams = apkDataFromPkg(p)
case pkg.JavaVMInstallation:

Check failure on line 217 in grype/pkg/package.go

View workflow job for this annotation

GitHub Actions / Quality tests

undefined: pkg.JavaVMInstallation

Check failure on line 217 in grype/pkg/package.go

View workflow job for this annotation

GitHub Actions / Integration tests

undefined: pkg.JavaVMInstallation

Check failure on line 217 in grype/pkg/package.go

View workflow job for this annotation

GitHub Actions / Static analysis

undefined: pkg.JavaVMInstallation

Check failure on line 217 in grype/pkg/package.go

View workflow job for this annotation

GitHub Actions / Static analysis

undefined: pkg.JavaVMInstallation

Check failure on line 217 in grype/pkg/package.go

View workflow job for this annotation

GitHub Actions / Static analysis

undefined: pkg.JavaVMInstallation

Check failure on line 217 in grype/pkg/package.go

View workflow job for this annotation

GitHub Actions / Static analysis

undefined: pkg.JavaVMInstallation

Check failure on line 217 in grype/pkg/package.go

View workflow job for this annotation

GitHub Actions / Unit tests

undefined: pkg.JavaVMInstallation
metadata = javaVmDataFromPkg(p)
}
return metadata, upstreams
}

func javaVmDataFromPkg(p pkg.Package) any {
if value, ok := p.Metadata.(pkg.JavaVMInstallation); ok {

Check failure on line 224 in grype/pkg/package.go

View workflow job for this annotation

GitHub Actions / Quality tests

undefined: pkg.JavaVMInstallation

Check failure on line 224 in grype/pkg/package.go

View workflow job for this annotation

GitHub Actions / Integration tests

undefined: pkg.JavaVMInstallation

Check failure on line 224 in grype/pkg/package.go

View workflow job for this annotation

GitHub Actions / Static analysis

undefined: pkg.JavaVMInstallation (typecheck)

Check failure on line 224 in grype/pkg/package.go

View workflow job for this annotation

GitHub Actions / Static analysis

undefined: pkg.JavaVMInstallation) (typecheck)

Check failure on line 224 in grype/pkg/package.go

View workflow job for this annotation

GitHub Actions / Static analysis

undefined: pkg.JavaVMInstallation) (typecheck)

Check failure on line 224 in grype/pkg/package.go

View workflow job for this annotation

GitHub Actions / Unit tests

undefined: pkg.JavaVMInstallation
return JavaVMInstallationMetadata{
Release: JavaVMReleaseMetadata{
JavaRuntimeVersion: value.Release.JavaRuntimeVersion,
JavaVersion: value.Release.JavaVersion,
FullVersion: value.Release.FullVersion,
SemanticVersion: value.Release.SemanticVersion,
},
}
}

return nil
}

func apkMetadataFromPkg(p pkg.Package) interface{} {
if m, ok := p.Metadata.(pkg.ApkDBEntry); ok {
metadata := ApkMetadata{}
Expand Down
16 changes: 11 additions & 5 deletions grype/version/jvm_version.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,21 @@ func newJvmVersion(raw string) (*jvmVersion, error) {
}

func (v *jvmVersion) Compare(other *Version) (int, error) {
if other.Format != JVMFormat {
return -1, fmt.Errorf("unable to compare JVM to given format: %s", other.Format)
if other.Format == JVMFormat {
if other.rich.jvmVersion == nil {
return -1, fmt.Errorf("given empty jvmVersion object")
}
return other.rich.jvmVersion.compare(*v), nil
}

if other.rich.jvmVersion == nil {
return -1, fmt.Errorf("given empty jvmVersion object")
if other.Format == SemanticFormat {
if other.rich.semVer == nil {
return -1, fmt.Errorf("given empty semVer object")
}
return other.rich.semVer.verObj.Compare(v.semVer), nil
}

return other.rich.jvmVersion.compare(*v), nil
return -1, fmt.Errorf("unable to compare JVM to given format: %s", other.Format)
}

func (v jvmVersion) compare(other jvmVersion) int {
Expand Down
4 changes: 4 additions & 0 deletions grype/version/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package version

import (
"fmt"
syftPkg "github.com/anchore/syft/syft/pkg"
"strings"

"github.com/anchore/grype/grype/pkg"
"github.com/anchore/syft/syft/cpe"
Expand Down Expand Up @@ -51,6 +53,8 @@ func NewVersionFromPkg(p pkg.Package) (*Version, error) {
if format == UnknownFormat {
if _, ok := p.Metadata.(pkg.JavaVMInstallationMetadata); ok {
format = JVMFormat
} else if p.Type == syftPkg.BinaryPkg && (strings.Contains(p.Name, "jdk") || strings.Contains(p.Name, "jre") || strings.Contains(p.Name, "java")) {
format = JVMFormat
}
}

Expand Down

0 comments on commit 7c9bbf2

Please sign in to comment.