mirror of
https://github.com/aquasecurity/trivy.git
synced 2025-12-21 23:00:42 -08:00
refactor: add allowed values for CLI flags (#4800)
* refactor: rename Value to Default * refactor: support allowed values for CLI flags * docs: auto-generate * test: fix * test: add tests for flags
This commit is contained in:
@@ -87,10 +87,10 @@ trivy aws [flags]
|
||||
-o, --output string output file name
|
||||
--policy-namespaces strings Rego namespaces
|
||||
--region string AWS Region to scan
|
||||
--report string specify a report format for the output. (all,summary) (default "all")
|
||||
--report string specify a report format for the output (all,summary) (default "all")
|
||||
--reset-policy-bundle remove policy bundle
|
||||
--service strings Only scan AWS Service(s) specified with this flag. Can specify multiple services using --service A --service B etc.
|
||||
-s, --severity string severities of security issues to be displayed (comma separated) (default "UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL")
|
||||
-s, --severity strings severities of security issues to be displayed (UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL) (default [UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL])
|
||||
--skip-policy-update skip fetching rego policy updates
|
||||
--skip-service strings Skip selected AWS Service(s) specified with this flag. Can specify multiple services using --skip-service A --skip-service B etc.
|
||||
-t, --template string output template
|
||||
|
||||
@@ -36,9 +36,9 @@ trivy config [flags] DIR
|
||||
--redis-key string redis key file location, if using redis as cache backend
|
||||
--redis-tls enable redis TLS with public certificates, if using redis as cache backend
|
||||
--registry-token string registry token
|
||||
--report string specify a compliance report format for the output. (all,summary) (default "all")
|
||||
--report string specify a compliance report format for the output (all,summary) (default "all")
|
||||
--reset-policy-bundle remove policy bundle
|
||||
-s, --severity string severities of security issues to be displayed (comma separated) (default "UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL")
|
||||
-s, --severity strings severities of security issues to be displayed (UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL) (default [UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL])
|
||||
--skip-dirs strings specify the directories where the traversal is skipped
|
||||
--skip-files strings specify the file paths to skip traversal
|
||||
--skip-policy-update skip fetching rego policy updates
|
||||
|
||||
@@ -28,8 +28,8 @@ trivy convert [flags] RESULT_JSON
|
||||
--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
|
||||
--report string specify a report format for the output. (all,summary) (default "all")
|
||||
-s, --severity string severities of security issues to be displayed (comma separated) (default "UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL")
|
||||
--report string specify a report format for the output (all,summary) (default "all")
|
||||
-s, --severity strings severities of security issues to be displayed (UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL) (default [UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL])
|
||||
-t, --template string output template
|
||||
```
|
||||
|
||||
|
||||
@@ -61,14 +61,14 @@ trivy filesystem [flags] PATH
|
||||
--redis-tls enable redis TLS with public certificates, if using redis as cache backend
|
||||
--registry-token string registry token
|
||||
--rekor-url string [EXPERIMENTAL] address of rekor STL server (default "https://rekor.sigstore.dev")
|
||||
--report string specify a compliance report format for the output. (all,summary) (default "all")
|
||||
--report string specify a compliance report format for the output (all,summary) (default "all")
|
||||
--reset remove all caches and database
|
||||
--reset-policy-bundle remove policy bundle
|
||||
--sbom-sources strings [EXPERIMENTAL] try to retrieve SBOM from the specified sources (oci,rekor)
|
||||
--scanners strings comma-separated list of what security issues to detect (vuln,config,secret,license) (default [vuln,secret])
|
||||
--secret-config string specify a path to config file for secret scanning (default "trivy-secret.yaml")
|
||||
--server string server address in client mode
|
||||
-s, --severity string severities of security issues to be displayed (comma separated) (default "UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL")
|
||||
-s, --severity strings severities of security issues to be displayed (UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL) (default [UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL])
|
||||
--skip-db-update skip updating vulnerability database
|
||||
--skip-dirs strings specify the directories where the traversal is skipped
|
||||
--skip-files strings specify the file paths to skip traversal
|
||||
|
||||
@@ -60,7 +60,7 @@ trivy image [flags] IMAGE_NAME
|
||||
--ignore-unfixed display only fixed vulnerabilities
|
||||
--ignored-licenses strings specify a list of license to ignore
|
||||
--ignorefile string specify .trivyignore file (default ".trivyignore")
|
||||
--image-config-scanners string comma-separated list of what security issues to detect on container image configurations (config,secret)
|
||||
--image-config-scanners strings comma-separated list of what security issues to detect on container image configurations (config,secret)
|
||||
--image-src strings image source(s) to use, in priority order (docker,containerd,podman,remote) (default [docker,containerd,podman,remote])
|
||||
--include-non-failures include successes and exceptions, available with '--scanners config'
|
||||
--input string input file path instead of image name
|
||||
@@ -82,14 +82,14 @@ trivy image [flags] IMAGE_NAME
|
||||
--registry-token string registry token
|
||||
--rekor-url string [EXPERIMENTAL] address of rekor STL server (default "https://rekor.sigstore.dev")
|
||||
--removed-pkgs detect vulnerabilities of removed packages (only for Alpine)
|
||||
--report string specify a format for the compliance report. (default "summary")
|
||||
--report string specify a format for the compliance report. (all,summary) (default "summary")
|
||||
--reset remove all caches and database
|
||||
--reset-policy-bundle remove policy bundle
|
||||
--sbom-sources strings [EXPERIMENTAL] try to retrieve SBOM from the specified sources (oci,rekor)
|
||||
--scanners strings comma-separated list of what security issues to detect (vuln,config,secret,license) (default [vuln,secret])
|
||||
--secret-config string specify a path to config file for secret scanning (default "trivy-secret.yaml")
|
||||
--server string server address in client mode
|
||||
-s, --severity string severities of security issues to be displayed (comma separated) (default "UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL")
|
||||
-s, --severity strings severities of security issues to be displayed (UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL) (default [UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL])
|
||||
--skip-db-update skip updating vulnerability database
|
||||
--skip-dirs strings specify the directories where the traversal is skipped
|
||||
--skip-files strings specify the file paths to skip traversal
|
||||
|
||||
@@ -32,7 +32,7 @@ trivy kubernetes [flags] { cluster | all | specific resources like kubectl. eg:
|
||||
--cache-ttl duration cache TTL when using redis as cache backend
|
||||
--clear-cache clear image caches without scanning
|
||||
--compliance string compliance report to generate (k8s-nsa,k8s-cis,k8s-pss-baseline,k8s-pss-restricted)
|
||||
--components strings specify which components to scan (default [workload,infra])
|
||||
--components strings specify which components to scan (workload,infra) (default [workload,infra])
|
||||
--config-data strings specify paths from which data for the Rego policies will be recursively loaded
|
||||
--config-policy strings specify the paths to the Rego policy files or to the directories containing them, applying config files
|
||||
--context string specify a context to scan
|
||||
@@ -72,13 +72,13 @@ trivy kubernetes [flags] { cluster | all | specific resources like kubectl. eg:
|
||||
--redis-tls enable redis TLS with public certificates, if using redis as cache backend
|
||||
--registry-token string registry token
|
||||
--rekor-url string [EXPERIMENTAL] address of rekor STL server (default "https://rekor.sigstore.dev")
|
||||
--report string specify a report format for the output. (all,summary) (default "all")
|
||||
--report string specify a report format for the output (all,summary) (default "all")
|
||||
--reset remove all caches and database
|
||||
--reset-policy-bundle remove policy bundle
|
||||
--sbom-sources strings [EXPERIMENTAL] try to retrieve SBOM from the specified sources (oci,rekor)
|
||||
--scanners string comma-separated list of what security issues to detect (vuln,config,secret,license) (default "vuln,config,secret,rbac")
|
||||
--secret-config string specify a path to config file for secret scanning (default "trivy-secret.yaml")
|
||||
-s, --severity string severities of security issues to be displayed (comma separated) (default "UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL")
|
||||
-s, --severity strings severities of security issues to be displayed (UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL) (default [UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL])
|
||||
--skip-db-update skip updating vulnerability database
|
||||
--skip-dirs strings specify the directories where the traversal is skipped
|
||||
--skip-files strings specify the file paths to skip traversal
|
||||
|
||||
@@ -64,7 +64,7 @@ trivy repository [flags] REPO_URL
|
||||
--scanners strings comma-separated list of what security issues to detect (vuln,config,secret,license) (default [vuln,secret])
|
||||
--secret-config string specify a path to config file for secret scanning (default "trivy-secret.yaml")
|
||||
--server string server address in client mode
|
||||
-s, --severity string severities of security issues to be displayed (comma separated) (default "UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL")
|
||||
-s, --severity strings severities of security issues to be displayed (UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL) (default [UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL])
|
||||
--skip-db-update skip updating vulnerability database
|
||||
--skip-dirs strings specify the directories where the traversal is skipped
|
||||
--skip-files strings specify the file paths to skip traversal
|
||||
|
||||
@@ -69,7 +69,7 @@ trivy rootfs [flags] ROOTDIR
|
||||
--scanners strings comma-separated list of what security issues to detect (vuln,config,secret,license) (default [vuln,secret])
|
||||
--secret-config string specify a path to config file for secret scanning (default "trivy-secret.yaml")
|
||||
--server string server address in client mode
|
||||
-s, --severity string severities of security issues to be displayed (comma separated) (default "UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL")
|
||||
-s, --severity strings severities of security issues to be displayed (UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL) (default [UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL])
|
||||
--skip-db-update skip updating vulnerability database
|
||||
--skip-dirs strings specify the directories where the traversal is skipped
|
||||
--skip-files strings specify the file paths to skip traversal
|
||||
|
||||
@@ -49,7 +49,7 @@ trivy sbom [flags] SBOM_PATH
|
||||
--reset remove all caches and database
|
||||
--sbom-sources strings [EXPERIMENTAL] try to retrieve SBOM from the specified sources (oci,rekor)
|
||||
--server string server address in client mode
|
||||
-s, --severity string severities of security issues to be displayed (comma separated) (default "UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL")
|
||||
-s, --severity strings severities of security issues to be displayed (UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL) (default [UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL])
|
||||
--skip-db-update skip updating vulnerability database
|
||||
--skip-dirs strings specify the directories where the traversal is skipped
|
||||
--skip-files strings specify the file paths to skip traversal
|
||||
|
||||
@@ -61,7 +61,7 @@ trivy vm [flags] VM_IMAGE
|
||||
--scanners strings comma-separated list of what security issues to detect (vuln,config,secret,license) (default [vuln,secret])
|
||||
--secret-config string specify a path to config file for secret scanning (default "trivy-secret.yaml")
|
||||
--server string server address in client mode
|
||||
-s, --severity string severities of security issues to be displayed (comma separated) (default "UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL")
|
||||
-s, --severity strings severities of security issues to be displayed (UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL) (default [UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL])
|
||||
--skip-db-update skip updating vulnerability database
|
||||
--skip-dirs strings specify the directories where the traversal is skipped
|
||||
--skip-files strings specify the file paths to skip traversal
|
||||
|
||||
6
go.mod
6
go.mod
@@ -94,7 +94,7 @@ require (
|
||||
go.etcd.io/bbolt v1.3.7
|
||||
go.uber.org/zap v1.24.0
|
||||
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1
|
||||
golang.org/x/mod v0.11.0
|
||||
golang.org/x/mod v0.12.0
|
||||
golang.org/x/sync v0.3.0
|
||||
golang.org/x/term v0.9.0
|
||||
golang.org/x/text v0.10.0
|
||||
@@ -359,9 +359,9 @@ require (
|
||||
golang.org/x/crypto v0.10.0 // indirect
|
||||
golang.org/x/net v0.11.0 // indirect
|
||||
golang.org/x/oauth2 v0.7.0 // indirect
|
||||
golang.org/x/sys v0.9.0 // indirect
|
||||
golang.org/x/sys v0.10.0 // indirect
|
||||
golang.org/x/time v0.3.0 // indirect
|
||||
golang.org/x/tools v0.8.0 // indirect
|
||||
golang.org/x/tools v0.10.0 // indirect
|
||||
google.golang.org/api v0.121.0 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect
|
||||
|
||||
12
go.sum
12
go.sum
@@ -1840,8 +1840,8 @@ golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.11.0 h1:bUO06HqtnRcc/7l71XBe4WcqTZ+3AH1J59zWDDwLKgU=
|
||||
golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc=
|
||||
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180811021610-c39426892332/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
@@ -2093,8 +2093,8 @@ golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.9.0 h1:KS/R3tvhPqvJvwcKfnBHJwwthS11LRhmM5D59eEXa0s=
|
||||
golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA=
|
||||
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
@@ -2197,8 +2197,8 @@ golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyj
|
||||
golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/tools v0.8.0 h1:vSDcovVPld282ceKgDimkRSC8kpaH1dgyc9UMzlt84Y=
|
||||
golang.org/x/tools v0.8.0/go.mod h1:JxBZ99ISMI5ViVkT1tr6tdNmXeTrcpVSD3vZ1RsRdN4=
|
||||
golang.org/x/tools v0.10.0 h1:tvDr/iQoUqNdohiYm0LmmKcBk+q86lb9EprIUFhHHGg=
|
||||
golang.org/x/tools v0.10.0/go.mod h1:UJwyiVBsOA2uwvK/e5OY3GTpDUJriEd+/YlqAwLPmyM=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
|
||||
@@ -17,8 +17,8 @@ func main() {
|
||||
log.Fatal(err)
|
||||
}
|
||||
// Set a dummy path for the documents
|
||||
flag.CacheDirFlag.Value = "/path/to/cache"
|
||||
flag.ModuleDirFlag.Value = "$HOME/.trivy/modules"
|
||||
flag.CacheDirFlag.Default = "/path/to/cache"
|
||||
flag.ModuleDirFlag.Default = "$HOME/.trivy/modules"
|
||||
|
||||
cmd := commands.NewApp(ver)
|
||||
cmd.DisableAutoGenTag = true
|
||||
|
||||
@@ -246,12 +246,12 @@ func NewImageCommand(globalFlags *flag.GlobalFlagGroup) *cobra.Command {
|
||||
|
||||
reportFlagGroup := flag.NewReportFlagGroup()
|
||||
report := flag.ReportFormatFlag
|
||||
report.Value = "summary" // override the default value as the summary is preferred for the compliance report
|
||||
report.Default = "summary" // override the default value as the summary is preferred for the compliance report
|
||||
report.Usage = "specify a format for the compliance report." // "--report" works only with "--compliance"
|
||||
reportFlagGroup.ReportFormat = &report
|
||||
|
||||
compliance := flag.ComplianceFlag
|
||||
compliance.Usage += fmt.Sprintf(" (%s)", types.ComplianceDockerCIS)
|
||||
compliance.Values = []string{types.ComplianceDockerCIS}
|
||||
reportFlagGroup.Compliance = &compliance // override usage as the accepted values differ for each subcommand.
|
||||
|
||||
imageFlags := &flag.Flags{
|
||||
@@ -330,7 +330,7 @@ func NewImageCommand(globalFlags *flag.GlobalFlagGroup) *cobra.Command {
|
||||
func NewFilesystemCommand(globalFlags *flag.GlobalFlagGroup) *cobra.Command {
|
||||
reportFlagGroup := flag.NewReportFlagGroup()
|
||||
reportFormat := flag.ReportFormatFlag
|
||||
reportFormat.Usage = "specify a compliance report format for the output. (all,summary)" //@TODO: support --report summary for non compliance reports
|
||||
reportFormat.Usage = "specify a compliance report format for the output" //@TODO: support --report summary for non compliance reports
|
||||
reportFlagGroup.ReportFormat = &reportFormat
|
||||
reportFlagGroup.ExitOnEOL = nil // disable '--exit-on-eol'
|
||||
|
||||
@@ -546,7 +546,7 @@ func NewClientCommand(globalFlags *flag.GlobalFlagGroup) *cobra.Command {
|
||||
Name: "remote",
|
||||
ConfigName: "server.addr",
|
||||
Shorthand: "",
|
||||
Value: "http://localhost:4954",
|
||||
Default: "http://localhost:4954",
|
||||
Usage: "server address",
|
||||
}
|
||||
remoteFlags.ServerAddr = &remoteAddr // disable '--server' and enable '--remote' instead.
|
||||
@@ -643,7 +643,7 @@ func NewConfigCommand(globalFlags *flag.GlobalFlagGroup) *cobra.Command {
|
||||
reportFlagGroup.ListAllPkgs = nil // disable '--list-all-pkgs'
|
||||
reportFlagGroup.ExitOnEOL = nil // disable '--exit-on-eol'
|
||||
reportFormat := flag.ReportFormatFlag
|
||||
reportFormat.Usage = "specify a compliance report format for the output. (all,summary)" //@TODO: support --report summary for non compliance reports
|
||||
reportFormat.Usage = "specify a compliance report format for the output" //@TODO: support --report summary for non compliance reports
|
||||
reportFlagGroup.ReportFormat = &reportFormat
|
||||
|
||||
scanFlags := &flag.ScanFlagGroup{
|
||||
@@ -880,7 +880,7 @@ func NewModuleCommand(globalFlags *flag.GlobalFlagGroup) *cobra.Command {
|
||||
func NewKubernetesCommand(globalFlags *flag.GlobalFlagGroup) *cobra.Command {
|
||||
scanFlags := flag.NewScanFlagGroup()
|
||||
scanners := flag.ScannersFlag
|
||||
scanners.Value = fmt.Sprintf( // overwrite the default value
|
||||
scanners.Default = fmt.Sprintf( // overwrite the default value
|
||||
"%s,%s,%s,%s",
|
||||
types.VulnerabilityScanner,
|
||||
types.MisconfigScanner,
|
||||
@@ -895,16 +895,21 @@ func NewKubernetesCommand(globalFlags *flag.GlobalFlagGroup) *cobra.Command {
|
||||
|
||||
reportFlagGroup := flag.NewReportFlagGroup()
|
||||
compliance := flag.ComplianceFlag
|
||||
compliance.Usage += fmt.Sprintf(" (%s,%s, %s, %s)", types.ComplianceK8sNsa, types.ComplianceK8sCIS, types.ComplianceK8sPSSBaseline, types.ComplianceK8sPSSRestricted)
|
||||
compliance.Values = []string{
|
||||
types.ComplianceK8sNsa,
|
||||
types.ComplianceK8sCIS,
|
||||
types.ComplianceK8sPSSBaseline,
|
||||
types.ComplianceK8sPSSRestricted,
|
||||
}
|
||||
reportFlagGroup.Compliance = &compliance // override usage as the accepted values differ for each subcommand.
|
||||
reportFlagGroup.ExitOnEOL = nil // disable '--exit-on-eol'
|
||||
|
||||
formatFlag := flag.FormatFlag
|
||||
formatFlag.Usage = "format (" + strings.Join([]string{
|
||||
formatFlag.Values = []string{
|
||||
r.FormatTable,
|
||||
r.FormatJSON,
|
||||
r.FormatCycloneDX,
|
||||
}, ", ") + ")"
|
||||
}
|
||||
reportFlagGroup.Format = &formatFlag
|
||||
|
||||
k8sFlags := &flag.Flags{
|
||||
@@ -968,7 +973,7 @@ func NewKubernetesCommand(globalFlags *flag.GlobalFlagGroup) *cobra.Command {
|
||||
func NewAWSCommand(globalFlags *flag.GlobalFlagGroup) *cobra.Command {
|
||||
reportFlagGroup := flag.NewReportFlagGroup()
|
||||
compliance := flag.ComplianceFlag
|
||||
compliance.Usage += fmt.Sprintf(" (%s, %s)", types.ComplianceAWSCIS12, types.ComplianceAWSCIS14)
|
||||
compliance.Values = []string{types.ComplianceAWSCIS12, types.ComplianceAWSCIS14}
|
||||
reportFlagGroup.Compliance = &compliance // override usage as the accepted values differ for each subcommand.
|
||||
reportFlagGroup.ExitOnEOL = nil // disable '--exit-on-eol'
|
||||
|
||||
@@ -1047,7 +1052,7 @@ func NewVMCommand(globalFlags *flag.GlobalFlagGroup) *cobra.Command {
|
||||
Region: &flag.Flag{
|
||||
Name: "aws-region",
|
||||
ConfigName: "aws.region",
|
||||
Value: "",
|
||||
Default: "",
|
||||
Usage: "AWS region to scan",
|
||||
},
|
||||
},
|
||||
|
||||
@@ -2,10 +2,16 @@ package commands
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"testing"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
|
||||
"github.com/aquasecurity/trivy/pkg/flag"
|
||||
"github.com/aquasecurity/trivy/pkg/report"
|
||||
)
|
||||
|
||||
func Test_showVersion(t *testing.T) {
|
||||
@@ -161,3 +167,128 @@ Policy Bundle:
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestFlags(t *testing.T) {
|
||||
type want struct {
|
||||
format string
|
||||
severities []dbTypes.Severity
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
arguments []string // 1st argument is path to trivy binaries
|
||||
want want
|
||||
wantErr string
|
||||
}{
|
||||
{
|
||||
name: "happy path",
|
||||
arguments: []string{
|
||||
"test",
|
||||
},
|
||||
want: want{
|
||||
format: report.FormatTable,
|
||||
severities: []dbTypes.Severity{
|
||||
dbTypes.SeverityUnknown,
|
||||
dbTypes.SeverityLow,
|
||||
dbTypes.SeverityMedium,
|
||||
dbTypes.SeverityHigh,
|
||||
dbTypes.SeverityCritical,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "happy path with comma-separated severities",
|
||||
arguments: []string{
|
||||
"test",
|
||||
"--severity",
|
||||
"LOW,MEDIUM",
|
||||
},
|
||||
want: want{
|
||||
format: report.FormatTable,
|
||||
severities: []dbTypes.Severity{
|
||||
dbTypes.SeverityLow,
|
||||
dbTypes.SeverityMedium,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "happy path with repeated severities",
|
||||
arguments: []string{
|
||||
"test",
|
||||
"--severity",
|
||||
"LOW",
|
||||
"--severity",
|
||||
"HIGH",
|
||||
},
|
||||
want: want{
|
||||
format: report.FormatTable,
|
||||
severities: []dbTypes.Severity{
|
||||
dbTypes.SeverityLow,
|
||||
dbTypes.SeverityHigh,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "happy path with json",
|
||||
arguments: []string{
|
||||
"test",
|
||||
"--format",
|
||||
"json",
|
||||
"--severity",
|
||||
"CRITICAL",
|
||||
},
|
||||
want: want{
|
||||
format: report.FormatJSON,
|
||||
severities: []dbTypes.Severity{
|
||||
dbTypes.SeverityCritical,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "invalid format",
|
||||
arguments: []string{
|
||||
"test",
|
||||
"--format",
|
||||
"foo",
|
||||
},
|
||||
wantErr: `invalid argument "foo" for "-f, --format" flag`,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
globalFlags := flag.NewGlobalFlagGroup()
|
||||
rootCmd := NewRootCommand("dev", globalFlags)
|
||||
rootCmd.SetErr(io.Discard)
|
||||
SetOut(io.Discard)
|
||||
|
||||
flags := &flag.Flags{
|
||||
ReportFlagGroup: flag.NewReportFlagGroup(),
|
||||
}
|
||||
cmd := &cobra.Command{
|
||||
Use: "test",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
// Bind
|
||||
require.NoError(t, flags.Bind(cmd))
|
||||
|
||||
options, err := flags.ToOptions("dev", args, globalFlags, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, tt.want.format, options.Format)
|
||||
assert.Equal(t, tt.want.severities, options.Severities)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
flags.AddFlags(cmd)
|
||||
rootCmd.AddCommand(cmd)
|
||||
|
||||
rootCmd.SetArgs(tt.arguments)
|
||||
|
||||
err := rootCmd.Execute()
|
||||
if tt.wantErr != "" {
|
||||
assert.ErrorContains(t, err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
require.NoError(t, err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,37 +4,37 @@ var (
|
||||
awsRegionFlag = Flag{
|
||||
Name: "region",
|
||||
ConfigName: "cloud.aws.region",
|
||||
Value: "",
|
||||
Default: "",
|
||||
Usage: "AWS Region to scan",
|
||||
}
|
||||
awsEndpointFlag = Flag{
|
||||
Name: "endpoint",
|
||||
ConfigName: "cloud.aws.endpoint",
|
||||
Value: "",
|
||||
Default: "",
|
||||
Usage: "AWS Endpoint override",
|
||||
}
|
||||
awsServiceFlag = Flag{
|
||||
Name: "service",
|
||||
ConfigName: "cloud.aws.service",
|
||||
Value: []string{},
|
||||
Default: []string{},
|
||||
Usage: "Only scan AWS Service(s) specified with this flag. Can specify multiple services using --service A --service B etc.",
|
||||
}
|
||||
awsSkipServicesFlag = Flag{
|
||||
Name: "skip-service",
|
||||
ConfigName: "cloud.aws.skip-service",
|
||||
Value: []string{},
|
||||
Default: []string{},
|
||||
Usage: "Skip selected AWS Service(s) specified with this flag. Can specify multiple services using --skip-service A --skip-service B etc.",
|
||||
}
|
||||
awsAccountFlag = Flag{
|
||||
Name: "account",
|
||||
ConfigName: "cloud.aws.account",
|
||||
Value: "",
|
||||
Default: "",
|
||||
Usage: "The AWS account to scan. It's useful to specify this when reviewing cached results for multiple accounts.",
|
||||
}
|
||||
awsARNFlag = Flag{
|
||||
Name: "arn",
|
||||
ConfigName: "cloud.aws.arn",
|
||||
Value: "",
|
||||
Default: "",
|
||||
Usage: "The AWS ARN to show results for. Useful to filter results once a scan is cached.",
|
||||
}
|
||||
)
|
||||
|
||||
@@ -22,43 +22,43 @@ var (
|
||||
ClearCacheFlag = Flag{
|
||||
Name: "clear-cache",
|
||||
ConfigName: "cache.clear",
|
||||
Value: false,
|
||||
Default: false,
|
||||
Usage: "clear image caches without scanning",
|
||||
}
|
||||
CacheBackendFlag = Flag{
|
||||
Name: "cache-backend",
|
||||
ConfigName: "cache.backend",
|
||||
Value: "fs",
|
||||
Default: "fs",
|
||||
Usage: "cache backend (e.g. redis://localhost:6379)",
|
||||
}
|
||||
CacheTTLFlag = Flag{
|
||||
Name: "cache-ttl",
|
||||
ConfigName: "cache.ttl",
|
||||
Value: time.Duration(0),
|
||||
Default: time.Duration(0),
|
||||
Usage: "cache TTL when using redis as cache backend",
|
||||
}
|
||||
RedisTLSFlag = Flag{
|
||||
Name: "redis-tls",
|
||||
ConfigName: "cache.redis.tls",
|
||||
Value: false,
|
||||
Default: false,
|
||||
Usage: "enable redis TLS with public certificates, if using redis as cache backend",
|
||||
}
|
||||
RedisCACertFlag = Flag{
|
||||
Name: "redis-ca",
|
||||
ConfigName: "cache.redis.ca",
|
||||
Value: "",
|
||||
Default: "",
|
||||
Usage: "redis ca file location, if using redis as cache backend",
|
||||
}
|
||||
RedisCertFlag = Flag{
|
||||
Name: "redis-cert",
|
||||
ConfigName: "cache.redis.cert",
|
||||
Value: "",
|
||||
Default: "",
|
||||
Usage: "redis certificate file location, if using redis as cache backend",
|
||||
}
|
||||
RedisKeyFlag = Flag{
|
||||
Name: "redis-key",
|
||||
ConfigName: "cache.redis.key",
|
||||
Value: "",
|
||||
Default: "",
|
||||
Usage: "redis key file location, if using redis as cache backend",
|
||||
}
|
||||
)
|
||||
|
||||
@@ -6,13 +6,13 @@ var (
|
||||
cloudUpdateCacheFlag = Flag{
|
||||
Name: "update-cache",
|
||||
ConfigName: "cloud.update-cache",
|
||||
Value: false,
|
||||
Default: false,
|
||||
Usage: "Update the cache for the applicable cloud provider instead of using cached results.",
|
||||
}
|
||||
cloudMaxCacheAgeFlag = Flag{
|
||||
Name: "max-cache-age",
|
||||
ConfigName: "cloud.max-cache-age",
|
||||
Value: time.Hour * 24,
|
||||
Default: time.Hour * 24,
|
||||
Usage: "The maximum age of the cloud cache. Cached data will be requeried from the cloud provider if it is older than this.",
|
||||
}
|
||||
)
|
||||
|
||||
@@ -13,19 +13,19 @@ var (
|
||||
ResetFlag = Flag{
|
||||
Name: "reset",
|
||||
ConfigName: "reset",
|
||||
Value: false,
|
||||
Default: false,
|
||||
Usage: "remove all caches and database",
|
||||
}
|
||||
DownloadDBOnlyFlag = Flag{
|
||||
Name: "download-db-only",
|
||||
ConfigName: "db.download-only",
|
||||
Value: false,
|
||||
Default: false,
|
||||
Usage: "download/update vulnerability database but don't run a scan",
|
||||
}
|
||||
SkipDBUpdateFlag = Flag{
|
||||
Name: "skip-db-update",
|
||||
ConfigName: "db.skip-update",
|
||||
Value: false,
|
||||
Default: false,
|
||||
Usage: "skip updating vulnerability database",
|
||||
Aliases: []Alias{
|
||||
{
|
||||
@@ -37,37 +37,37 @@ var (
|
||||
DownloadJavaDBOnlyFlag = Flag{
|
||||
Name: "download-java-db-only",
|
||||
ConfigName: "db.download-java-only",
|
||||
Value: false,
|
||||
Default: false,
|
||||
Usage: "download/update Java index database but don't run a scan",
|
||||
}
|
||||
SkipJavaDBUpdateFlag = Flag{
|
||||
Name: "skip-java-db-update",
|
||||
ConfigName: "db.java-skip-update",
|
||||
Value: false,
|
||||
Default: false,
|
||||
Usage: "skip updating Java index database",
|
||||
}
|
||||
NoProgressFlag = Flag{
|
||||
Name: "no-progress",
|
||||
ConfigName: "db.no-progress",
|
||||
Value: false,
|
||||
Default: false,
|
||||
Usage: "suppress progress bar",
|
||||
}
|
||||
DBRepositoryFlag = Flag{
|
||||
Name: "db-repository",
|
||||
ConfigName: "db.repository",
|
||||
Value: defaultDBRepository,
|
||||
Default: defaultDBRepository,
|
||||
Usage: "OCI repository to retrieve trivy-db from",
|
||||
}
|
||||
JavaDBRepositoryFlag = Flag{
|
||||
Name: "java-db-repository",
|
||||
ConfigName: "db.java-repository",
|
||||
Value: defaultJavaDBRepository,
|
||||
Default: defaultJavaDBRepository,
|
||||
Usage: "OCI repository to retrieve trivy-java-db from",
|
||||
}
|
||||
LightFlag = Flag{
|
||||
Name: "light",
|
||||
ConfigName: "db.light",
|
||||
Value: false,
|
||||
Default: false,
|
||||
Usage: "deprecated",
|
||||
Deprecated: true,
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ var (
|
||||
Name: "config",
|
||||
ConfigName: "config",
|
||||
Shorthand: "c",
|
||||
Value: "trivy.yaml",
|
||||
Default: "trivy.yaml",
|
||||
Usage: "config path",
|
||||
Persistent: true,
|
||||
}
|
||||
@@ -22,7 +22,7 @@ var (
|
||||
Name: "version",
|
||||
ConfigName: "version",
|
||||
Shorthand: "v",
|
||||
Value: false,
|
||||
Default: false,
|
||||
Usage: "show version",
|
||||
Persistent: true,
|
||||
}
|
||||
@@ -30,7 +30,7 @@ var (
|
||||
Name: "quiet",
|
||||
ConfigName: "quiet",
|
||||
Shorthand: "q",
|
||||
Value: false,
|
||||
Default: false,
|
||||
Usage: "suppress progress bar and log output",
|
||||
Persistent: true,
|
||||
}
|
||||
@@ -38,35 +38,35 @@ var (
|
||||
Name: "debug",
|
||||
ConfigName: "debug",
|
||||
Shorthand: "d",
|
||||
Value: false,
|
||||
Default: false,
|
||||
Usage: "debug mode",
|
||||
Persistent: true,
|
||||
}
|
||||
InsecureFlag = Flag{
|
||||
Name: "insecure",
|
||||
ConfigName: "insecure",
|
||||
Value: false,
|
||||
Default: false,
|
||||
Usage: "allow insecure server connections",
|
||||
Persistent: true,
|
||||
}
|
||||
TimeoutFlag = Flag{
|
||||
Name: "timeout",
|
||||
ConfigName: "timeout",
|
||||
Value: time.Second * 300, // 5 mins
|
||||
Default: time.Second * 300, // 5 mins
|
||||
Usage: "timeout",
|
||||
Persistent: true,
|
||||
}
|
||||
CacheDirFlag = Flag{
|
||||
Name: "cache-dir",
|
||||
ConfigName: "cache.dir",
|
||||
Value: fsutils.CacheDir(),
|
||||
Default: fsutils.CacheDir(),
|
||||
Usage: "cache directory",
|
||||
Persistent: true,
|
||||
}
|
||||
GenerateDefaultConfigFlag = Flag{
|
||||
Name: "generate-default-config",
|
||||
ConfigName: "generate-default-config",
|
||||
Value: false,
|
||||
Default: false,
|
||||
Usage: "write the default config to trivy-default.yaml",
|
||||
Persistent: true,
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package flag
|
||||
|
||||
import (
|
||||
v1 "github.com/google/go-containerregistry/pkg/v1"
|
||||
"golang.org/x/exp/slices"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
ftypes "github.com/aquasecurity/trivy/pkg/fanal/types"
|
||||
@@ -18,38 +17,43 @@ var (
|
||||
ImageConfigScannersFlag = Flag{
|
||||
Name: "image-config-scanners",
|
||||
ConfigName: "image.image-config-scanners",
|
||||
Value: "",
|
||||
Usage: "comma-separated list of what security issues to detect on container image configurations (config,secret)",
|
||||
Default: []string{},
|
||||
Values: types.Scanners{
|
||||
types.MisconfigScanner,
|
||||
types.SecretScanner,
|
||||
}.StringSlice(),
|
||||
Usage: "comma-separated list of what security issues to detect on container image configurations",
|
||||
}
|
||||
ScanRemovedPkgsFlag = Flag{
|
||||
Name: "removed-pkgs",
|
||||
ConfigName: "image.removed-pkgs",
|
||||
Value: false,
|
||||
Default: false,
|
||||
Usage: "detect vulnerabilities of removed packages (only for Alpine)",
|
||||
}
|
||||
InputFlag = Flag{
|
||||
Name: "input",
|
||||
ConfigName: "image.input",
|
||||
Value: "",
|
||||
Default: "",
|
||||
Usage: "input file path instead of image name",
|
||||
}
|
||||
PlatformFlag = Flag{
|
||||
Name: "platform",
|
||||
ConfigName: "image.platform",
|
||||
Value: "",
|
||||
Default: "",
|
||||
Usage: "set platform in the form os/arch if image is multi-platform capable",
|
||||
}
|
||||
DockerHostFlag = Flag{
|
||||
Name: "docker-host",
|
||||
ConfigName: "image.docker.host",
|
||||
Value: "",
|
||||
Default: "",
|
||||
Usage: "unix domain socket path to use for docker scanning",
|
||||
}
|
||||
SourceFlag = Flag{
|
||||
Name: "image-src",
|
||||
ConfigName: "image.source",
|
||||
Value: ftypes.AllImageSources.StringSlice(),
|
||||
Usage: "image source(s) to use, in priority order (docker,containerd,podman,remote)",
|
||||
Default: ftypes.AllImageSources.StringSlice(),
|
||||
Values: ftypes.AllImageSources.StringSlice(),
|
||||
Usage: "image source(s) to use, in priority order",
|
||||
}
|
||||
)
|
||||
|
||||
@@ -98,16 +102,6 @@ func (f *ImageFlagGroup) Flags() []*Flag {
|
||||
}
|
||||
|
||||
func (f *ImageFlagGroup) ToOptions() (ImageOptions, error) {
|
||||
scanners, err := parseScanners(getStringSlice(f.ImageConfigScanners), types.AllImageConfigScanners)
|
||||
if err != nil {
|
||||
return ImageOptions{}, xerrors.Errorf("unable to parse image config scanners: %w", err)
|
||||
}
|
||||
|
||||
imageSources, err := parseImageSources(getStringSlice(f.ImageSources))
|
||||
if err != nil {
|
||||
return ImageOptions{}, xerrors.Errorf("unable to parse image sources: %w", err)
|
||||
}
|
||||
|
||||
var platform ftypes.Platform
|
||||
if p := getString(f.Platform); p != "" {
|
||||
pl, err := v1.ParsePlatform(p)
|
||||
@@ -122,22 +116,10 @@ func (f *ImageFlagGroup) ToOptions() (ImageOptions, error) {
|
||||
|
||||
return ImageOptions{
|
||||
Input: getString(f.Input),
|
||||
ImageConfigScanners: scanners,
|
||||
ImageConfigScanners: getUnderlyingStringSlice[types.Scanner](f.ImageConfigScanners),
|
||||
ScanRemovedPkgs: getBool(f.ScanRemovedPkgs),
|
||||
Platform: platform,
|
||||
DockerHost: getString(f.DockerHost),
|
||||
ImageSources: imageSources,
|
||||
ImageSources: getUnderlyingStringSlice[ftypes.ImageSource](f.ImageSources),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func parseImageSources(srcs []string) (ftypes.ImageSources, error) {
|
||||
var imageSources ftypes.ImageSources
|
||||
for _, s := range srcs {
|
||||
src := ftypes.ImageSource(s)
|
||||
if !slices.Contains(ftypes.AllImageSources, src) {
|
||||
return nil, xerrors.Errorf("unknown image source: %s", s)
|
||||
}
|
||||
imageSources = append(imageSources, src)
|
||||
}
|
||||
return imageSources, nil
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ var (
|
||||
ClusterContextFlag = Flag{
|
||||
Name: "context",
|
||||
ConfigName: "kubernetes.context",
|
||||
Value: "",
|
||||
Default: "",
|
||||
Usage: "specify a context to scan",
|
||||
Aliases: []Alias{
|
||||
{Name: "ctx"},
|
||||
@@ -26,19 +26,23 @@ var (
|
||||
Name: "namespace",
|
||||
ConfigName: "kubernetes.namespace",
|
||||
Shorthand: "n",
|
||||
Value: "",
|
||||
Default: "",
|
||||
Usage: "specify a namespace to scan",
|
||||
}
|
||||
KubeConfigFlag = Flag{
|
||||
Name: "kubeconfig",
|
||||
ConfigName: "kubernetes.kubeconfig",
|
||||
Value: "",
|
||||
Default: "",
|
||||
Usage: "specify the kubeconfig file path to use",
|
||||
}
|
||||
ComponentsFlag = Flag{
|
||||
Name: "components",
|
||||
ConfigName: "kubernetes.components",
|
||||
Value: []string{
|
||||
Default: []string{
|
||||
"workload",
|
||||
"infra",
|
||||
},
|
||||
Values: []string{
|
||||
"workload",
|
||||
"infra",
|
||||
},
|
||||
@@ -47,38 +51,38 @@ var (
|
||||
K8sVersionFlag = Flag{
|
||||
Name: "k8s-version",
|
||||
ConfigName: "kubernetes.k8s.version",
|
||||
Value: "",
|
||||
Default: "",
|
||||
Usage: "specify k8s version to validate outdated api by it (example: 1.21.0)",
|
||||
}
|
||||
ParallelFlag = Flag{
|
||||
Name: "parallel",
|
||||
ConfigName: "kubernetes.parallel",
|
||||
Value: 5,
|
||||
Default: 5,
|
||||
Usage: "number (between 1-20) of goroutines enabled for parallel scanning",
|
||||
}
|
||||
TolerationsFlag = Flag{
|
||||
Name: "tolerations",
|
||||
ConfigName: "kubernetes.tolerations",
|
||||
Value: []string{},
|
||||
Default: []string{},
|
||||
Usage: "specify node-collector job tolerations (example: key1=value1:NoExecute,key2=value2:NoSchedule)",
|
||||
}
|
||||
AllNamespaces = Flag{
|
||||
Name: "all-namespaces",
|
||||
ConfigName: "kubernetes.all.namespaces",
|
||||
Shorthand: "A",
|
||||
Value: false,
|
||||
Default: false,
|
||||
Usage: "fetch resources from all cluster namespaces",
|
||||
}
|
||||
NodeCollectorNamespace = Flag{
|
||||
Name: "node-collector-namespace",
|
||||
ConfigName: "node.collector.namespace",
|
||||
Value: "trivy-temp",
|
||||
Default: "trivy-temp",
|
||||
Usage: "specify the namespace in which the node-collector job should be deployed",
|
||||
}
|
||||
ExcludeNodes = Flag{
|
||||
Name: "exclude-nodes",
|
||||
ConfigName: "exclude.nodes",
|
||||
Value: []string{},
|
||||
Default: []string{},
|
||||
Usage: "indicate the node labels that the node-collector job should exclude from scanning (example: kubernetes.io/arch:arm64,team:dev)",
|
||||
}
|
||||
)
|
||||
|
||||
@@ -9,56 +9,56 @@ var (
|
||||
LicenseFull = Flag{
|
||||
Name: "license-full",
|
||||
ConfigName: "license.full",
|
||||
Value: false,
|
||||
Default: false,
|
||||
Usage: "eagerly look for licenses in source code headers and license files",
|
||||
}
|
||||
IgnoredLicenses = Flag{
|
||||
Name: "ignored-licenses",
|
||||
ConfigName: "license.ignored",
|
||||
Value: []string{},
|
||||
Default: []string{},
|
||||
Usage: "specify a list of license to ignore",
|
||||
}
|
||||
LicenseConfidenceLevel = Flag{
|
||||
Name: "license-confidence-level",
|
||||
ConfigName: "license.confidenceLevel",
|
||||
Value: 0.9,
|
||||
Default: 0.9,
|
||||
Usage: "specify license classifier's confidence level",
|
||||
}
|
||||
|
||||
// LicenseForbidden is an option only in a config file
|
||||
LicenseForbidden = Flag{
|
||||
ConfigName: "license.forbidden",
|
||||
Value: licensing.ForbiddenLicenses,
|
||||
Default: licensing.ForbiddenLicenses,
|
||||
Usage: "forbidden licenses",
|
||||
}
|
||||
// LicenseRestricted is an option only in a config file
|
||||
LicenseRestricted = Flag{
|
||||
ConfigName: "license.restricted",
|
||||
Value: licensing.RestrictedLicenses,
|
||||
Default: licensing.RestrictedLicenses,
|
||||
Usage: "restricted licenses",
|
||||
}
|
||||
// LicenseReciprocal is an option only in a config file
|
||||
LicenseReciprocal = Flag{
|
||||
ConfigName: "license.reciprocal",
|
||||
Value: licensing.ReciprocalLicenses,
|
||||
Default: licensing.ReciprocalLicenses,
|
||||
Usage: "reciprocal licenses",
|
||||
}
|
||||
// LicenseNotice is an option only in a config file
|
||||
LicenseNotice = Flag{
|
||||
ConfigName: "license.notice",
|
||||
Value: licensing.NoticeLicenses,
|
||||
Default: licensing.NoticeLicenses,
|
||||
Usage: "notice licenses",
|
||||
}
|
||||
// LicensePermissive is an option only in a config file
|
||||
LicensePermissive = Flag{
|
||||
ConfigName: "license.permissive",
|
||||
Value: licensing.PermissiveLicenses,
|
||||
Default: licensing.PermissiveLicenses,
|
||||
Usage: "permissive licenses",
|
||||
}
|
||||
// LicenseUnencumbered is an option only in a config file
|
||||
LicenseUnencumbered = Flag{
|
||||
ConfigName: "license.unencumbered",
|
||||
Value: licensing.UnencumberedLicenses,
|
||||
Default: licensing.UnencumberedLicenses,
|
||||
Usage: "unencumbered licenses",
|
||||
}
|
||||
)
|
||||
|
||||
@@ -10,49 +10,49 @@ var (
|
||||
ResetPolicyBundleFlag = Flag{
|
||||
Name: "reset-policy-bundle",
|
||||
ConfigName: "misconfiguration.reset-policy-bundle",
|
||||
Value: false,
|
||||
Default: false,
|
||||
Usage: "remove policy bundle",
|
||||
}
|
||||
IncludeNonFailuresFlag = Flag{
|
||||
Name: "include-non-failures",
|
||||
ConfigName: "misconfiguration.include-non-failures",
|
||||
Value: false,
|
||||
Default: false,
|
||||
Usage: "include successes and exceptions, available with '--scanners config'",
|
||||
}
|
||||
HelmValuesFileFlag = Flag{
|
||||
Name: "helm-values",
|
||||
ConfigName: "misconfiguration.helm.values",
|
||||
Value: []string{},
|
||||
Default: []string{},
|
||||
Usage: "specify paths to override the Helm values.yaml files",
|
||||
}
|
||||
HelmSetFlag = Flag{
|
||||
Name: "helm-set",
|
||||
ConfigName: "misconfiguration.helm.set",
|
||||
Value: []string{},
|
||||
Default: []string{},
|
||||
Usage: "specify Helm values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)",
|
||||
}
|
||||
HelmSetFileFlag = Flag{
|
||||
Name: "helm-set-file",
|
||||
ConfigName: "misconfiguration.helm.set-file",
|
||||
Value: []string{},
|
||||
Default: []string{},
|
||||
Usage: "specify Helm values from respective files specified via the command line (can specify multiple or separate values with commas: key1=path1,key2=path2)",
|
||||
}
|
||||
HelmSetStringFlag = Flag{
|
||||
Name: "helm-set-string",
|
||||
ConfigName: "misconfiguration.helm.set-string",
|
||||
Value: []string{},
|
||||
Default: []string{},
|
||||
Usage: "specify Helm string values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)",
|
||||
}
|
||||
TfVarsFlag = Flag{
|
||||
Name: "tf-vars",
|
||||
ConfigName: "misconfiguration.terraform.vars",
|
||||
Value: []string{},
|
||||
Default: []string{},
|
||||
Usage: "specify paths to override the Terraform tfvars files",
|
||||
}
|
||||
TerraformExcludeDownloaded = Flag{
|
||||
Name: "tf-exclude-downloaded-modules",
|
||||
ConfigName: "misconfiguration.terraform.exclude-downloaded-modules",
|
||||
Value: false,
|
||||
Default: false,
|
||||
Usage: "remove results for downloaded modules in .terraform folder",
|
||||
}
|
||||
)
|
||||
|
||||
@@ -14,14 +14,14 @@ var (
|
||||
ModuleDirFlag = Flag{
|
||||
Name: "module-dir",
|
||||
ConfigName: "module.dir",
|
||||
Value: module.DefaultDir,
|
||||
Default: module.DefaultDir,
|
||||
Usage: "specify directory to the wasm modules that will be loaded",
|
||||
Persistent: true,
|
||||
}
|
||||
EnableModulesFlag = Flag{
|
||||
Name: "enable-modules",
|
||||
ConfigName: "module.enable-modules",
|
||||
Value: []string{},
|
||||
Default: []string{},
|
||||
Usage: "[EXPERIMENTAL] module names to enable",
|
||||
Persistent: true,
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/samber/lo"
|
||||
"github.com/spf13/cast"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/pflag"
|
||||
@@ -21,6 +22,10 @@ import (
|
||||
"github.com/aquasecurity/trivy/pkg/result"
|
||||
)
|
||||
|
||||
type String interface {
|
||||
~string
|
||||
}
|
||||
|
||||
type Flag struct {
|
||||
// Name is for CLI flag and environment variable.
|
||||
// If this field is empty, it will be available only in config file.
|
||||
@@ -32,8 +37,12 @@ type Flag struct {
|
||||
// Shorthand is a shorthand letter.
|
||||
Shorthand string
|
||||
|
||||
// Value is the default value. It must be filled to determine the flag type.
|
||||
Value interface{}
|
||||
// Default is the default value. It must be filled to determine the flag type.
|
||||
Default any
|
||||
|
||||
// Values is a list of allowed values.
|
||||
// It currently supports string flags and string slice flags only.
|
||||
Values []string
|
||||
|
||||
// Usage explains how to use the flag.
|
||||
Usage string
|
||||
@@ -178,13 +187,21 @@ func addFlag(cmd *cobra.Command, flag *Flag) {
|
||||
flags = cmd.Flags()
|
||||
}
|
||||
|
||||
switch v := flag.Value.(type) {
|
||||
switch v := flag.Default.(type) {
|
||||
case int:
|
||||
flags.IntP(flag.Name, flag.Shorthand, v, flag.Usage)
|
||||
case string:
|
||||
flags.StringP(flag.Name, flag.Shorthand, v, flag.Usage)
|
||||
usage := flag.Usage
|
||||
if len(flag.Values) > 0 {
|
||||
usage += fmt.Sprintf(" (%s)", strings.Join(flag.Values, ","))
|
||||
}
|
||||
flags.VarP(newCustomStringValue(v, flag.Values), flag.Name, flag.Shorthand, usage)
|
||||
case []string:
|
||||
flags.StringSliceP(flag.Name, flag.Shorthand, v, flag.Usage)
|
||||
usage := flag.Usage
|
||||
if len(flag.Values) > 0 {
|
||||
usage += fmt.Sprintf(" (%s)", strings.Join(flag.Values, ","))
|
||||
}
|
||||
flags.VarP(newCustomStringSliceValue(v, flag.Values), flag.Name, flag.Shorthand, usage)
|
||||
case bool:
|
||||
flags.BoolP(flag.Name, flag.Shorthand, v, flag.Usage)
|
||||
case time.Duration:
|
||||
@@ -203,7 +220,7 @@ func bind(cmd *cobra.Command, flag *Flag) error {
|
||||
return nil
|
||||
} else if flag.Name == "" {
|
||||
// This flag is available only in trivy.yaml
|
||||
viper.SetDefault(flag.ConfigName, flag.Value)
|
||||
viper.SetDefault(flag.ConfigName, flag.Default)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -266,6 +283,16 @@ func getStringSlice(flag *Flag) []string {
|
||||
return v
|
||||
}
|
||||
|
||||
func getUnderlyingStringSlice[T String](flag *Flag) []T {
|
||||
ss := getStringSlice(flag)
|
||||
if len(ss) == 0 {
|
||||
return nil
|
||||
}
|
||||
return lo.Map(ss, func(s string, _ int) T {
|
||||
return T(s)
|
||||
})
|
||||
}
|
||||
|
||||
func getInt(flag *Flag) int {
|
||||
return cast.ToInt(getValue(flag))
|
||||
}
|
||||
|
||||
@@ -12,19 +12,19 @@ var (
|
||||
UsernameFlag = Flag{
|
||||
Name: "username",
|
||||
ConfigName: "registry.username",
|
||||
Value: []string{},
|
||||
Default: []string{},
|
||||
Usage: "username. Comma-separated usernames allowed.",
|
||||
}
|
||||
PasswordFlag = Flag{
|
||||
Name: "password",
|
||||
ConfigName: "registry.password",
|
||||
Value: []string{},
|
||||
Default: []string{},
|
||||
Usage: "password. Comma-separated passwords allowed. TRIVY_PASSWORD should be used for security reasons.",
|
||||
}
|
||||
RegistryTokenFlag = Flag{
|
||||
Name: "registry-token",
|
||||
ConfigName: "registry.token",
|
||||
Value: "",
|
||||
Default: "",
|
||||
Usage: "registry token",
|
||||
}
|
||||
)
|
||||
|
||||
@@ -10,19 +10,19 @@ var (
|
||||
SkipPolicyUpdateFlag = Flag{
|
||||
Name: "skip-policy-update",
|
||||
ConfigName: "rego.skip-policy-update",
|
||||
Value: false,
|
||||
Default: false,
|
||||
Usage: "skip fetching rego policy updates",
|
||||
}
|
||||
TraceFlag = Flag{
|
||||
Name: "trace",
|
||||
ConfigName: "rego.trace",
|
||||
Value: false,
|
||||
Default: false,
|
||||
Usage: "enable more verbose trace output for custom queries",
|
||||
}
|
||||
ConfigPolicyFlag = Flag{
|
||||
Name: "config-policy",
|
||||
ConfigName: "rego.policy",
|
||||
Value: []string{},
|
||||
Default: []string{},
|
||||
Usage: "specify the paths to the Rego policy files or to the directories containing them, applying config files",
|
||||
Aliases: []Alias{
|
||||
{Name: "policy"},
|
||||
@@ -31,7 +31,7 @@ var (
|
||||
ConfigDataFlag = Flag{
|
||||
Name: "config-data",
|
||||
ConfigName: "rego.data",
|
||||
Value: []string{},
|
||||
Default: []string{},
|
||||
Usage: "specify paths from which data for the Rego policies will be recursively loaded",
|
||||
Aliases: []Alias{
|
||||
{Name: "data"},
|
||||
@@ -40,7 +40,7 @@ var (
|
||||
PolicyNamespaceFlag = Flag{
|
||||
Name: "policy-namespaces",
|
||||
ConfigName: "rego.namespaces",
|
||||
Value: []string{},
|
||||
Default: []string{},
|
||||
Usage: "Rego namespaces",
|
||||
Aliases: []Alias{
|
||||
{Name: "namespaces"},
|
||||
|
||||
@@ -15,31 +15,31 @@ var (
|
||||
ServerTokenFlag = Flag{
|
||||
Name: "token",
|
||||
ConfigName: "server.token",
|
||||
Value: "",
|
||||
Default: "",
|
||||
Usage: "for authentication in client/server mode",
|
||||
}
|
||||
ServerTokenHeaderFlag = Flag{
|
||||
Name: "token-header",
|
||||
ConfigName: "server.token-header",
|
||||
Value: DefaultTokenHeader,
|
||||
Default: DefaultTokenHeader,
|
||||
Usage: "specify a header name for token in client/server mode",
|
||||
}
|
||||
ServerAddrFlag = Flag{
|
||||
Name: "server",
|
||||
ConfigName: "server.addr",
|
||||
Value: "",
|
||||
Default: "",
|
||||
Usage: "server address in client mode",
|
||||
}
|
||||
ServerCustomHeadersFlag = Flag{
|
||||
Name: "custom-headers",
|
||||
ConfigName: "server.custom-headers",
|
||||
Value: []string{},
|
||||
Default: []string{},
|
||||
Usage: "custom headers in client mode",
|
||||
}
|
||||
ServerListenFlag = Flag{
|
||||
Name: "listen",
|
||||
ConfigName: "server.listen",
|
||||
Value: "localhost:4954",
|
||||
Default: "localhost:4954",
|
||||
Usage: "listen address in server mode",
|
||||
}
|
||||
)
|
||||
|
||||
@@ -4,19 +4,19 @@ var (
|
||||
FetchBranchFlag = Flag{
|
||||
Name: "branch",
|
||||
ConfigName: "repository.branch",
|
||||
Value: "",
|
||||
Default: "",
|
||||
Usage: "pass the branch name to be scanned",
|
||||
}
|
||||
FetchCommitFlag = Flag{
|
||||
Name: "commit",
|
||||
ConfigName: "repository.commit",
|
||||
Value: "",
|
||||
Default: "",
|
||||
Usage: "pass the commit hash to be scanned",
|
||||
}
|
||||
FetchTagFlag = Flag{
|
||||
Name: "tag",
|
||||
ConfigName: "repository.tag",
|
||||
Value: "",
|
||||
Default: "",
|
||||
Usage: "pass the tag name to be scanned",
|
||||
}
|
||||
)
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/samber/lo"
|
||||
"golang.org/x/exp/slices"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
@@ -26,76 +27,79 @@ var (
|
||||
Name: "format",
|
||||
ConfigName: "format",
|
||||
Shorthand: "f",
|
||||
Value: report.FormatTable,
|
||||
Usage: "format (" + strings.Join(report.SupportedFormats, ", ") + ")",
|
||||
Default: report.FormatTable,
|
||||
Values: report.SupportedFormats,
|
||||
Usage: "format",
|
||||
}
|
||||
ReportFormatFlag = Flag{
|
||||
Name: "report",
|
||||
ConfigName: "report",
|
||||
Value: "all",
|
||||
Usage: "specify a report format for the output. (all,summary)",
|
||||
Default: "all",
|
||||
Values: []string{"all", "summary"},
|
||||
Usage: "specify a report format for the output",
|
||||
}
|
||||
TemplateFlag = Flag{
|
||||
Name: "template",
|
||||
ConfigName: "template",
|
||||
Shorthand: "t",
|
||||
Value: "",
|
||||
Default: "",
|
||||
Usage: "output template",
|
||||
}
|
||||
DependencyTreeFlag = Flag{
|
||||
Name: "dependency-tree",
|
||||
ConfigName: "dependency-tree",
|
||||
Value: false,
|
||||
Default: false,
|
||||
Usage: "[EXPERIMENTAL] show dependency origin tree of vulnerable packages",
|
||||
}
|
||||
ListAllPkgsFlag = Flag{
|
||||
Name: "list-all-pkgs",
|
||||
ConfigName: "list-all-pkgs",
|
||||
Value: false,
|
||||
Default: false,
|
||||
Usage: "enabling the option will output all packages regardless of vulnerability",
|
||||
}
|
||||
IgnoreFileFlag = Flag{
|
||||
Name: "ignorefile",
|
||||
ConfigName: "ignorefile",
|
||||
Value: result.DefaultIgnoreFile,
|
||||
Default: result.DefaultIgnoreFile,
|
||||
Usage: "specify .trivyignore file",
|
||||
}
|
||||
IgnorePolicyFlag = Flag{
|
||||
Name: "ignore-policy",
|
||||
ConfigName: "ignore-policy",
|
||||
Value: "",
|
||||
Default: "",
|
||||
Usage: "specify the Rego file path to evaluate each vulnerability",
|
||||
}
|
||||
ExitCodeFlag = Flag{
|
||||
Name: "exit-code",
|
||||
ConfigName: "exit-code",
|
||||
Value: 0,
|
||||
Default: 0,
|
||||
Usage: "specify exit code when any security issues are found",
|
||||
}
|
||||
ExitOnEOLFlag = Flag{
|
||||
Name: "exit-on-eol",
|
||||
ConfigName: "exit-on-eol",
|
||||
Value: 0,
|
||||
Default: 0,
|
||||
Usage: "exit with the specified code when the OS reaches end of service/life",
|
||||
}
|
||||
OutputFlag = Flag{
|
||||
Name: "output",
|
||||
ConfigName: "output",
|
||||
Shorthand: "o",
|
||||
Value: "",
|
||||
Default: "",
|
||||
Usage: "output file name",
|
||||
}
|
||||
SeverityFlag = Flag{
|
||||
Name: "severity",
|
||||
ConfigName: "severity",
|
||||
Shorthand: "s",
|
||||
Value: strings.Join(dbTypes.SeverityNames, ","),
|
||||
Usage: "severities of security issues to be displayed (comma separated)",
|
||||
Default: dbTypes.SeverityNames,
|
||||
Values: dbTypes.SeverityNames,
|
||||
Usage: "severities of security issues to be displayed",
|
||||
}
|
||||
ComplianceFlag = Flag{
|
||||
Name: "compliance",
|
||||
ConfigName: "scan.compliance",
|
||||
Value: "",
|
||||
Default: "",
|
||||
Usage: "compliance report to generate",
|
||||
}
|
||||
)
|
||||
@@ -177,10 +181,6 @@ func (f *ReportFlagGroup) ToOptions(out io.Writer) (ReportOptions, error) {
|
||||
listAllPkgs := getBool(f.ListAllPkgs)
|
||||
output := getString(f.Output)
|
||||
|
||||
if format != "" && !slices.Contains(report.SupportedFormats, format) {
|
||||
return ReportOptions{}, xerrors.Errorf("unknown format: %v", format)
|
||||
}
|
||||
|
||||
if template != "" {
|
||||
if format == "" {
|
||||
log.Logger.Warn("'--template' is ignored because '--format template' is not specified. Use '--template' option with '--format template' option.")
|
||||
@@ -237,7 +237,7 @@ func (f *ReportFlagGroup) ToOptions(out io.Writer) (ReportOptions, error) {
|
||||
ExitOnEOL: getInt(f.ExitOnEOL),
|
||||
IgnorePolicy: getString(f.IgnorePolicy),
|
||||
Output: out,
|
||||
Severities: splitSeverity(getStringSlice(f.Severity)),
|
||||
Severities: toSeverity(getStringSlice(f.Severity)),
|
||||
Compliance: cs,
|
||||
}, nil
|
||||
}
|
||||
@@ -272,23 +272,16 @@ func (f *ReportFlagGroup) forceListAllPkgs(format string, listAllPkgs, dependenc
|
||||
return false
|
||||
}
|
||||
|
||||
func splitSeverity(severity []string) []dbTypes.Severity {
|
||||
switch {
|
||||
case len(severity) == 0:
|
||||
func toSeverity(severity []string) []dbTypes.Severity {
|
||||
if len(severity) == 0 {
|
||||
return nil
|
||||
case len(severity) == 1 && strings.Contains(severity[0], ","): // get severities from flag
|
||||
severity = strings.Split(severity[0], ",")
|
||||
}
|
||||
|
||||
var severities []dbTypes.Severity
|
||||
for _, s := range severity {
|
||||
sev, err := dbTypes.NewSeverity(strings.ToUpper(s))
|
||||
if err != nil {
|
||||
log.Logger.Warnf("unknown severity option: %s", err)
|
||||
continue
|
||||
}
|
||||
severities = append(severities, sev)
|
||||
}
|
||||
severities := lo.Map(severity, func(s string, _ int) dbTypes.Severity {
|
||||
// Note that there is no need to check the error here
|
||||
// since the severity value is already validated in the flag parser.
|
||||
sev, _ := dbTypes.NewSeverity(s)
|
||||
return sev
|
||||
})
|
||||
log.Logger.Debugf("Severities: %q", severities)
|
||||
return severities
|
||||
}
|
||||
|
||||
@@ -48,33 +48,6 @@ func TestReportFlagGroup_ToOptions(t *testing.T) {
|
||||
Output: os.Stdout,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "happy path with a low case severity",
|
||||
fields: fields{
|
||||
severities: "critical",
|
||||
},
|
||||
want: flag.ReportOptions{
|
||||
Output: os.Stdout,
|
||||
Severities: []dbTypes.Severity{
|
||||
dbTypes.SeverityCritical,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "happy path with an unknown severity",
|
||||
fields: fields{
|
||||
severities: "CRITICAL,INVALID",
|
||||
},
|
||||
want: flag.ReportOptions{
|
||||
Output: os.Stdout,
|
||||
Severities: []dbTypes.Severity{
|
||||
dbTypes.SeverityCritical,
|
||||
},
|
||||
},
|
||||
wantLogs: []string{
|
||||
"unknown severity option: unknown severity: INVALID",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "happy path with an cyclonedx",
|
||||
fields: fields{
|
||||
@@ -179,7 +152,7 @@ func TestReportFlagGroup_ToOptions(t *testing.T) {
|
||||
name: "happy path with compliance",
|
||||
fields: fields{
|
||||
compliane: "@testdata/example-spec.yaml",
|
||||
severities: "low",
|
||||
severities: dbTypes.SeverityLow.String(),
|
||||
},
|
||||
want: flag.ReportOptions{
|
||||
Output: os.Stdout,
|
||||
|
||||
@@ -10,21 +10,21 @@ var (
|
||||
ArtifactTypeFlag = Flag{
|
||||
Name: "artifact-type",
|
||||
ConfigName: "sbom.artifact-type",
|
||||
Value: "",
|
||||
Default: "",
|
||||
Usage: "deprecated",
|
||||
Deprecated: true,
|
||||
}
|
||||
SBOMFormatFlag = Flag{
|
||||
Name: "sbom-format",
|
||||
ConfigName: "sbom.format",
|
||||
Value: "",
|
||||
Default: "",
|
||||
Usage: "deprecated",
|
||||
Deprecated: true,
|
||||
}
|
||||
VEXFlag = Flag{
|
||||
Name: "vex",
|
||||
ConfigName: "sbom.vex",
|
||||
Value: "",
|
||||
Default: "",
|
||||
Usage: "[EXPERIMENTAL] file path to VEX",
|
||||
}
|
||||
)
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
package flag
|
||||
|
||||
import (
|
||||
"golang.org/x/exp/slices"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/aquasecurity/trivy/pkg/types"
|
||||
)
|
||||
|
||||
@@ -11,28 +8,34 @@ var (
|
||||
SkipDirsFlag = Flag{
|
||||
Name: "skip-dirs",
|
||||
ConfigName: "scan.skip-dirs",
|
||||
Value: []string{},
|
||||
Default: []string{},
|
||||
Usage: "specify the directories where the traversal is skipped",
|
||||
}
|
||||
SkipFilesFlag = Flag{
|
||||
Name: "skip-files",
|
||||
ConfigName: "scan.skip-files",
|
||||
Value: []string{},
|
||||
Default: []string{},
|
||||
Usage: "specify the file paths to skip traversal",
|
||||
}
|
||||
OfflineScanFlag = Flag{
|
||||
Name: "offline-scan",
|
||||
ConfigName: "scan.offline",
|
||||
Value: false,
|
||||
Default: false,
|
||||
Usage: "do not issue API requests to identify dependencies",
|
||||
}
|
||||
ScannersFlag = Flag{
|
||||
Name: "scanners",
|
||||
ConfigName: "scan.scanners",
|
||||
Value: types.Scanners{
|
||||
Default: types.Scanners{
|
||||
types.VulnerabilityScanner,
|
||||
types.SecretScanner,
|
||||
}.StringSlice(),
|
||||
Values: types.Scanners{
|
||||
types.VulnerabilityScanner,
|
||||
types.MisconfigScanner,
|
||||
types.SecretScanner,
|
||||
types.LicenseScanner,
|
||||
}.StringSlice(),
|
||||
Aliases: []Alias{
|
||||
{
|
||||
Name: "security-checks",
|
||||
@@ -40,36 +43,37 @@ var (
|
||||
Deprecated: true, // --security-checks was renamed to --scanners
|
||||
},
|
||||
},
|
||||
Usage: "comma-separated list of what security issues to detect (vuln,config,secret,license)",
|
||||
Usage: "comma-separated list of what security issues to detect",
|
||||
}
|
||||
FilePatternsFlag = Flag{
|
||||
Name: "file-patterns",
|
||||
ConfigName: "scan.file-patterns",
|
||||
Value: []string{},
|
||||
Default: []string{},
|
||||
Usage: "specify config file patterns",
|
||||
}
|
||||
SlowFlag = Flag{
|
||||
Name: "slow",
|
||||
ConfigName: "scan.slow",
|
||||
Value: false,
|
||||
Default: false,
|
||||
Usage: "scan over time with lower CPU and memory utilization",
|
||||
}
|
||||
SBOMSourcesFlag = Flag{
|
||||
Name: "sbom-sources",
|
||||
ConfigName: "scan.sbom-sources",
|
||||
Value: []string{},
|
||||
Usage: "[EXPERIMENTAL] try to retrieve SBOM from the specified sources (oci,rekor)",
|
||||
Default: []string{},
|
||||
Values: []string{"oci", "rekor"},
|
||||
Usage: "[EXPERIMENTAL] try to retrieve SBOM from the specified sources",
|
||||
}
|
||||
RekorURLFlag = Flag{
|
||||
Name: "rekor-url",
|
||||
ConfigName: "scan.rekor-url",
|
||||
Value: "https://rekor.sigstore.dev",
|
||||
Default: "https://rekor.sigstore.dev",
|
||||
Usage: "[EXPERIMENTAL] address of rekor STL server",
|
||||
}
|
||||
IncludeDevDepsFlag = Flag{
|
||||
Name: "include-dev-deps",
|
||||
ConfigName: "include-dev-deps",
|
||||
Value: false,
|
||||
Default: false,
|
||||
Usage: "include development dependencies in the report (supported: npm)",
|
||||
}
|
||||
)
|
||||
@@ -136,47 +140,17 @@ func (f *ScanFlagGroup) ToOptions(args []string) (ScanOptions, error) {
|
||||
if len(args) == 1 {
|
||||
target = args[0]
|
||||
}
|
||||
scanners, err := parseScanners(getStringSlice(f.Scanners), types.AllScanners)
|
||||
if err != nil {
|
||||
return ScanOptions{}, xerrors.Errorf("unable to parse scanners: %w", err)
|
||||
}
|
||||
|
||||
sbomSources := getStringSlice(f.SBOMSources)
|
||||
if err = validateSBOMSources(sbomSources); err != nil {
|
||||
return ScanOptions{}, xerrors.Errorf("unable to parse SBOM sources: %w", err)
|
||||
}
|
||||
|
||||
return ScanOptions{
|
||||
Target: target,
|
||||
SkipDirs: getStringSlice(f.SkipDirs),
|
||||
SkipFiles: getStringSlice(f.SkipFiles),
|
||||
OfflineScan: getBool(f.OfflineScan),
|
||||
Scanners: scanners,
|
||||
Scanners: getUnderlyingStringSlice[types.Scanner](f.Scanners),
|
||||
FilePatterns: getStringSlice(f.FilePatterns),
|
||||
Slow: getBool(f.Slow),
|
||||
SBOMSources: sbomSources,
|
||||
SBOMSources: getStringSlice(f.SBOMSources),
|
||||
RekorURL: getString(f.RekorURL),
|
||||
IncludeDevDeps: getBool(f.IncludeDevDeps),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func parseScanners(scanner []string, allowedScanners []types.Scanner) (types.Scanners, error) {
|
||||
var scanners types.Scanners
|
||||
for _, v := range scanner {
|
||||
s := types.Scanner(v)
|
||||
if !slices.Contains(allowedScanners, s) {
|
||||
return nil, xerrors.Errorf("unknown scanner: %s", v)
|
||||
}
|
||||
scanners = append(scanners, s)
|
||||
}
|
||||
return scanners, nil
|
||||
}
|
||||
|
||||
func validateSBOMSources(sbomSources []string) error {
|
||||
for _, v := range sbomSources {
|
||||
if !slices.Contains(types.SBOMSources, v) {
|
||||
return xerrors.Errorf("unknown SBOM source: %s", v)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -46,16 +46,6 @@ func TestScanFlagGroup_ToOptions(t *testing.T) {
|
||||
},
|
||||
assertion: require.NoError,
|
||||
},
|
||||
{
|
||||
name: "with wrong scanner",
|
||||
fields: fields{
|
||||
scanners: "vuln,WRONG-CHECK",
|
||||
},
|
||||
want: flag.ScanOptions{},
|
||||
assertion: func(t require.TestingT, err error, msgs ...interface{}) {
|
||||
require.ErrorContains(t, err, "unknown scanner: WRONG-CHECK")
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "without target (args)",
|
||||
args: []string{},
|
||||
|
||||
@@ -4,7 +4,7 @@ var (
|
||||
SecretConfigFlag = Flag{
|
||||
Name: "secret-config",
|
||||
ConfigName: "secret.config",
|
||||
Value: "trivy-secret.yaml",
|
||||
Default: "trivy-secret.yaml",
|
||||
Usage: "specify a path to config file for secret scanning",
|
||||
}
|
||||
)
|
||||
|
||||
91
pkg/flag/value.go
Normal file
91
pkg/flag/value.go
Normal file
@@ -0,0 +1,91 @@
|
||||
package flag
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"golang.org/x/exp/slices"
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
// -- string Value
|
||||
type customStringValue struct {
|
||||
value *string
|
||||
allowed []string
|
||||
}
|
||||
|
||||
func newCustomStringValue(val string, allowed []string) *customStringValue {
|
||||
return &customStringValue{
|
||||
value: &val,
|
||||
allowed: allowed,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *customStringValue) Set(val string) error {
|
||||
if len(s.allowed) > 0 && !slices.Contains(s.allowed, val) {
|
||||
return xerrors.Errorf("must be one of %q", s.allowed)
|
||||
}
|
||||
s.value = &val
|
||||
return nil
|
||||
}
|
||||
func (s *customStringValue) Type() string {
|
||||
return "string"
|
||||
}
|
||||
|
||||
func (s *customStringValue) String() string { return *s.value }
|
||||
|
||||
// -- stringSlice Value
|
||||
type customStringSliceValue struct {
|
||||
value *[]string
|
||||
allowed []string
|
||||
changed bool
|
||||
}
|
||||
|
||||
func newCustomStringSliceValue(val []string, allowed []string) *customStringSliceValue {
|
||||
return &customStringSliceValue{
|
||||
value: &val,
|
||||
allowed: allowed,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *customStringSliceValue) Set(val string) error {
|
||||
values := strings.Split(val, ",")
|
||||
for _, v := range values {
|
||||
if len(s.allowed) > 0 && !slices.Contains(s.allowed, v) {
|
||||
return xerrors.Errorf("must be one of %q", s.allowed)
|
||||
}
|
||||
}
|
||||
if !s.changed {
|
||||
*s.value = values
|
||||
} else {
|
||||
*s.value = append(*s.value, values...)
|
||||
}
|
||||
s.changed = true
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *customStringSliceValue) Type() string {
|
||||
return "stringSlice"
|
||||
}
|
||||
|
||||
func (s *customStringSliceValue) String() string {
|
||||
if len(*s.value) == 0 {
|
||||
// "[]" is not recognized as a zero value
|
||||
// cf. https://github.com/spf13/pflag/blob/d5e0c0615acee7028e1e2740a11102313be88de1/flag.go#L553-L565
|
||||
return ""
|
||||
}
|
||||
return "[" + strings.Join(*s.value, ",") + "]"
|
||||
}
|
||||
|
||||
func (s *customStringSliceValue) Append(val string) error {
|
||||
s.changed = true
|
||||
return s.Set(val)
|
||||
}
|
||||
|
||||
func (s *customStringSliceValue) Replace(val []string) error {
|
||||
*s.value = val
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *customStringSliceValue) GetSlice() []string {
|
||||
return *s.value
|
||||
}
|
||||
@@ -11,16 +11,20 @@ var (
|
||||
VulnTypeFlag = Flag{
|
||||
Name: "vuln-type",
|
||||
ConfigName: "vulnerability.type",
|
||||
Value: []string{
|
||||
Default: []string{
|
||||
types.VulnTypeOS,
|
||||
types.VulnTypeLibrary,
|
||||
},
|
||||
Usage: "comma-separated list of vulnerability types (os,library)",
|
||||
Values: []string{
|
||||
types.VulnTypeOS,
|
||||
types.VulnTypeLibrary,
|
||||
},
|
||||
Usage: "comma-separated list of vulnerability types",
|
||||
}
|
||||
IgnoreUnfixedFlag = Flag{
|
||||
Name: "ignore-unfixed",
|
||||
ConfigName: "vulnerability.ignore-unfixed",
|
||||
Value: false,
|
||||
Default: false,
|
||||
Usage: "display only fixed vulnerabilities",
|
||||
}
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user