mirror of
https://github.com/aquasecurity/trivy.git
synced 2025-12-12 07:40:48 -08:00
fix(cli): pass integer to exit-on-eol (#3716)
This commit is contained in:
@@ -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")
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
```
|
||||
|
||||
<details>
|
||||
<summary>Result</summary>
|
||||
|
||||
```
|
||||
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
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
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
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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)),
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user