mirror of
https://github.com/anchore/grype
synced 2024-11-10 06:34:13 +00:00
175 patch - allow ignore not fixed to work independently of configured rules (#454)
* add ignore rules that allow different states of fixes to be ignored Signed-off-by: Christopher Angelo Phillips <christopher.phillips@anchore.com>
This commit is contained in:
parent
e544dff368
commit
30340dbdf6
3 changed files with 118 additions and 22 deletions
16
cmd/root.go
16
cmd/root.go
|
@ -27,10 +27,18 @@ import (
|
|||
"github.com/spf13/pflag"
|
||||
"github.com/spf13/viper"
|
||||
"github.com/wagoodman/go-partybus"
|
||||
|
||||
grypeDb "github.com/anchore/grype-db/pkg/db/v3"
|
||||
)
|
||||
|
||||
var persistentOpts = config.CliOnlyOptions{}
|
||||
|
||||
var ignoreNonFixedMatches = []match.IgnoreRule{
|
||||
{FixState: string(grypeDb.NotFixedState)},
|
||||
{FixState: string(grypeDb.WontFixState)},
|
||||
{FixState: string(grypeDb.UnknownFixState)},
|
||||
}
|
||||
|
||||
var (
|
||||
rootCmd = &cobra.Command{
|
||||
Use: fmt.Sprintf("%s [IMAGE]", internal.ApplicationName),
|
||||
|
@ -117,7 +125,7 @@ func setRootFlags(flags *pflag.FlagSet) {
|
|||
|
||||
flags.BoolP(
|
||||
"only-fixed", "", false,
|
||||
"only set the return code to 1 if vulnerabilities are found that have fixes",
|
||||
"ignore matches for vulnerabilities that are not fixed",
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -240,8 +248,12 @@ func startWorker(userInput string, failOnSeverity *vulnerability.Severity) <-cha
|
|||
return
|
||||
}
|
||||
|
||||
if appConfig.OnlyFixed {
|
||||
appConfig.Ignore = append(appConfig.Ignore, ignoreNonFixedMatches...)
|
||||
}
|
||||
|
||||
allMatches := grype.FindVulnerabilitiesForPackage(provider, context.Distro, packages...)
|
||||
remainingMatches, ignoredMatches := match.ApplyIgnoreRules(allMatches, appConfig.Ignore, appConfig.OnlyFixed)
|
||||
remainingMatches, ignoredMatches := match.ApplyIgnoreRules(allMatches, appConfig.Ignore)
|
||||
|
||||
if count := len(ignoredMatches); count > 0 {
|
||||
log.Infof("Ignoring %d matches due to user-provided ignore rules", count)
|
||||
|
|
|
@ -2,8 +2,6 @@ package match
|
|||
|
||||
import (
|
||||
"github.com/bmatcuk/doublestar/v2"
|
||||
|
||||
grypeDb "github.com/anchore/grype-db/pkg/db/v3"
|
||||
)
|
||||
|
||||
// An IgnoredMatch is a vulnerability Match that has been ignored because one or more IgnoreRules applied to the match.
|
||||
|
@ -20,6 +18,7 @@ type IgnoredMatch struct {
|
|||
// rule to apply.
|
||||
type IgnoreRule struct {
|
||||
Vulnerability string `yaml:"vulnerability" json:"vulnerability" mapstructure:"vulnerability"`
|
||||
FixState string `yaml:"fix-state" json:"fix-state" mapstructure:"fix-state"`
|
||||
Package IgnoreRulePackage `yaml:"package" json:"package" mapstructure:"package"`
|
||||
}
|
||||
|
||||
|
@ -37,11 +36,7 @@ type IgnoreRulePackage struct {
|
|||
// applicable rules are attached to the Match to form an IgnoredMatch.
|
||||
// ApplyIgnoreRules returns two collections: the matches that are not being
|
||||
// ignored, and the matches that are being ignored.
|
||||
func ApplyIgnoreRules(matches Matches, rules []IgnoreRule, failOnlyFixed bool) (Matches, []IgnoredMatch) {
|
||||
if len(rules) == 0 {
|
||||
return matches, nil
|
||||
}
|
||||
|
||||
func ApplyIgnoreRules(matches Matches, rules []IgnoreRule) (Matches, []IgnoredMatch) {
|
||||
var ignoredMatches []IgnoredMatch
|
||||
remainingMatches := NewMatches()
|
||||
|
||||
|
@ -54,12 +49,7 @@ func ApplyIgnoreRules(matches Matches, rules []IgnoreRule, failOnlyFixed bool) (
|
|||
}
|
||||
}
|
||||
|
||||
var ignoreMatch bool
|
||||
if failOnlyFixed {
|
||||
ignoreMatch = isNotFixed(match)
|
||||
}
|
||||
|
||||
if len(applicableRules) > 0 || ignoreMatch {
|
||||
if len(applicableRules) > 0 {
|
||||
ignoredMatches = append(ignoredMatches, IgnoredMatch{
|
||||
Match: match,
|
||||
AppliedIgnoreRules: applicableRules,
|
||||
|
@ -74,10 +64,6 @@ func ApplyIgnoreRules(matches Matches, rules []IgnoreRule, failOnlyFixed bool) (
|
|||
return remainingMatches, ignoredMatches
|
||||
}
|
||||
|
||||
func isNotFixed(m Match) bool {
|
||||
return m.Vulnerability.Fix.State == grypeDb.NotFixedState
|
||||
}
|
||||
|
||||
func shouldIgnore(match Match, rule IgnoreRule) bool {
|
||||
ignoreConditions := getIgnoreConditionsForRule(rule)
|
||||
if len(ignoreConditions) == 0 {
|
||||
|
@ -123,9 +109,19 @@ func getIgnoreConditionsForRule(rule IgnoreRule) []ignoreCondition {
|
|||
ignoreConditions = append(ignoreConditions, ifPackageLocationApplies(l))
|
||||
}
|
||||
|
||||
if fs := rule.FixState; fs != "" {
|
||||
ignoreConditions = append(ignoreConditions, ifFixStateApplies(fs))
|
||||
}
|
||||
|
||||
return ignoreConditions
|
||||
}
|
||||
|
||||
func ifFixStateApplies(fs string) ignoreCondition {
|
||||
return func(match Match) bool {
|
||||
return fs == string(match.Vulnerability.Fix.State)
|
||||
}
|
||||
}
|
||||
|
||||
func ifVulnerabilityApplies(vulnerability string) ignoreCondition {
|
||||
return func(match Match) bool {
|
||||
return vulnerability == match.Vulnerability.ID
|
||||
|
|
|
@ -11,6 +11,8 @@ import (
|
|||
"github.com/anchore/grype/grype/vulnerability"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
grypeDb "github.com/anchore/grype-db/pkg/db/v3"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -18,6 +20,9 @@ var (
|
|||
{
|
||||
Vulnerability: vulnerability.Vulnerability{
|
||||
ID: "CVE-123",
|
||||
Fix: vulnerability.Fix{
|
||||
State: grypeDb.FixedState,
|
||||
},
|
||||
},
|
||||
Package: pkg.Package{
|
||||
Name: "dive",
|
||||
|
@ -33,6 +38,9 @@ var (
|
|||
{
|
||||
Vulnerability: vulnerability.Vulnerability{
|
||||
ID: "CVE-456",
|
||||
Fix: vulnerability.Fix{
|
||||
State: grypeDb.NotFixedState,
|
||||
},
|
||||
},
|
||||
Package: pkg.Package{
|
||||
Name: "reach",
|
||||
|
@ -46,6 +54,44 @@ var (
|
|||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Vulnerability: vulnerability.Vulnerability{
|
||||
ID: "CVE-457",
|
||||
Fix: vulnerability.Fix{
|
||||
State: grypeDb.WontFixState,
|
||||
},
|
||||
},
|
||||
Package: pkg.Package{
|
||||
Name: "beach",
|
||||
Version: "100.0.51",
|
||||
Type: "gem",
|
||||
Locations: []source.Location{
|
||||
{
|
||||
RealPath: "/real/path/with/beach",
|
||||
VirtualPath: "/virtual/path/that/has/beach",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Vulnerability: vulnerability.Vulnerability{
|
||||
ID: "CVE-458",
|
||||
Fix: vulnerability.Fix{
|
||||
State: grypeDb.UnknownFixState,
|
||||
},
|
||||
},
|
||||
Package: pkg.Package{
|
||||
Name: "speach",
|
||||
Version: "100.0.52",
|
||||
Type: "gem",
|
||||
Locations: []source.Location{
|
||||
{
|
||||
RealPath: "/real/path/with/speach",
|
||||
VirtualPath: "/virtual/path/that/has/speach",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
|
@ -101,7 +147,10 @@ func TestApplyIgnoreRules(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
expectedRemainingMatches: nil,
|
||||
expectedRemainingMatches: []Match{
|
||||
allMatches[2],
|
||||
allMatches[3],
|
||||
},
|
||||
expectedIgnoredMatches: []IgnoredMatch{
|
||||
{
|
||||
Match: allMatches[0],
|
||||
|
@ -133,6 +182,8 @@ func TestApplyIgnoreRules(t *testing.T) {
|
|||
},
|
||||
expectedRemainingMatches: []Match{
|
||||
allMatches[0],
|
||||
allMatches[2],
|
||||
allMatches[3],
|
||||
},
|
||||
expectedIgnoredMatches: []IgnoredMatch{
|
||||
{
|
||||
|
@ -145,16 +196,53 @@ func TestApplyIgnoreRules(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ignore matches without fix",
|
||||
allMatches: allMatches,
|
||||
ignoreRules: []IgnoreRule{
|
||||
{FixState: string(grypeDb.NotFixedState)},
|
||||
{FixState: string(grypeDb.WontFixState)},
|
||||
{FixState: string(grypeDb.UnknownFixState)},
|
||||
},
|
||||
expectedRemainingMatches: []Match{
|
||||
allMatches[0],
|
||||
},
|
||||
expectedIgnoredMatches: []IgnoredMatch{
|
||||
{
|
||||
Match: allMatches[1],
|
||||
AppliedIgnoreRules: []IgnoreRule{
|
||||
{
|
||||
FixState: "not-fixed",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Match: allMatches[2],
|
||||
AppliedIgnoreRules: []IgnoreRule{
|
||||
{
|
||||
FixState: "wont-fix",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Match: allMatches[3],
|
||||
AppliedIgnoreRules: []IgnoreRule{
|
||||
{
|
||||
FixState: "unknown",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, testCase := range cases {
|
||||
t.Run(testCase.name, func(t *testing.T) {
|
||||
failOnlyFixed := false
|
||||
locationComparerOption := cmp.Comparer(func(x, y source.Location) bool {
|
||||
return x.RealPath == y.RealPath && x.VirtualPath == y.VirtualPath
|
||||
})
|
||||
|
||||
actualRemainingMatches, actualIgnoredMatches := ApplyIgnoreRules(sliceToMatches(testCase.allMatches), testCase.ignoreRules, failOnlyFixed)
|
||||
actualRemainingMatches, actualIgnoredMatches := ApplyIgnoreRules(sliceToMatches(testCase.allMatches), testCase.ignoreRules)
|
||||
|
||||
if diff := cmp.Diff(testCase.expectedRemainingMatches, matchesToSlice(actualRemainingMatches), locationComparerOption); diff != "" {
|
||||
t.Errorf("unexpected diff in remaining matches (-expected +actual):\n%s", diff)
|
||||
|
|
Loading…
Reference in a new issue