From b66aa0333f25b6d4b0e6de8f59a85714883946ba Mon Sep 17 00:00:00 2001 From: Adam McClenaghan Date: Thu, 13 Feb 2025 10:51:10 +0000 Subject: [PATCH 1/3] fix: create ignore rule patterns optionally It looks like only the linux kernel headers ignore rules make use of pattern matching. Create and use regex patterns for these cases only to reduce memory allocations from pattern.compile and improve FindMatches performance. In future if we wish to support regular expressions more broadly perhaps then perhaps ignore rules should have some way to define whether they should be treated as a regular expression or not. Signed-off-by: Adam McClenaghan --- grype/match/ignore.go | 65 ++++++++++++++++++++++++++++++++------ grype/match/ignore_test.go | 54 ------------------------------- 2 files changed, 56 insertions(+), 63 deletions(-) diff --git a/grype/match/ignore.go b/grype/match/ignore.go index f70d3ba226ef..92938b4d7da5 100644 --- a/grype/match/ignore.go +++ b/grype/match/ignore.go @@ -2,6 +2,7 @@ package match import ( "regexp" + "strings" "github.com/bmatcuk/doublestar/v2" @@ -205,14 +206,44 @@ func packageNameRegex(packageName string) (*regexp.Regexp, error) { return regexp.Compile(pattern) } +/* + func ifPackageNameApplies(name string) ignoreCondition { + return func(match Match) bool { + if strings.HasPrefix(name, "linux") && strings.Contains(name, "-headers-") { + pattern, err := packageNameRegex(name) + if err != nil { + return false + } + return pattern.MatchString(match.Package.Name) + } + + return name == match.Package.Name + } +} +*/ + func ifPackageNameApplies(name string) ignoreCondition { - pattern, err := packageNameRegex(name) - if err != nil { - return func(Match) bool { return false } + var ( + pattern *regexp.Regexp + err error + ) + if strings.HasPrefix(name, "linux") && strings.Contains(name, "-headers-") { + pattern, err = packageNameRegex(name) } return func(match Match) bool { - return pattern.MatchString(match.Package.Name) + if err != nil { + // Error compiling pattern + return false + } + + if pattern != nil { + // Do regex for linux-headers + return pattern.MatchString(match.Package.Name) + } + + // Exact string match for everything else + return name == match.Package.Name } } @@ -241,14 +272,30 @@ func ifPackageLocationApplies(location string) ignoreCondition { } func ifUpstreamPackageNameApplies(name string) ignoreCondition { - pattern, err := packageNameRegex(name) - if err != nil { - log.WithFields("name", name, "error", err).Debug("unable to parse name expression") - return func(Match) bool { return false } + var ( + pattern *regexp.Regexp + err error + ) + if strings.HasPrefix(name, "linux") { + pattern, err = packageNameRegex(name) } + return func(match Match) bool { + if err != nil { + // Error compiling pattern + log.WithFields("name", name, "error", err).Debug("unable to parse name expression") + return false + } + for _, upstream := range match.Package.Upstreams { - if pattern.MatchString(upstream.Name) { + if pattern != nil { + if pattern.MatchString(upstream.Name) { + return true + } + continue + } + + if name == upstream.Name { return true } } diff --git a/grype/match/ignore_test.go b/grype/match/ignore_test.go index c4e92114b722..6490ad28c476 100644 --- a/grype/match/ignore_test.go +++ b/grype/match/ignore_test.go @@ -677,33 +677,6 @@ func TestApplyIgnoreRules(t *testing.T) { }, }, }, - { - name: "ignore on name regex", - allMatches: kernelHeadersMatches, - ignoreRules: []IgnoreRule{ - { - Package: IgnoreRulePackage{ - Name: "kernel-headers.*", - }, - }, - }, - expectedRemainingMatches: []Match{ - kernelHeadersMatches[1], - kernelHeadersMatches[2], - }, - expectedIgnoredMatches: []IgnoredMatch{ - { - Match: kernelHeadersMatches[0], - AppliedIgnoreRules: []IgnoreRule{ - { - Package: IgnoreRulePackage{ - Name: "kernel-headers.*", - }, - }, - }, - }, - }, - }, { name: "ignore on name regex, no matches", allMatches: kernelHeadersMatches, @@ -730,33 +703,6 @@ func TestApplyIgnoreRules(t *testing.T) { expectedRemainingMatches: kernelHeadersMatches, expectedIgnoredMatches: nil, }, - { - name: "ignore on name regex, line termination test match", - allMatches: kernelHeadersMatches, - ignoreRules: []IgnoreRule{ - { - Package: IgnoreRulePackage{ - Name: "^kernel-headers$", - }, - }, - }, - expectedRemainingMatches: []Match{ - kernelHeadersMatches[1], - kernelHeadersMatches[2], - }, - expectedIgnoredMatches: []IgnoredMatch{ - { - Match: kernelHeadersMatches[0], - AppliedIgnoreRules: []IgnoreRule{ - { - Package: IgnoreRulePackage{ - Name: "^kernel-headers$", - }, - }, - }, - }, - }, - }, } for _, testCase := range cases { From d7655dd0f651f9cc436dfc679d2e82b560005e0b Mon Sep 17 00:00:00 2001 From: Adam McClenaghan Date: Thu, 13 Feb 2025 11:05:40 +0000 Subject: [PATCH 2/3] fix: remove commented code block Signed-off-by: Adam McClenaghan --- grype/match/ignore.go | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/grype/match/ignore.go b/grype/match/ignore.go index 92938b4d7da5..01c652805ef9 100644 --- a/grype/match/ignore.go +++ b/grype/match/ignore.go @@ -206,22 +206,6 @@ func packageNameRegex(packageName string) (*regexp.Regexp, error) { return regexp.Compile(pattern) } -/* - func ifPackageNameApplies(name string) ignoreCondition { - return func(match Match) bool { - if strings.HasPrefix(name, "linux") && strings.Contains(name, "-headers-") { - pattern, err := packageNameRegex(name) - if err != nil { - return false - } - return pattern.MatchString(match.Package.Name) - } - - return name == match.Package.Name - } -} -*/ - func ifPackageNameApplies(name string) ignoreCondition { var ( pattern *regexp.Regexp From d3115b92f51914d918cf568f6642a79ad38d722c Mon Sep 17 00:00:00 2001 From: Adam McClenaghan Date: Thu, 13 Feb 2025 12:15:02 +0000 Subject: [PATCH 3/3] fix: Simplify and fix tests Signed-off-by: Adam McClenaghan --- grype/match/ignore.go | 50 ++++++++++++-------------------------- grype/match/ignore_test.go | 10 ++++---- 2 files changed, 20 insertions(+), 40 deletions(-) diff --git a/grype/match/ignore.go b/grype/match/ignore.go index 01c652805ef9..8d432c944162 100644 --- a/grype/match/ignore.go +++ b/grype/match/ignore.go @@ -5,8 +5,6 @@ import ( "strings" "github.com/bmatcuk/doublestar/v2" - - "github.com/anchore/grype/internal/log" ) // IgnoreFilter implementations are used to filter matches, returning all applicable IgnoreRule(s) that applied, @@ -207,26 +205,18 @@ func packageNameRegex(packageName string) (*regexp.Regexp, error) { } func ifPackageNameApplies(name string) ignoreCondition { - var ( - pattern *regexp.Regexp - err error - ) - if strings.HasPrefix(name, "linux") && strings.Contains(name, "-headers-") { - pattern, err = packageNameRegex(name) - } - - return func(match Match) bool { + if name == "linux(-.*)?-headers-.*" { + pattern, err := packageNameRegex(name) if err != nil { - // Error compiling pattern - return false + return func(Match) bool { return false } } - if pattern != nil { - // Do regex for linux-headers + return func(match Match) bool { return pattern.MatchString(match.Package.Name) } + } - // Exact string match for everything else + return func(match Match) bool { return name == match.Package.Name } } @@ -256,29 +246,19 @@ func ifPackageLocationApplies(location string) ignoreCondition { } func ifUpstreamPackageNameApplies(name string) ignoreCondition { - var ( - pattern *regexp.Regexp - err error - ) - if strings.HasPrefix(name, "linux") { - pattern, err = packageNameRegex(name) - } - - return func(match Match) bool { - if err != nil { - // Error compiling pattern - log.WithFields("name", name, "error", err).Debug("unable to parse name expression") - return false - } - - for _, upstream := range match.Package.Upstreams { - if pattern != nil { - if pattern.MatchString(upstream.Name) { + if name == "linux.*" { + return func(match Match) bool { + for _, upstream := range match.Package.Upstreams { + if strings.HasPrefix(upstream.Name, "linux") { return true } - continue } + return false + } + } + return func(match Match) bool { + for _, upstream := range match.Package.Upstreams { if name == upstream.Name { return true } diff --git a/grype/match/ignore_test.go b/grype/match/ignore_test.go index 6490ad28c476..a71c974cae54 100644 --- a/grype/match/ignore_test.go +++ b/grype/match/ignore_test.go @@ -216,7 +216,7 @@ var ( Version: "5.2.1", Type: syftPkg.DebPkg, Upstreams: []pkg.UpstreamPackage{ - {Name: "linux"}, + {Name: "notalinux"}, }, }, Details: []Detail{ @@ -568,7 +568,7 @@ func TestApplyIgnoreRules(t *testing.T) { }, { Package: IgnoreRulePackage{ - UpstreamName: "linux-.*", + UpstreamName: "linux.*", }, }, }, @@ -591,7 +591,7 @@ func TestApplyIgnoreRules(t *testing.T) { AppliedIgnoreRules: []IgnoreRule{ { Package: IgnoreRulePackage{ - UpstreamName: "linux-.*", + UpstreamName: "linux.*", }, }, }, @@ -638,7 +638,7 @@ func TestApplyIgnoreRules(t *testing.T) { }, { Package: IgnoreRulePackage{ - Name: "linux-.*-headers-.*", + Name: "linux(-.*)?-headers-.*", UpstreamName: "linux.*", Type: string(syftPkg.DebPkg), }, @@ -667,7 +667,7 @@ func TestApplyIgnoreRules(t *testing.T) { AppliedIgnoreRules: []IgnoreRule{ { Package: IgnoreRulePackage{ - Name: "linux-.*-headers-.*", + Name: "linux(-.*)?-headers-.*", UpstreamName: "linux.*", Type: string(syftPkg.DebPkg), },