Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(misconf): Add support for skip-dirs and skip-files misconf scanning #7496

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions pkg/flag/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -470,6 +470,8 @@ func (o *Options) FilterOpts() result.FilterOptions {
IgnoreLicenses: o.IgnoredLicenses,
CacheDir: o.CacheDir,
VEXSources: o.VEXSources,
SkipDirs: o.SkipDirs,
SkipFiles: o.SkipFiles,
}
}

Expand Down
58 changes: 56 additions & 2 deletions pkg/result/filter.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,15 @@ import (
"path/filepath"
"slices"
"sort"
"strings"

"github.com/open-policy-agent/opa/rego"
"github.com/samber/lo"
"golang.org/x/xerrors"

dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
"github.com/aquasecurity/trivy/pkg/fanal/walker"
"github.com/aquasecurity/trivy/pkg/log"
"github.com/aquasecurity/trivy/pkg/types"
"github.com/aquasecurity/trivy/pkg/vex"
)
Expand All @@ -31,6 +34,8 @@ type FilterOptions struct {
IgnoreLicenses []string
CacheDir string
VEXSources []vex.Source
SkipDirs []string
SkipFiles []string
}

// Filter filters out the report
Expand Down Expand Up @@ -65,7 +70,7 @@ func FilterResult(ctx context.Context, result *types.Result, ignoreConf IgnoreCo
})

filterVulnerabilities(result, severities, opt.IgnoreStatuses, ignoreConf)
filterMisconfigurations(result, severities, opt.IncludeNonFailures, ignoreConf)
filterMisconfigurations(result, severities, opt.IncludeNonFailures, opt.SkipFiles, opt.SkipDirs, ignoreConf)
filterSecrets(result, severities, ignoreConf)
filterLicenses(result, severities, opt.IgnoreLicenses, ignoreConf)

Expand Down Expand Up @@ -117,12 +122,60 @@ func filterVulnerabilities(result *types.Result, severities []string, ignoreStat
}
}

func filterMisconfigurations(result *types.Result, severities []string, includeNonFailures bool,
func checkGlobMatch(misconf types.DetectedMisconfiguration, result *types.Result, filename string, skips []string) bool {
if walker.SkipPath(filepath.ToSlash(filepath.Clean(filename)), walker.CleanSkipPaths(skips)) {
log.Debug("skipping path based on glob match", log.String("file", filename))
result.MisconfSummary.Exceptions++
result.ModifiedFindings = append(result.ModifiedFindings,
types.NewModifiedFinding(misconf, types.FindingStatusIgnored, fmt.Sprintf("skipped due to glob match: %s", skips), "trivy cli args"))
return true
}
return false
}

func checkSubstrMatch(misconf types.DetectedMisconfiguration, result *types.Result, filename string, skips []string) bool {
for _, skipDir := range skips {
if strings.Contains(filepath.ToSlash(filepath.Clean(filename)), skipDir) {
log.Debug("skipping path based on substring match", log.String("file", filename))
result.MisconfSummary.Exceptions++
result.ModifiedFindings = append(result.ModifiedFindings,
types.NewModifiedFinding(misconf, types.FindingStatusIgnored, fmt.Sprintf("skipped due to substring match: %s", skips), "trivy cli args"))
return true
}
}
return false
}

func checkPathMatch(misconf types.DetectedMisconfiguration, result *types.Result, skips []string) bool {
for _, o := range misconf.CauseMetadata.Occurrences {
if checkGlobMatch(misconf, result, o.Filename, skips) {
return true
}

if checkSubstrMatch(misconf, result, o.Filename, skips) {
return true
}
}
return false
}

func filterMisconfigurations(result *types.Result, severities []string, includeNonFailures bool, skipFiles, skipDirs []string,
ignoreConfig IgnoreConfig) {
var filtered []types.DetectedMisconfiguration
result.MisconfSummary = new(types.MisconfSummary)

for _, misconf := range result.Misconfigurations {

// Filter by skip dirs
if checkPathMatch(misconf, result, skipDirs) {
continue
}

// Filter by skip files
if checkPathMatch(misconf, result, skipFiles) {
continue
}

// Filter by severity
if !slices.Contains(severities, misconf.Severity) {
continue
Expand All @@ -142,6 +195,7 @@ func filterMisconfigurations(result *types.Result, severities []string, includeN
if misconf.Status != types.MisconfStatusFailure && !includeNonFailures {
continue
}

filtered = append(filtered, misconf)
}

Expand Down
126 changes: 126 additions & 0 deletions pkg/result/filter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,23 @@ func TestFilter(t *testing.T) {
Message: "something bad",
Severity: dbTypes.SeverityHigh.String(),
Status: types.MisconfStatusFailure,
CauseMetadata: ftypes.CauseMetadata{
Resource: "foo-resource-1",
Provider: "bar-provider-1",
Service: "baz-service-1",
StartLine: 123,
EndLine: 456,
Occurrences: []ftypes.Occurrence{
{
Resource: "foo-resource-occurrence-1",
Filename: "bar-filename-occurrence-1",
Location: ftypes.Location{
StartLine: 666,
EndLine: 888,
},
},
},
},
}
misconf2 = types.DetectedMisconfiguration{
Type: "Kubernetes Security Check",
Expand All @@ -147,6 +164,23 @@ func TestFilter(t *testing.T) {
Message: "something bad",
Severity: dbTypes.SeverityLow.String(),
Status: types.MisconfStatusFailure,
CauseMetadata: ftypes.CauseMetadata{
Resource: "foo-resource-3",
Provider: "bar-provider-3",
Service: "baz-service-3",
StartLine: 123,
EndLine: 456,
Occurrences: []ftypes.Occurrence{
{
Resource: "foo-resource-occurrence-3",
Filename: "../modules/bar-filename-occurrence-3",
Location: ftypes.Location{
StartLine: 666,
EndLine: 888,
},
},
},
},
}
secret1 = types.DetectedSecret{
RuleID: "generic-wanted-rule",
Expand Down Expand Up @@ -194,6 +228,8 @@ func TestFilter(t *testing.T) {
ignoreFile string
policyFile string
vexPath string
skipFiles []string
skipDirs []string
}
tests := []struct {
name string
Expand Down Expand Up @@ -1002,6 +1038,94 @@ func TestFilter(t *testing.T) {
},
},
},
{
name: "skip dirs arg for misconfigurations",
args: args{
report: types.Report{
Results: types.Results{
{
Misconfigurations: []types.DetectedMisconfiguration{
misconf1,
misconf2,
misconf3, //ignored by skip dirs arg
},
},
},
},
severities: []dbTypes.Severity{
dbTypes.SeverityLow,
dbTypes.SeverityHigh,
},
skipDirs: []string{"../modules"},
},
want: types.Report{
Results: types.Results{
{
MisconfSummary: &types.MisconfSummary{
Successes: 1,
Failures: 1,
Exceptions: 1,
},
Misconfigurations: []types.DetectedMisconfiguration{
misconf1,
},
ModifiedFindings: []types.ModifiedFinding{
{
Type: types.FindingTypeMisconfiguration,
Status: types.FindingStatusIgnored,
Statement: "skipped due to substring match: [../modules]",
Source: "trivy cli args",
Finding: misconf3,
},
},
},
},
},
},
{
name: "skip files arg for misconfigurations",
args: args{
report: types.Report{
Results: types.Results{
{
Misconfigurations: []types.DetectedMisconfiguration{
misconf1,
misconf2,
misconf3, //ignored by skip files arg
},
},
},
},
severities: []dbTypes.Severity{
dbTypes.SeverityLow,
dbTypes.SeverityHigh,
},
skipFiles: []string{"../**/bar-filename-occurrence-3"},
},
want: types.Report{
Results: types.Results{
{
MisconfSummary: &types.MisconfSummary{
Successes: 1,
Failures: 1,
Exceptions: 1,
},
Misconfigurations: []types.DetectedMisconfiguration{
misconf1,
},
ModifiedFindings: []types.ModifiedFinding{
{
Type: types.FindingTypeMisconfiguration,
Status: types.FindingStatusIgnored,
Statement: "skipped due to glob match: [../**/bar-filename-occurrence-3]",
Source: "trivy cli args",
Finding: misconf3,
},
},
},
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
Expand All @@ -1022,6 +1146,8 @@ func TestFilter(t *testing.T) {
IgnoreStatuses: tt.args.ignoreStatuses,
IgnoreFile: tt.args.ignoreFile,
PolicyFile: tt.args.policyFile,
SkipDirs: tt.args.skipDirs,
SkipFiles: tt.args.skipFiles,
})
require.NoError(t, err)
assert.Equal(t, tt.want, tt.args.report)
Expand Down