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): Support --ignore-policy in config scans #5359

Merged
merged 4 commits into from
Oct 23, 2023
Merged
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
1 change: 1 addition & 0 deletions docs/docs/references/configuration/cli/trivy_config.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ trivy config [flags] DIR
--helm-set-string strings specify Helm string values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)
--helm-values strings specify paths to override the Helm values.yaml files
-h, --help help for config
--ignore-policy string specify the Rego file path to evaluate each vulnerability
--ignorefile string specify .trivyignore file (default ".trivyignore")
--include-non-failures include successes and exceptions, available with '--scanners config'
--k8s-version string specify k8s version to validate outdated api by it (example: 1.21.0)
Expand Down
1 change: 0 additions & 1 deletion pkg/commands/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -622,7 +622,6 @@ func NewServerCommand(globalFlags *flag.GlobalFlagGroup) *cobra.Command {
func NewConfigCommand(globalFlags *flag.GlobalFlagGroup) *cobra.Command {
reportFlagGroup := flag.NewReportFlagGroup()
reportFlagGroup.DependencyTree = nil // disable '--dependency-tree'
reportFlagGroup.IgnorePolicy = nil // disable '--ignore-policy'
reportFlagGroup.ListAllPkgs = nil // disable '--list-all-pkgs'
reportFlagGroup.ExitOnEOL = nil // disable '--exit-on-eol'
reportFormat := flag.ReportFormatFlag
Expand Down
25 changes: 17 additions & 8 deletions pkg/result/filter.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,18 +65,24 @@ func FilterResult(ctx context.Context, result *types.Result, ignoreConf IgnoreCo
result.Secrets = filterSecrets(result, severities, ignoreConf.Secrets)
result.Licenses = filterLicenses(result.Licenses, severities, opt.IgnoreLicenses, ignoreConf.Licenses)

var ignoredMisconfs int
if opt.PolicyFile != "" {
var err error
filteredVulns, filteredMisconfs, err = applyPolicy(ctx, filteredVulns, filteredMisconfs, opt.PolicyFile)
var ignored int
filteredVulns, filteredMisconfs, ignored, err = applyPolicy(ctx, filteredVulns, filteredMisconfs, opt.PolicyFile)
if err != nil {
return xerrors.Errorf("failed to apply the policy: %w", err)
}
ignoredMisconfs += ignored
}
sort.Sort(types.BySeverity(filteredVulns))

result.Vulnerabilities = filteredVulns
result.Misconfigurations = filteredMisconfs
result.MisconfSummary = misconfSummary
if result.MisconfSummary != nil {
result.MisconfSummary.Exceptions += ignoredMisconfs
}
result.Misconfigurations = filteredMisconfs

return nil
}
Expand Down Expand Up @@ -147,6 +153,7 @@ func filterMisconfigurations(result *types.Result, severities []string, includeN
continue
} else if ignoreMisconfs.Match(result.Target, misconf.ID) || ignoreMisconfs.Match(result.Target, misconf.AVDID) {
// Filter misconfigurations by ignore file
summary.Exceptions++
continue
}

Expand Down Expand Up @@ -215,10 +222,10 @@ func summarize(status types.MisconfStatus, summary *types.MisconfSummary) {
}

func applyPolicy(ctx context.Context, vulns []types.DetectedVulnerability, misconfs []types.DetectedMisconfiguration,
policyFile string) ([]types.DetectedVulnerability, []types.DetectedMisconfiguration, error) {
policyFile string) ([]types.DetectedVulnerability, []types.DetectedMisconfiguration, int, error) {
policy, err := os.ReadFile(policyFile)
if err != nil {
return nil, nil, xerrors.Errorf("unable to read the policy file: %w", err)
return nil, nil, 0, xerrors.Errorf("unable to read the policy file: %w", err)
}

query, err := rego.New(
Expand All @@ -227,15 +234,15 @@ func applyPolicy(ctx context.Context, vulns []types.DetectedVulnerability, misco
rego.Module("trivy.rego", string(policy)),
).PrepareForEval(ctx)
if err != nil {
return nil, nil, xerrors.Errorf("unable to prepare for eval: %w", err)
return nil, nil, 0, xerrors.Errorf("unable to prepare for eval: %w", err)
}

// Vulnerabilities
var filteredVulns []types.DetectedVulnerability
for _, vuln := range vulns {
ignored, err := evaluate(ctx, query, vuln)
if err != nil {
return nil, nil, err
return nil, nil, 0, err
}
if ignored {
continue
Expand All @@ -244,18 +251,20 @@ func applyPolicy(ctx context.Context, vulns []types.DetectedVulnerability, misco
}

// Misconfigurations
var ignoredMisconfs int
var filteredMisconfs []types.DetectedMisconfiguration
for _, misconf := range misconfs {
ignored, err := evaluate(ctx, query, misconf)
if err != nil {
return nil, nil, err
return nil, nil, 0, err
}
if ignored {
ignoredMisconfs++
continue
}
filteredMisconfs = append(filteredMisconfs, misconf)
}
return filteredVulns, filteredMisconfs, nil
return filteredVulns, filteredMisconfs, ignoredMisconfs, nil
}
func evaluate(ctx context.Context, query rego.PreparedEvalQuery, input interface{}) (bool, error) {
results, err := query.Eval(ctx, rego.EvalInput(input))
Expand Down
67 changes: 66 additions & 1 deletion pkg/result/filter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,11 @@ func TestFilter(t *testing.T) {
{
Target: "Dockerfile",
Class: types.ClassConfig,
MisconfSummary: &types.MisconfSummary{
Successes: 0,
Failures: 0,
Exceptions: 1,
},
},
{
Secrets: []ftypes.SecretFinding{
Expand Down Expand Up @@ -584,7 +589,7 @@ func TestFilter(t *testing.T) {
MisconfSummary: &types.MisconfSummary{
Successes: 0,
Failures: 1,
Exceptions: 0,
Exceptions: 2,
},
Misconfigurations: []types.DetectedMisconfiguration{
{
Expand Down Expand Up @@ -685,6 +690,66 @@ func TestFilter(t *testing.T) {
},
},
},
{
name: "ignore file for misconf",
args: args{
report: types.Report{
Results: types.Results{
{
Misconfigurations: []types.DetectedMisconfiguration{
{
ID: "AVD-TEST-0001",
AVDID: "AVD-TEST-0001",
Title: "test-0001",
Description: "foo",
Severity: dbTypes.SeverityHigh.String(),
Status: types.StatusFailure,
},
{
ID: "AVD-TEST-0002",
AVDID: "AVD-TEST-0002",
Title: "test-0002",
Description: "bar",
Severity: dbTypes.SeverityHigh.String(),
Status: types.StatusPassed,
},
{ // this misconf is ignored
ID: "AVD-TEST-0003",
AVDID: "AVD-TEST-0003",
Title: "test-0003",
Description: "baz",
Severity: dbTypes.SeverityHigh.String(),
Status: types.StatusFailure,
},
},
},
},
},
severities: []dbTypes.Severity{dbTypes.SeverityHigh},
policyFile: "./testdata/test-ignore-policy-misconf.rego",
},
want: types.Report{
Results: types.Results{
{
MisconfSummary: &types.MisconfSummary{
Successes: 1,
Failures: 2,
Exceptions: 1,
simar7 marked this conversation as resolved.
Show resolved Hide resolved
},
Misconfigurations: []types.DetectedMisconfiguration{
{
ID: "AVD-TEST-0001",
AVDID: "AVD-TEST-0001",
Title: "test-0001",
Description: "foo",
Severity: dbTypes.SeverityHigh.String(),
Status: types.StatusFailure,
},
},
},
},
},
},
{
name: "happy path with duplicates, one with empty fixed version",
args: args{
Expand Down
9 changes: 9 additions & 0 deletions pkg/result/testdata/test-ignore-policy-misconf.rego
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package trivy

import data.lib.trivy

default ignore=false

ignore {
input.AVDID != "AVD-TEST-0001"
}