Skip to content

Commit

Permalink
feat(misconf): Support --ignore-policy in config scans (#5359)
Browse files Browse the repository at this point in the history
Signed-off-by: Simar <simar@linux.com>
  • Loading branch information
simar7 committed Oct 23, 2023
1 parent 05b3c86 commit 01c98d1
Show file tree
Hide file tree
Showing 5 changed files with 93 additions and 10 deletions.
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,
},
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"
}

0 comments on commit 01c98d1

Please sign in to comment.