diff --git a/docs/docs/references/cli/client.md b/docs/docs/references/cli/client.md index 222aeee26e..76775b44d3 100644 --- a/docs/docs/references/cli/client.md +++ b/docs/docs/references/cli/client.md @@ -16,7 +16,7 @@ Scan Flags Report Flags --dependency-tree show dependency origin tree (EXPERIMENTAL) --exit-code int specify exit code when any security issues are found - --exit-on-eosl exit with the specified code when the os of image ends of service/life + --exit-on-eol int exit with the specified code when the os of image ends of service/life -f, --format string format (table, json, sarif, template, cyclonedx, spdx, spdx-json, github, cosign-vuln) (default "table") --ignore-policy string specify the Rego file path to evaluate each vulnerability --ignorefile string specify .trivyignore file (default ".trivyignore") diff --git a/docs/docs/references/cli/image.md b/docs/docs/references/cli/image.md index 7d5824031b..107ea1f1af 100644 --- a/docs/docs/references/cli/image.md +++ b/docs/docs/references/cli/image.md @@ -39,7 +39,7 @@ Scan Flags Report Flags --exit-code int specify exit code when any security issues are found - --exit-on-eosl exit with the specified code when the os of image ends of service/life + --exit-on-eol int exit with the specified code when the os of image ends of service/life -f, --format string format (table, json, sarif, template, cyclonedx, spdx, spdx-json, github, cosign-vuln) (default "table") --ignore-policy string specify the Rego file path to evaluate each vulnerability --ignorefile string specify .trivyignore file (default ".trivyignore") diff --git a/docs/docs/references/customization/config-file.md b/docs/docs/references/customization/config-file.md index f76433f044..98b98d2c73 100644 --- a/docs/docs/references/customization/config-file.md +++ b/docs/docs/references/customization/config-file.md @@ -63,9 +63,9 @@ ignore-policy: # Default is 0 exit-code: 0 -# Same as '--exit-on-eosl' -# Default is false -exit-on-eosl: false +# Same as '--exit-on-eol' +# Default is 0 +exit-on-eol: 0 # Same as '--output' # Default is empty (stdout) diff --git a/docs/docs/vulnerability/examples/others.md b/docs/docs/vulnerability/examples/others.md index 49f365817e..54badff727 100644 --- a/docs/docs/vulnerability/examples/others.md +++ b/docs/docs/vulnerability/examples/others.md @@ -68,14 +68,14 @@ $ trivy image --exit-code 0 --severity MEDIUM,HIGH ruby:2.4.0 $ trivy image --exit-code 1 --severity CRITICAL ruby:2.4.0 ``` -## Exit on EOSL +## Exit on EOL Sometimes you may surprisingly get 0 vulnerabilities in an old image: - Enabling `--ignore-unfixed` option while all packages have no fixed versions. - Scanning a rather outdated OS (e.g. Ubuntu 10.04). -An OS at the end of service/life (EOSL) usually gets into this situation, which is definitely full of vulnerabilities. -Use the `exit-on-eosl` option accompanied by `exit-code` option to exit with a non-zero code. +An OS at the end of service/life (EOL) usually gets into this situation, which is definitely full of vulnerabilities. +`--exit-on-eol` can fail scanning on EOL OS with a non-zero code. This flag is available with the following targets. - Container images (`trivy image`) @@ -84,27 +84,39 @@ This flag is available with the following targets. - Root filesystem (`trivy rootfs`) ``` -$ trivy image --exit-code 1 --exit-on-eosl testbeds/ubuntu:10.04 +$ trivy image --exit-on-eol 1 alpine:3.10 ```
Result ``` -2023-01-19T22:05:54.358+0800 WARN This OS version is no longer supported by the distribution: ubuntu 10.04 -2023-01-19T22:05:54.358+0800 WARN The vulnerability detection may be insufficient because security updates are not provided +2023-03-01T11:07:15.455+0200 INFO Vulnerability scanning is enabled +... +2023-03-01T11:07:17.938+0200 WARN This OS version is no longer supported by the distribution: alpine 3.10.9 +2023-03-01T11:07:17.938+0200 WARN The vulnerability detection may be insufficient because security updates are not provided -testbeds/ubuntu:10.04 (ubuntu 10.04) -==================================== -Total: 0 (UNKNOWN: 0, LOW: 0, MEDIUM: 0, HIGH: 0, CRITICAL: 0) +alpine:3.10 (alpine 3.10.9) +=========================== +Total: 1 (UNKNOWN: 0, LOW: 0, MEDIUM: 0, HIGH: 0, CRITICAL: 1) + +┌───────────┬────────────────┬──────────┬───────────────────┬───────────────┬─────────────────────────────────────────────────────────────┐ +│ Library │ Vulnerability │ Severity │ Installed Version │ Fixed Version │ Title │ +├───────────┼────────────────┼──────────┼───────────────────┼───────────────┼─────────────────────────────────────────────────────────────┤ +│ apk-tools │ CVE-2021-36159 │ CRITICAL │ 2.10.6-r0 │ 2.10.7-r0 │ libfetch before 2021-07-26, as used in apk-tools, xbps, and │ +│ │ │ │ │ │ other products, mishandles... │ +│ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2021-36159 │ +└───────────┴────────────────┴──────────┴───────────────────┴───────────────┴─────────────────────────────────────────────────────────────┘ +2023-03-01T11:07:17.941+0200 ERROR Detected EOL OS: alpine 3.10.9 ```
-This option is useful for CI/CD. The following example will fail when a critical vulnerability is found or the OS is EOSL: +This option is useful for CI/CD. +The following example will fail when a critical vulnerability is found or the OS is EOSL: ``` -$ ./trivy image --exit-code 1 --exit-on-eosl --severity CRITICAL alpine:3.16.3 +$ trivy image --exit-code 1 --exit-on-eol 1 --severity CRITICAL alpine:3.16.3 ``` ## Reset diff --git a/pkg/commands/app.go b/pkg/commands/app.go index b4f9af076e..b59403461c 100644 --- a/pkg/commands/app.go +++ b/pkg/commands/app.go @@ -291,7 +291,7 @@ func NewFilesystemCommand(globalFlags *flag.GlobalFlagGroup) *cobra.Command { reportFlagGroup := flag.NewReportFlagGroup() reportFlagGroup.ReportFormat = nil // TODO: support --report summary reportFlagGroup.Compliance = nil // disable '--compliance' - reportFlagGroup.ExitOnEOSL = nil // disable '--exit-on-eosl' + reportFlagGroup.ExitOnEOL = nil // disable '--exit-on-eol' fsFlags := &flag.Flags{ CacheFlagGroup: flag.NewCacheFlagGroup(), @@ -403,7 +403,7 @@ func NewRepositoryCommand(globalFlags *flag.GlobalFlagGroup) *cobra.Command { reportFlagGroup := flag.NewReportFlagGroup() reportFlagGroup.ReportFormat = nil // TODO: support --report summary reportFlagGroup.Compliance = nil // disable '--compliance' - reportFlagGroup.ExitOnEOSL = nil // disable '--exit-on-eosl' + reportFlagGroup.ExitOnEOL = nil // disable '--exit-on-eol' repoFlags := &flag.Flags{ CacheFlagGroup: flag.NewCacheFlagGroup(), @@ -553,7 +553,7 @@ func NewConfigCommand(globalFlags *flag.GlobalFlagGroup) *cobra.Command { reportFlagGroup.ListAllPkgs = nil // disable '--list-all-pkgs' reportFlagGroup.ReportFormat = nil // TODO: support --report summary reportFlagGroup.Compliance = nil // disable '--compliance' - reportFlagGroup.ExitOnEOSL = nil // disable '--exit-on-eosl' + reportFlagGroup.ExitOnEOL = nil // disable '--exit-on-eol' scanFlags := &flag.ScanFlagGroup{ // Enable only '--skip-dirs' and '--skip-files' and disable other flags @@ -798,7 +798,7 @@ func NewKubernetesCommand(globalFlags *flag.GlobalFlagGroup) *cobra.Command { compliance := flag.ComplianceFlag compliance.Usage += fmt.Sprintf(" (%s,%s, %s, %s)", types.ComplianceK8sNsa, types.ComplianceK8sCIS, types.ComplianceK8sPSSBaseline, types.ComplianceK8sPSSRestricted) reportFlagGroup.Compliance = &compliance // override usage as the accepted values differ for each subcommand. - reportFlagGroup.ExitOnEOSL = nil // disable '--exit-on-eosl' + reportFlagGroup.ExitOnEOL = nil // disable '--exit-on-eol' k8sFlags := &flag.Flags{ CacheFlagGroup: flag.NewCacheFlagGroup(), @@ -861,7 +861,7 @@ func NewAWSCommand(globalFlags *flag.GlobalFlagGroup) *cobra.Command { compliance := flag.ComplianceFlag compliance.Usage += fmt.Sprintf(" (%s, %s)", types.ComplianceAWSCIS12, types.ComplianceAWSCIS14) reportFlagGroup.Compliance = &compliance // override usage as the accepted values differ for each subcommand. - reportFlagGroup.ExitOnEOSL = nil // disable '--exit-on-eosl' + reportFlagGroup.ExitOnEOL = nil // disable '--exit-on-eol' awsFlags := &flag.Flags{ AWSFlagGroup: flag.NewAWSFlagGroup(), diff --git a/pkg/commands/artifact/run.go b/pkg/commands/artifact/run.go index aadd88e346..24be95513c 100644 --- a/pkg/commands/artifact/run.go +++ b/pkg/commands/artifact/run.go @@ -457,7 +457,7 @@ func Run(ctx context.Context, opts flag.Options, targetKind TargetKind) (err err return xerrors.Errorf("report error: %w", err) } - exitOnEosl(opts, report.Metadata) + exitOnEOL(opts, report.Metadata) Exit(opts, report.Results.Failed()) return nil @@ -668,9 +668,10 @@ func Exit(opts flag.Options, failedResults bool) { } } -func exitOnEosl(opts flag.Options, m types.Metadata) { - if opts.ReportOptions.ExitOnEOSL && m.OS != nil && m.OS.Eosl { - Exit(opts, true) +func exitOnEOL(opts flag.Options, m types.Metadata) { + if opts.ExitOnEOL != 0 && m.OS != nil && m.OS.Eosl { + log.Logger.Errorf("Detected EOL OS: %s %s", m.OS.Family, m.OS.Name) + os.Exit(opts.ExitOnEOL) } } diff --git a/pkg/flag/report_flags.go b/pkg/flag/report_flags.go index a68e9ba418..7023ec5a5a 100644 --- a/pkg/flag/report_flags.go +++ b/pkg/flag/report_flags.go @@ -72,11 +72,11 @@ var ( Value: 0, Usage: "specify exit code when any security issues are found", } - ExitOnEOSLFlag = Flag{ - Name: "exit-on-eosl", - ConfigName: "exit-on-eosl", - Value: false, - Usage: "exit with the specified code when the os of image ends of service/life", + ExitOnEOLFlag = Flag{ + Name: "exit-on-eol", + ConfigName: "exit-on-eol", + Value: 0, + Usage: "exit with the specified code when the OS reaches end of service/life", } OutputFlag = Flag{ Name: "output", @@ -111,7 +111,7 @@ type ReportFlagGroup struct { IgnoreFile *Flag IgnorePolicy *Flag ExitCode *Flag - ExitOnEOSL *Flag + ExitOnEOL *Flag Output *Flag Severity *Flag Compliance *Flag @@ -125,7 +125,7 @@ type ReportOptions struct { ListAllPkgs bool IgnoreFile string ExitCode int - ExitOnEOSL bool + ExitOnEOL int IgnorePolicy string Output io.Writer Severities []dbTypes.Severity @@ -142,7 +142,7 @@ func NewReportFlagGroup() *ReportFlagGroup { IgnoreFile: &IgnoreFileFlag, IgnorePolicy: &IgnorePolicyFlag, ExitCode: &ExitCodeFlag, - ExitOnEOSL: &ExitOnEOSLFlag, + ExitOnEOL: &ExitOnEOLFlag, Output: &OutputFlag, Severity: &SeverityFlag, Compliance: &ComplianceFlag, @@ -163,7 +163,7 @@ func (f *ReportFlagGroup) Flags() []*Flag { f.IgnoreFile, f.IgnorePolicy, f.ExitCode, - f.ExitOnEOSL, + f.ExitOnEOL, f.Output, f.Severity, f.Compliance, @@ -171,18 +171,12 @@ func (f *ReportFlagGroup) Flags() []*Flag { } func (f *ReportFlagGroup) ToOptions(out io.Writer) (ReportOptions, error) { - exitCode := getInt(f.ExitCode) - exitOnEOSL := getBool(f.ExitOnEOSL) format := getString(f.Format) template := getString(f.Template) dependencyTree := getBool(f.DependencyTree) listAllPkgs := getBool(f.ListAllPkgs) output := getString(f.Output) - if exitOnEOSL && exitCode == 0 { - log.Logger.Warn("'--exit-on-eosl' is ignored because '--exit-code' is 0 or not specified. Use '--exit-on-eosl' option with non-zero '--exit-code' option.") - } - if format != "" && !slices.Contains(report.SupportedFormats, format) { return ReportOptions{}, xerrors.Errorf("unknown format: %v", format) } @@ -239,8 +233,8 @@ func (f *ReportFlagGroup) ToOptions(out io.Writer) (ReportOptions, error) { DependencyTree: dependencyTree, ListAllPkgs: listAllPkgs, IgnoreFile: getString(f.IgnoreFile), - ExitCode: exitCode, - ExitOnEOSL: exitOnEOSL, + ExitCode: getInt(f.ExitCode), + ExitOnEOL: getInt(f.ExitOnEOL), IgnorePolicy: getString(f.IgnorePolicy), Output: out, Severities: splitSeverity(getStringSlice(f.Severity)), diff --git a/pkg/flag/report_flags_test.go b/pkg/flag/report_flags_test.go index a8257015b9..17397f453d 100644 --- a/pkg/flag/report_flags_test.go +++ b/pkg/flag/report_flags_test.go @@ -203,20 +203,6 @@ func TestReportFlagGroup_ToOptions(t *testing.T) { Severities: []dbTypes.Severity{dbTypes.SeverityLow}, }, }, - { - name: "invalid option combination: --exit-code 0 with --exit-on-eosl", - fields: fields{ - exitCode: 0, - exitOnEOSL: true, - }, - wantLogs: []string{ - "'--exit-on-eosl' is ignored because '--exit-code' is 0 or not specified. Use '--exit-on-eosl' option with non-zero '--exit-code' option.", - }, - want: flag.ReportOptions{ - Output: os.Stdout, - ExitOnEOSL: true, - }, - }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -235,7 +221,7 @@ func TestReportFlagGroup_ToOptions(t *testing.T) { viper.Set(flag.IgnoreUnfixedFlag.ConfigName, tt.fields.ignoreUnfixed) viper.Set(flag.IgnorePolicyFlag.ConfigName, tt.fields.ignorePolicy) viper.Set(flag.ExitCodeFlag.ConfigName, tt.fields.exitCode) - viper.Set(flag.ExitOnEOSLFlag.ConfigName, tt.fields.exitOnEOSL) + viper.Set(flag.ExitOnEOLFlag.ConfigName, tt.fields.exitOnEOSL) viper.Set(flag.OutputFlag.ConfigName, tt.fields.output) viper.Set(flag.SeverityFlag.ConfigName, tt.fields.severities) viper.Set(flag.ComplianceFlag.ConfigName, tt.fields.compliane) @@ -249,7 +235,7 @@ func TestReportFlagGroup_ToOptions(t *testing.T) { IgnoreFile: &flag.IgnoreFileFlag, IgnorePolicy: &flag.IgnorePolicyFlag, ExitCode: &flag.ExitCodeFlag, - ExitOnEOSL: &flag.ExitOnEOSLFlag, + ExitOnEOL: &flag.ExitOnEOLFlag, Output: &flag.OutputFlag, Severity: &flag.SeverityFlag, Compliance: &flag.ComplianceFlag,