diff --git a/docs/docs/configuration/filtering.md b/docs/docs/configuration/filtering.md index 75e880af4f4..0c661915f95 100644 --- a/docs/docs/configuration/filtering.md +++ b/docs/docs/configuration/filtering.md @@ -422,7 +422,9 @@ Total: 0 (UNKNOWN: 0, LOW: 0, MEDIUM: 0, HIGH: 0, CRITICAL: 0) Rego is part of the popular [Open Policy Agent (OPA)](https://www.openpolicyagent.org) CNCF project. For advanced filtering, Trivy allows you to use Rego language to filter vulnerabilities. -Use the `--ignore-policy` flag which takes a path to a Rego file that defines the filtering policy. +Use the `--ignore-policy` flag which takes a path to a Rego file that defines the filtering policy. The flag can also take +a directory path containing Rego policy files (each `.rego` file found in the directory is applied for the filtering). + The Rego package name must be `trivy` and it must include a "rule" named `ignore` which determines if each individual scan result should be excluded (ignore=true) or not (ignore=false). The `input` for the evaluation is each [DetectedVulnerability](https://github.com/aquasecurity/trivy/blob/00f2059e5d7bc2ca2e3e8b1562bdfede1ed570e3/pkg/types/vulnerability.go#L9) and [DetectedMisconfiguration](https://github.com/aquasecurity/trivy/blob/00f2059e5d7bc2ca2e3e8b1562bdfede1ed570e3/pkg/types/misconfiguration.go#L6). diff --git a/docs/docs/references/configuration/cli/trivy_aws.md b/docs/docs/references/configuration/cli/trivy_aws.md index af1ebc44a83..da644a5905e 100644 --- a/docs/docs/references/configuration/cli/trivy_aws.md +++ b/docs/docs/references/configuration/cli/trivy_aws.md @@ -81,7 +81,7 @@ trivy aws [flags] --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 aws - --ignore-policy string specify the Rego file path to evaluate each vulnerability + --ignore-policy string specify the Rego file path (or dir path with Rego files) to evaluate each vulnerability --ignorefile string specify .trivyignore file (default ".trivyignore") --include-non-failures include successes and exceptions, available with '--scanners misconfig' --list-all-pkgs enabling the option will output all packages regardless of vulnerability diff --git a/docs/docs/references/configuration/cli/trivy_config.md b/docs/docs/references/configuration/cli/trivy_config.md index 865ecb6ba60..d94dfcda176 100644 --- a/docs/docs/references/configuration/cli/trivy_config.md +++ b/docs/docs/references/configuration/cli/trivy_config.md @@ -25,7 +25,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 + --ignore-policy string specify the Rego file path (or dir path with Rego files) to evaluate each vulnerability --ignorefile string specify .trivyignore file (default ".trivyignore") --include-non-failures include successes and exceptions, available with '--scanners misconfig' --k8s-version string specify k8s version to validate outdated api by it (example: 1.21.0) diff --git a/docs/docs/references/configuration/cli/trivy_convert.md b/docs/docs/references/configuration/cli/trivy_convert.md index e8fe589500e..39df91abe31 100644 --- a/docs/docs/references/configuration/cli/trivy_convert.md +++ b/docs/docs/references/configuration/cli/trivy_convert.md @@ -24,7 +24,7 @@ trivy convert [flags] RESULT_JSON --exit-on-eol int exit with the specified code when the OS reaches end of service/life -f, --format string format (table,json,template,sarif,cyclonedx,spdx,spdx-json,github,cosign-vuln) (default "table") -h, --help help for convert - --ignore-policy string specify the Rego file path to evaluate each vulnerability + --ignore-policy string specify the Rego file path (or dir path with Rego files) to evaluate each vulnerability --ignorefile string specify .trivyignore file (default ".trivyignore") --list-all-pkgs enabling the option will output all packages regardless of vulnerability -o, --output string output file name diff --git a/docs/docs/references/configuration/cli/trivy_filesystem.md b/docs/docs/references/configuration/cli/trivy_filesystem.md index e26b26df7bf..b0ded8dae54 100644 --- a/docs/docs/references/configuration/cli/trivy_filesystem.md +++ b/docs/docs/references/configuration/cli/trivy_filesystem.md @@ -40,7 +40,7 @@ trivy filesystem [flags] PATH --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 filesystem - --ignore-policy string specify the Rego file path to evaluate each vulnerability + --ignore-policy string specify the Rego file path (or dir path with Rego files) to evaluate each vulnerability --ignore-status strings comma-separated list of vulnerability status to ignore (unknown,not_affected,affected,fixed,under_investigation,will_not_fix,fix_deferred,end_of_life) --ignore-unfixed display only fixed vulnerabilities --ignored-licenses strings specify a list of license to ignore diff --git a/docs/docs/references/configuration/cli/trivy_image.md b/docs/docs/references/configuration/cli/trivy_image.md index 20be9b45941..71863dad01c 100644 --- a/docs/docs/references/configuration/cli/trivy_image.md +++ b/docs/docs/references/configuration/cli/trivy_image.md @@ -56,7 +56,7 @@ trivy image [flags] IMAGE_NAME --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 image - --ignore-policy string specify the Rego file path to evaluate each vulnerability + --ignore-policy string specify the Rego file path (or dir path with Rego files) to evaluate each vulnerability --ignore-status strings comma-separated list of vulnerability status to ignore (unknown,not_affected,affected,fixed,under_investigation,will_not_fix,fix_deferred,end_of_life) --ignore-unfixed display only fixed vulnerabilities --ignored-licenses strings specify a list of license to ignore diff --git a/docs/docs/references/configuration/cli/trivy_kubernetes.md b/docs/docs/references/configuration/cli/trivy_kubernetes.md index ed22d8299f5..6bd660297f3 100644 --- a/docs/docs/references/configuration/cli/trivy_kubernetes.md +++ b/docs/docs/references/configuration/cli/trivy_kubernetes.md @@ -51,7 +51,7 @@ trivy kubernetes [flags] { cluster | all | specific resources like kubectl. eg: --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 kubernetes - --ignore-policy string specify the Rego file path to evaluate each vulnerability + --ignore-policy string specify the Rego file path (or dir path with Rego files) to evaluate each vulnerability --ignore-status strings comma-separated list of vulnerability status to ignore (unknown,not_affected,affected,fixed,under_investigation,will_not_fix,fix_deferred,end_of_life) --ignore-unfixed display only fixed vulnerabilities --ignorefile string specify .trivyignore file (default ".trivyignore") diff --git a/docs/docs/references/configuration/cli/trivy_repository.md b/docs/docs/references/configuration/cli/trivy_repository.md index 0a2a614e4a5..2cbf37e48ae 100644 --- a/docs/docs/references/configuration/cli/trivy_repository.md +++ b/docs/docs/references/configuration/cli/trivy_repository.md @@ -40,7 +40,7 @@ trivy repository [flags] (REPO_PATH | REPO_URL) --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 repository - --ignore-policy string specify the Rego file path to evaluate each vulnerability + --ignore-policy string specify the Rego file path (or dir path with Rego files) to evaluate each vulnerability --ignore-status strings comma-separated list of vulnerability status to ignore (unknown,not_affected,affected,fixed,under_investigation,will_not_fix,fix_deferred,end_of_life) --ignore-unfixed display only fixed vulnerabilities --ignored-licenses strings specify a list of license to ignore diff --git a/docs/docs/references/configuration/cli/trivy_rootfs.md b/docs/docs/references/configuration/cli/trivy_rootfs.md index 571fb009f4f..0ec8a7a2fa5 100644 --- a/docs/docs/references/configuration/cli/trivy_rootfs.md +++ b/docs/docs/references/configuration/cli/trivy_rootfs.md @@ -43,7 +43,7 @@ trivy rootfs [flags] ROOTDIR --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 rootfs - --ignore-policy string specify the Rego file path to evaluate each vulnerability + --ignore-policy string specify the Rego file path (or dir path with Rego files) to evaluate each vulnerability --ignore-status strings comma-separated list of vulnerability status to ignore (unknown,not_affected,affected,fixed,under_investigation,will_not_fix,fix_deferred,end_of_life) --ignore-unfixed display only fixed vulnerabilities --ignored-licenses strings specify a list of license to ignore diff --git a/docs/docs/references/configuration/cli/trivy_sbom.md b/docs/docs/references/configuration/cli/trivy_sbom.md index 5d941e9744b..727d6e00fbf 100644 --- a/docs/docs/references/configuration/cli/trivy_sbom.md +++ b/docs/docs/references/configuration/cli/trivy_sbom.md @@ -33,7 +33,7 @@ trivy sbom [flags] SBOM_PATH --file-patterns strings specify config file patterns -f, --format string format (table,json,template,sarif,cyclonedx,spdx,spdx-json,github,cosign-vuln) (default "table") -h, --help help for sbom - --ignore-policy string specify the Rego file path to evaluate each vulnerability + --ignore-policy string specify the Rego file path (or dir path with Rego files) to evaluate each vulnerability --ignore-status strings comma-separated list of vulnerability status to ignore (unknown,not_affected,affected,fixed,under_investigation,will_not_fix,fix_deferred,end_of_life) --ignore-unfixed display only fixed vulnerabilities --ignored-licenses strings specify a list of license to ignore diff --git a/docs/docs/references/configuration/cli/trivy_vm.md b/docs/docs/references/configuration/cli/trivy_vm.md index 6acf6606284..2ef66eef893 100644 --- a/docs/docs/references/configuration/cli/trivy_vm.md +++ b/docs/docs/references/configuration/cli/trivy_vm.md @@ -40,7 +40,7 @@ trivy vm [flags] VM_IMAGE --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 vm - --ignore-policy string specify the Rego file path to evaluate each vulnerability + --ignore-policy string specify the Rego file path (or dir path with Rego files) to evaluate each vulnerability --ignore-status strings comma-separated list of vulnerability status to ignore (unknown,not_affected,affected,fixed,under_investigation,will_not_fix,fix_deferred,end_of_life) --ignore-unfixed display only fixed vulnerabilities --ignorefile string specify .trivyignore file (default ".trivyignore") diff --git a/pkg/flag/report_flags.go b/pkg/flag/report_flags.go index 94b8c2ff689..bea5468e3be 100644 --- a/pkg/flag/report_flags.go +++ b/pkg/flag/report_flags.go @@ -65,7 +65,7 @@ var ( IgnorePolicyFlag = Flag[string]{ Name: "ignore-policy", ConfigName: "ignore-policy", - Usage: "specify the Rego file path to evaluate each vulnerability", + Usage: "specify the Rego file path (or dir path with Rego files) to evaluate each vulnerability", } ExitCodeFlag = Flag[int]{ Name: "exit-code", diff --git a/pkg/result/filter.go b/pkg/result/filter.go index 6edcef72046..c13a3ce834c 100644 --- a/pkg/result/filter.go +++ b/pkg/result/filter.go @@ -3,10 +3,12 @@ package result import ( "context" "fmt" + "io/fs" "os" "path/filepath" "sort" + "github.com/open-policy-agent/opa/bundle" "github.com/open-policy-agent/opa/rego" "github.com/samber/lo" "golang.org/x/exp/maps" @@ -14,6 +16,7 @@ import ( "golang.org/x/xerrors" dbTypes "github.com/aquasecurity/trivy-db/pkg/types" + "github.com/aquasecurity/trivy/pkg/log" "github.com/aquasecurity/trivy/pkg/sbom/core" sbomio "github.com/aquasecurity/trivy/pkg/sbom/io" "github.com/aquasecurity/trivy/pkg/types" @@ -69,8 +72,16 @@ func FilterResult(ctx context.Context, result *types.Result, ignoreConf IgnoreCo filterLicenses(result, severities, opt.IgnoreLicenses, ignoreConf) if opt.PolicyFile != "" { - if err := applyPolicy(ctx, result, opt.PolicyFile); err != nil { - return xerrors.Errorf("failed to apply the policy: %w", err) + // Get ignore policy files from the input path (either file or files in dir) + policyFiles, err := findPolicyFiles(opt.PolicyFile) + if err != nil { + return err + } + + for _, policyFile := range policyFiles { + if err := applyPolicy(ctx, result, policyFile); err != nil { + return xerrors.Errorf("failed to apply ignore policy %s: %w", policyFile, err) + } } } sort.Sort(types.BySeverity(result.Vulnerabilities)) @@ -239,6 +250,42 @@ func summarize(status types.MisconfStatus, summary *types.MisconfSummary) { } } +func findPolicyFiles(policiesPath string) ([]string, error) { + fi, err := os.Stat(policiesPath) + if err != nil { + return nil, xerrors.Errorf("failed to analyze ignore policy path %q: %w", policiesPath, err) + } + + // The ignore policy option is a file + if !fi.IsDir() { + return []string{ + policiesPath, + }, nil + } + + // If the ignore policy option is a dir find rego files in it + var files []string + if err = filepath.WalkDir(policiesPath, func(path string, d fs.DirEntry, err error) error { + if err != nil { + return err + } + if !d.Type().IsRegular() || filepath.Ext(path) != bundle.RegoExt { + return nil + } + + files = append(files, path) + return nil + }); err != nil { + return nil, xerrors.Errorf("failed to find policy files in %q: %w", policiesPath, err) + } + + if len(files) == 0 { + log.Logger.Warnf("No ignore policies found in %q", policiesPath) + } + + return files, nil +} + func applyPolicy(ctx context.Context, result *types.Result, policyFile string) error { policy, err := os.ReadFile(policyFile) if err != nil { diff --git a/pkg/result/filter_test.go b/pkg/result/filter_test.go index d98048c6af1..a88b980e7db 100644 --- a/pkg/result/filter_test.go +++ b/pkg/result/filter_test.go @@ -713,6 +713,71 @@ func TestFilter(t *testing.T) { }, }, }, + { + name: "ignore policy directory", + args: args{ + report: types.Report{ + Results: types.Results{ + { + Vulnerabilities: []types.DetectedVulnerability{ + vuln1, + vuln3, // ignored by policy + vuln4, // ignored by policy + }, + Misconfigurations: []types.DetectedMisconfiguration{ + misconf1, + misconf3, // ignored by policy + }, + }, + }, + }, + severities: []dbTypes.Severity{ + dbTypes.SeverityLow, + dbTypes.SeverityHigh, + }, + policyFile: "./testdata/ignore-dir", + }, + want: types.Report{ + Results: types.Results{ + { + Vulnerabilities: []types.DetectedVulnerability{ + vuln1, + }, + MisconfSummary: &types.MisconfSummary{ + Successes: 0, + Failures: 1, + Exceptions: 1, + }, + Misconfigurations: []types.DetectedMisconfiguration{ + misconf1, + }, + ModifiedFindings: []types.ModifiedFinding{ + { + Type: types.FindingTypeMisconfiguration, + Status: types.FindingStatusIgnored, + Statement: "Filtered by Rego", + Source: "testdata/ignore-dir/ignore-misconf.rego", + Finding: misconf3, + }, + { + Type: types.FindingTypeVulnerability, + Status: types.FindingStatusIgnored, + Statement: "Filtered by Rego", + Source: "testdata/ignore-dir/ignore-vuln.rego", + Finding: vuln3, + }, + { + Type: types.FindingTypeVulnerability, + Status: types.FindingStatusIgnored, + Statement: "Filtered by Rego", + Source: "testdata/ignore-dir/ignore-vuln.rego", + Finding: vuln4, + }, + }, + }, + }, + }, + }, { name: "happy path with duplicates, one with empty fixed version", args: args{ diff --git a/pkg/result/testdata/ignore-dir/ignore-misconf.rego b/pkg/result/testdata/ignore-dir/ignore-misconf.rego new file mode 100644 index 00000000000..1aa5062ddf2 --- /dev/null +++ b/pkg/result/testdata/ignore-dir/ignore-misconf.rego @@ -0,0 +1,9 @@ +package trivy + +import data.lib.trivy + +default ignore=false + +ignore { + input.AVDID != "AVD-ID100" +} diff --git a/pkg/result/testdata/ignore-dir/ignore-vuln.rego b/pkg/result/testdata/ignore-dir/ignore-vuln.rego new file mode 100644 index 00000000000..3940166eecb --- /dev/null +++ b/pkg/result/testdata/ignore-dir/ignore-vuln.rego @@ -0,0 +1,9 @@ +package trivy + +import data.lib.trivy + +default ignore=false + +ignore { + input.VulnerabilityID != "CVE-2019-0001" +}