mirror of
https://github.com/aquasecurity/trivy.git
synced 2025-12-05 20:40:16 -08:00
chore(cli): Remove Trivy Cloud (#9847)
This commit is contained in:
2
.github/CODEOWNERS
vendored
2
.github/CODEOWNERS
vendored
@@ -11,7 +11,7 @@ pkg/scanner/ @knqyf263 @DmitriyLewen
|
|||||||
docs/guide/scanner/misconfiguration/ @simar7 @nikpivkin
|
docs/guide/scanner/misconfiguration/ @simar7 @nikpivkin
|
||||||
docs/guide/target/aws.md @simar7 @nikpivkin
|
docs/guide/target/aws.md @simar7 @nikpivkin
|
||||||
pkg/fanal/analyzer/config/ @simar7 @nikpivkin
|
pkg/fanal/analyzer/config/ @simar7 @nikpivkin
|
||||||
pkg/cloud/ @simar7 @nikpivkin
|
pkg/config/aws/ @simar7 @nikpivkin
|
||||||
pkg/iac/ @simar7 @nikpivkin
|
pkg/iac/ @simar7 @nikpivkin
|
||||||
|
|
||||||
# Helm chart
|
# Helm chart
|
||||||
|
|||||||
@@ -45,14 +45,11 @@ trivy [global flags] command [flags] target
|
|||||||
### SEE ALSO
|
### SEE ALSO
|
||||||
|
|
||||||
* [trivy clean](trivy_clean.md) - Remove cached files
|
* [trivy clean](trivy_clean.md) - Remove cached files
|
||||||
* [trivy cloud](trivy_cloud.md) - Control Trivy Cloud platform integration settings
|
|
||||||
* [trivy config](trivy_config.md) - Scan config files for misconfigurations
|
* [trivy config](trivy_config.md) - Scan config files for misconfigurations
|
||||||
* [trivy convert](trivy_convert.md) - Convert Trivy JSON report into a different format
|
* [trivy convert](trivy_convert.md) - Convert Trivy JSON report into a different format
|
||||||
* [trivy filesystem](trivy_filesystem.md) - Scan local filesystem
|
* [trivy filesystem](trivy_filesystem.md) - Scan local filesystem
|
||||||
* [trivy image](trivy_image.md) - Scan a container image
|
* [trivy image](trivy_image.md) - Scan a container image
|
||||||
* [trivy kubernetes](trivy_kubernetes.md) - [EXPERIMENTAL] Scan kubernetes cluster
|
* [trivy kubernetes](trivy_kubernetes.md) - [EXPERIMENTAL] Scan kubernetes cluster
|
||||||
* [trivy login](trivy_login.md) - Log in to the Trivy Cloud platform
|
|
||||||
* [trivy logout](trivy_logout.md) - Log out of Trivy Cloud platform
|
|
||||||
* [trivy module](trivy_module.md) - Manage modules
|
* [trivy module](trivy_module.md) - Manage modules
|
||||||
* [trivy plugin](trivy_plugin.md) - Manage plugins
|
* [trivy plugin](trivy_plugin.md) - Manage plugins
|
||||||
* [trivy registry](trivy_registry.md) - Manage registry authentication
|
* [trivy registry](trivy_registry.md) - Manage registry authentication
|
||||||
|
|||||||
@@ -1,29 +0,0 @@
|
|||||||
## trivy cloud
|
|
||||||
|
|
||||||
Control Trivy Cloud platform integration settings
|
|
||||||
|
|
||||||
### Options
|
|
||||||
|
|
||||||
```
|
|
||||||
-h, --help help for cloud
|
|
||||||
```
|
|
||||||
|
|
||||||
### Options inherited from parent commands
|
|
||||||
|
|
||||||
```
|
|
||||||
--cacert string Path to PEM-encoded CA certificate file
|
|
||||||
--cache-dir string cache directory (default "/path/to/cache")
|
|
||||||
-c, --config string config path (default "trivy.yaml")
|
|
||||||
-d, --debug debug mode
|
|
||||||
--generate-default-config write the default config to trivy-default.yaml
|
|
||||||
--insecure allow insecure server connections
|
|
||||||
-q, --quiet suppress progress bar and log output
|
|
||||||
--timeout duration timeout (default 5m0s)
|
|
||||||
-v, --version show version
|
|
||||||
```
|
|
||||||
|
|
||||||
### SEE ALSO
|
|
||||||
|
|
||||||
* [trivy](trivy.md) - Unified security scanner
|
|
||||||
* [trivy cloud config](trivy_cloud_config.md) - Control Trivy Cloud configuration
|
|
||||||
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
## trivy cloud config
|
|
||||||
|
|
||||||
Control Trivy Cloud configuration
|
|
||||||
|
|
||||||
### Options
|
|
||||||
|
|
||||||
```
|
|
||||||
-h, --help help for config
|
|
||||||
```
|
|
||||||
|
|
||||||
### Options inherited from parent commands
|
|
||||||
|
|
||||||
```
|
|
||||||
--cacert string Path to PEM-encoded CA certificate file
|
|
||||||
--cache-dir string cache directory (default "/path/to/cache")
|
|
||||||
-c, --config string config path (default "trivy.yaml")
|
|
||||||
-d, --debug debug mode
|
|
||||||
--generate-default-config write the default config to trivy-default.yaml
|
|
||||||
--insecure allow insecure server connections
|
|
||||||
-q, --quiet suppress progress bar and log output
|
|
||||||
--timeout duration timeout (default 5m0s)
|
|
||||||
-v, --version show version
|
|
||||||
```
|
|
||||||
|
|
||||||
### SEE ALSO
|
|
||||||
|
|
||||||
* [trivy cloud](trivy_cloud.md) - Control Trivy Cloud platform integration settings
|
|
||||||
* [trivy cloud config edit](trivy_cloud_config_edit.md) - Edit Trivy Cloud configuration
|
|
||||||
* [trivy cloud config get](trivy_cloud_config_get.md) - Get Trivy Cloud configuration
|
|
||||||
* [trivy cloud config list](trivy_cloud_config_list.md) - List Trivy Cloud configuration
|
|
||||||
* [trivy cloud config set](trivy_cloud_config_set.md) - Set Trivy Cloud configuration
|
|
||||||
* [trivy cloud config unset](trivy_cloud_config_unset.md) - Unset Trivy Cloud configuration
|
|
||||||
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
## trivy cloud config edit
|
|
||||||
|
|
||||||
Edit Trivy Cloud configuration
|
|
||||||
|
|
||||||
### Synopsis
|
|
||||||
|
|
||||||
Edit Trivy Cloud platform configuration in the default editor specified in the EDITOR environment variable
|
|
||||||
|
|
||||||
```
|
|
||||||
trivy cloud config edit [flags]
|
|
||||||
```
|
|
||||||
|
|
||||||
### Options
|
|
||||||
|
|
||||||
```
|
|
||||||
-h, --help help for edit
|
|
||||||
```
|
|
||||||
|
|
||||||
### Options inherited from parent commands
|
|
||||||
|
|
||||||
```
|
|
||||||
--cacert string Path to PEM-encoded CA certificate file
|
|
||||||
--cache-dir string cache directory (default "/path/to/cache")
|
|
||||||
-c, --config string config path (default "trivy.yaml")
|
|
||||||
-d, --debug debug mode
|
|
||||||
--generate-default-config write the default config to trivy-default.yaml
|
|
||||||
--insecure allow insecure server connections
|
|
||||||
-q, --quiet suppress progress bar and log output
|
|
||||||
--timeout duration timeout (default 5m0s)
|
|
||||||
-v, --version show version
|
|
||||||
```
|
|
||||||
|
|
||||||
### SEE ALSO
|
|
||||||
|
|
||||||
* [trivy cloud config](trivy_cloud_config.md) - Control Trivy Cloud configuration
|
|
||||||
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
## trivy cloud config get
|
|
||||||
|
|
||||||
Get Trivy Cloud configuration
|
|
||||||
|
|
||||||
### Synopsis
|
|
||||||
|
|
||||||
Get a Trivy Cloud platform configuration
|
|
||||||
|
|
||||||
Available config settings can be viewed by using the `trivy cloud config list` command
|
|
||||||
|
|
||||||
```
|
|
||||||
trivy cloud config get [setting] [flags]
|
|
||||||
```
|
|
||||||
|
|
||||||
### Examples
|
|
||||||
|
|
||||||
```
|
|
||||||
$ trivy cloud config get server.scanning.enabled
|
|
||||||
$ trivy cloud config get server.scanning.upload-results
|
|
||||||
```
|
|
||||||
|
|
||||||
### Options
|
|
||||||
|
|
||||||
```
|
|
||||||
-h, --help help for get
|
|
||||||
```
|
|
||||||
|
|
||||||
### Options inherited from parent commands
|
|
||||||
|
|
||||||
```
|
|
||||||
--cacert string Path to PEM-encoded CA certificate file
|
|
||||||
--cache-dir string cache directory (default "/path/to/cache")
|
|
||||||
-c, --config string config path (default "trivy.yaml")
|
|
||||||
-d, --debug debug mode
|
|
||||||
--generate-default-config write the default config to trivy-default.yaml
|
|
||||||
--insecure allow insecure server connections
|
|
||||||
-q, --quiet suppress progress bar and log output
|
|
||||||
--timeout duration timeout (default 5m0s)
|
|
||||||
-v, --version show version
|
|
||||||
```
|
|
||||||
|
|
||||||
### SEE ALSO
|
|
||||||
|
|
||||||
* [trivy cloud config](trivy_cloud_config.md) - Control Trivy Cloud configuration
|
|
||||||
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
## trivy cloud config list
|
|
||||||
|
|
||||||
List Trivy Cloud configuration
|
|
||||||
|
|
||||||
### Synopsis
|
|
||||||
|
|
||||||
List Trivy Cloud platform configuration in human readable format
|
|
||||||
|
|
||||||
```
|
|
||||||
trivy cloud config list [flags]
|
|
||||||
```
|
|
||||||
|
|
||||||
### Options
|
|
||||||
|
|
||||||
```
|
|
||||||
-h, --help help for list
|
|
||||||
```
|
|
||||||
|
|
||||||
### Options inherited from parent commands
|
|
||||||
|
|
||||||
```
|
|
||||||
--cacert string Path to PEM-encoded CA certificate file
|
|
||||||
--cache-dir string cache directory (default "/path/to/cache")
|
|
||||||
-c, --config string config path (default "trivy.yaml")
|
|
||||||
-d, --debug debug mode
|
|
||||||
--generate-default-config write the default config to trivy-default.yaml
|
|
||||||
--insecure allow insecure server connections
|
|
||||||
-q, --quiet suppress progress bar and log output
|
|
||||||
--timeout duration timeout (default 5m0s)
|
|
||||||
-v, --version show version
|
|
||||||
```
|
|
||||||
|
|
||||||
### SEE ALSO
|
|
||||||
|
|
||||||
* [trivy cloud config](trivy_cloud_config.md) - Control Trivy Cloud configuration
|
|
||||||
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
## trivy cloud config set
|
|
||||||
|
|
||||||
Set Trivy Cloud configuration
|
|
||||||
|
|
||||||
### Synopsis
|
|
||||||
|
|
||||||
Set a Trivy Cloud platform setting
|
|
||||||
|
|
||||||
Available config settings can be viewed by using the `trivy cloud config list` command
|
|
||||||
|
|
||||||
```
|
|
||||||
trivy cloud config set [setting] [value] [flags]
|
|
||||||
```
|
|
||||||
|
|
||||||
### Examples
|
|
||||||
|
|
||||||
```
|
|
||||||
$ trivy cloud config set server.scanning.enabled true
|
|
||||||
$ trivy cloud config set server.scanning.upload-results false
|
|
||||||
```
|
|
||||||
|
|
||||||
### Options
|
|
||||||
|
|
||||||
```
|
|
||||||
-h, --help help for set
|
|
||||||
```
|
|
||||||
|
|
||||||
### Options inherited from parent commands
|
|
||||||
|
|
||||||
```
|
|
||||||
--cacert string Path to PEM-encoded CA certificate file
|
|
||||||
--cache-dir string cache directory (default "/path/to/cache")
|
|
||||||
-c, --config string config path (default "trivy.yaml")
|
|
||||||
-d, --debug debug mode
|
|
||||||
--generate-default-config write the default config to trivy-default.yaml
|
|
||||||
--insecure allow insecure server connections
|
|
||||||
-q, --quiet suppress progress bar and log output
|
|
||||||
--timeout duration timeout (default 5m0s)
|
|
||||||
-v, --version show version
|
|
||||||
```
|
|
||||||
|
|
||||||
### SEE ALSO
|
|
||||||
|
|
||||||
* [trivy cloud config](trivy_cloud_config.md) - Control Trivy Cloud configuration
|
|
||||||
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
## trivy cloud config unset
|
|
||||||
|
|
||||||
Unset Trivy Cloud configuration
|
|
||||||
|
|
||||||
### Synopsis
|
|
||||||
|
|
||||||
Unset a Trivy Cloud platform configuration and return it to the default setting
|
|
||||||
|
|
||||||
Available config settings can be viewed by using the `trivy cloud config list` command
|
|
||||||
|
|
||||||
```
|
|
||||||
trivy cloud config unset [setting] [flags]
|
|
||||||
```
|
|
||||||
|
|
||||||
### Examples
|
|
||||||
|
|
||||||
```
|
|
||||||
$ trivy cloud config unset server.scanning.enabled
|
|
||||||
$ trivy cloud config unset server.scanning.upload-results
|
|
||||||
```
|
|
||||||
|
|
||||||
### Options
|
|
||||||
|
|
||||||
```
|
|
||||||
-h, --help help for unset
|
|
||||||
```
|
|
||||||
|
|
||||||
### Options inherited from parent commands
|
|
||||||
|
|
||||||
```
|
|
||||||
--cacert string Path to PEM-encoded CA certificate file
|
|
||||||
--cache-dir string cache directory (default "/path/to/cache")
|
|
||||||
-c, --config string config path (default "trivy.yaml")
|
|
||||||
-d, --debug debug mode
|
|
||||||
--generate-default-config write the default config to trivy-default.yaml
|
|
||||||
--insecure allow insecure server connections
|
|
||||||
-q, --quiet suppress progress bar and log output
|
|
||||||
--timeout duration timeout (default 5m0s)
|
|
||||||
-v, --version show version
|
|
||||||
```
|
|
||||||
|
|
||||||
### SEE ALSO
|
|
||||||
|
|
||||||
* [trivy cloud config](trivy_cloud_config.md) - Control Trivy Cloud configuration
|
|
||||||
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
## trivy login
|
|
||||||
|
|
||||||
Log in to the Trivy Cloud platform
|
|
||||||
|
|
||||||
### Synopsis
|
|
||||||
|
|
||||||
Log in to the Trivy Cloud platform to enable scanning of images and repositories in the cloud using the token retrieved from the Trivy Cloud platform
|
|
||||||
|
|
||||||
```
|
|
||||||
trivy login [flags]
|
|
||||||
```
|
|
||||||
|
|
||||||
### Examples
|
|
||||||
|
|
||||||
```
|
|
||||||
# Log in to the Trivy Cloud platform
|
|
||||||
$ trivy login --token <token>
|
|
||||||
```
|
|
||||||
|
|
||||||
### Options
|
|
||||||
|
|
||||||
```
|
|
||||||
--api-url string API URL for Trivy Cloud platform (default "https://api.trivy.dev")
|
|
||||||
-h, --help help for login
|
|
||||||
--token string Token used to athenticate with Trivy Cloud platform
|
|
||||||
--trivy-server-url string Trivy Server URL for Trivy Cloud platform (default "https://scan.trivy.dev")
|
|
||||||
```
|
|
||||||
|
|
||||||
### Options inherited from parent commands
|
|
||||||
|
|
||||||
```
|
|
||||||
--cacert string Path to PEM-encoded CA certificate file
|
|
||||||
--cache-dir string cache directory (default "/path/to/cache")
|
|
||||||
-c, --config string config path (default "trivy.yaml")
|
|
||||||
-d, --debug debug mode
|
|
||||||
--generate-default-config write the default config to trivy-default.yaml
|
|
||||||
--insecure allow insecure server connections
|
|
||||||
-q, --quiet suppress progress bar and log output
|
|
||||||
--timeout duration timeout (default 5m0s)
|
|
||||||
-v, --version show version
|
|
||||||
```
|
|
||||||
|
|
||||||
### SEE ALSO
|
|
||||||
|
|
||||||
* [trivy](trivy.md) - Unified security scanner
|
|
||||||
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
## trivy logout
|
|
||||||
|
|
||||||
Log out of Trivy Cloud platform
|
|
||||||
|
|
||||||
```
|
|
||||||
trivy logout [flags]
|
|
||||||
```
|
|
||||||
|
|
||||||
### Options
|
|
||||||
|
|
||||||
```
|
|
||||||
-h, --help help for logout
|
|
||||||
```
|
|
||||||
|
|
||||||
### Options inherited from parent commands
|
|
||||||
|
|
||||||
```
|
|
||||||
--cacert string Path to PEM-encoded CA certificate file
|
|
||||||
--cache-dir string cache directory (default "/path/to/cache")
|
|
||||||
-c, --config string config path (default "trivy.yaml")
|
|
||||||
-d, --debug debug mode
|
|
||||||
--generate-default-config write the default config to trivy-default.yaml
|
|
||||||
--insecure allow insecure server connections
|
|
||||||
-q, --quiet suppress progress bar and log output
|
|
||||||
--timeout duration timeout (default 5m0s)
|
|
||||||
-v, --version show version
|
|
||||||
```
|
|
||||||
|
|
||||||
### SEE ALSO
|
|
||||||
|
|
||||||
* [trivy](trivy.md) - Unified security scanner
|
|
||||||
|
|
||||||
5
go.mod
5
go.mod
@@ -111,7 +111,7 @@ require (
|
|||||||
github.com/twitchtv/twirp v8.1.3+incompatible
|
github.com/twitchtv/twirp v8.1.3+incompatible
|
||||||
github.com/xeipuuv/gojsonschema v1.2.0
|
github.com/xeipuuv/gojsonschema v1.2.0
|
||||||
github.com/xlab/treeprint v1.2.0
|
github.com/xlab/treeprint v1.2.0
|
||||||
github.com/zalando/go-keyring v0.2.6
|
github.com/zalando/go-keyring v0.2.6 // indirect
|
||||||
github.com/zclconf/go-cty v1.17.0
|
github.com/zclconf/go-cty v1.17.0
|
||||||
github.com/zclconf/go-cty-yaml v1.1.0
|
github.com/zclconf/go-cty-yaml v1.1.0
|
||||||
go.etcd.io/bbolt v1.4.3
|
go.etcd.io/bbolt v1.4.3
|
||||||
@@ -133,7 +133,6 @@ require (
|
|||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
al.essio.dev/pkg/shellescape v1.5.1 // indirect
|
|
||||||
buf.build/gen/go/bufbuild/bufplugin/protocolbuffers/go v1.36.6-20250718181942-e35f9b667443.1 // indirect
|
buf.build/gen/go/bufbuild/bufplugin/protocolbuffers/go v1.36.6-20250718181942-e35f9b667443.1 // indirect
|
||||||
buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.6-20250717185734-6c6e0d3c608e.1 // indirect
|
buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.6-20250717185734-6c6e0d3c608e.1 // indirect
|
||||||
buf.build/gen/go/bufbuild/registry/connectrpc/go v1.18.1-20250721151928-2b7ae473b098.1 // indirect
|
buf.build/gen/go/bufbuild/registry/connectrpc/go v1.18.1-20250721151928-2b7ae473b098.1 // indirect
|
||||||
@@ -227,7 +226,6 @@ require (
|
|||||||
github.com/cpuguy83/go-md2man/v2 v2.0.7 // indirect
|
github.com/cpuguy83/go-md2man/v2 v2.0.7 // indirect
|
||||||
github.com/cyberphone/json-canonicalization v0.0.0-20231011164504-785e29786b46 // indirect
|
github.com/cyberphone/json-canonicalization v0.0.0-20231011164504-785e29786b46 // indirect
|
||||||
github.com/cyphar/filepath-securejoin v0.6.0 // indirect
|
github.com/cyphar/filepath-securejoin v0.6.0 // indirect
|
||||||
github.com/danieljoos/wincred v1.2.2 // indirect
|
|
||||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect
|
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect
|
||||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||||
@@ -284,7 +282,6 @@ require (
|
|||||||
github.com/gobwas/glob v0.2.3 // indirect
|
github.com/gobwas/glob v0.2.3 // indirect
|
||||||
github.com/goccy/go-json v0.10.5 // indirect
|
github.com/goccy/go-json v0.10.5 // indirect
|
||||||
github.com/goccy/go-yaml v1.15.23 // indirect
|
github.com/goccy/go-yaml v1.15.23 // indirect
|
||||||
github.com/godbus/dbus/v5 v5.1.0 // indirect
|
|
||||||
github.com/gofrs/flock v0.13.0 // indirect
|
github.com/gofrs/flock v0.13.0 // indirect
|
||||||
github.com/gofrs/uuid v4.3.1+incompatible // indirect
|
github.com/gofrs/uuid v4.3.1+incompatible // indirect
|
||||||
github.com/gogo/protobuf v1.3.2 // indirect
|
github.com/gogo/protobuf v1.3.2 // indirect
|
||||||
|
|||||||
2
go.sum
2
go.sum
@@ -687,8 +687,6 @@ github.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0=
|
|||||||
github.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM=
|
github.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM=
|
||||||
github.com/google/safetext v0.0.0-20220905092116-b49f7bc46da2 h1:SJ+NtwL6QaZ21U+IrK7d0gGgpjGGvd2kz+FzTHVzdqI=
|
github.com/google/safetext v0.0.0-20220905092116-b49f7bc46da2 h1:SJ+NtwL6QaZ21U+IrK7d0gGgpjGGvd2kz+FzTHVzdqI=
|
||||||
github.com/google/safetext v0.0.0-20220905092116-b49f7bc46da2/go.mod h1:Tv1PlzqC9t8wNnpPdctvtSUOPUUg4SHeE6vR1Ir2hmg=
|
github.com/google/safetext v0.0.0-20220905092116-b49f7bc46da2/go.mod h1:Tv1PlzqC9t8wNnpPdctvtSUOPUUg4SHeE6vR1Ir2hmg=
|
||||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
|
|
||||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
|
|
||||||
github.com/google/tink/go v1.7.0 h1:6Eox8zONGebBFcCBqkVmt60LaWZa6xg1cl/DwAh/J1w=
|
github.com/google/tink/go v1.7.0 h1:6Eox8zONGebBFcCBqkVmt60LaWZa6xg1cl/DwAh/J1w=
|
||||||
github.com/google/tink/go v1.7.0/go.mod h1:GAUOd+QE3pgj9q8VKIGTCP33c/B7eb4NhxLcgTJZStM=
|
github.com/google/tink/go v1.7.0/go.mod h1:GAUOd+QE3pgj9q8VKIGTCP33c/B7eb4NhxLcgTJZStM=
|
||||||
github.com/google/trillian v1.7.2 h1:EPBxc4YWY4Ak8tcuhyFleY+zYlbCDCa4Sn24e1Ka8Js=
|
github.com/google/trillian v1.7.2 h1:EPBxc4YWY4Ak8tcuhyFleY+zYlbCDCa4Sn24e1Ka8Js=
|
||||||
|
|||||||
10
mkdocs.yml
10
mkdocs.yml
@@ -169,21 +169,11 @@ nav:
|
|||||||
- CLI:
|
- CLI:
|
||||||
- Overview: guide/references/configuration/cli/trivy.md
|
- Overview: guide/references/configuration/cli/trivy.md
|
||||||
- Clean: guide/references/configuration/cli/trivy_clean.md
|
- Clean: guide/references/configuration/cli/trivy_clean.md
|
||||||
- Cloud:
|
|
||||||
- Cloud: guide/references/configuration/cli/trivy_cloud.md
|
|
||||||
- Cloud Config: guide/references/configuration/cli/trivy_cloud_config.md
|
|
||||||
- Cloud Config Edit: guide/references/configuration/cli/trivy_cloud_config_edit.md
|
|
||||||
- Cloud Config List: guide/references/configuration/cli/trivy_cloud_config_list.md
|
|
||||||
- Cloud Config Set: guide/references/configuration/cli/trivy_cloud_config_set.md
|
|
||||||
- Cloud Config Unset: guide/references/configuration/cli/trivy_cloud_config_unset.md
|
|
||||||
- Cloud Config Get: guide/references/configuration/cli/trivy_cloud_config_get.md
|
|
||||||
- Config: guide/references/configuration/cli/trivy_config.md
|
- Config: guide/references/configuration/cli/trivy_config.md
|
||||||
- Convert: guide/references/configuration/cli/trivy_convert.md
|
- Convert: guide/references/configuration/cli/trivy_convert.md
|
||||||
- Filesystem: guide/references/configuration/cli/trivy_filesystem.md
|
- Filesystem: guide/references/configuration/cli/trivy_filesystem.md
|
||||||
- Image: guide/references/configuration/cli/trivy_image.md
|
- Image: guide/references/configuration/cli/trivy_image.md
|
||||||
- Kubernetes: guide/references/configuration/cli/trivy_kubernetes.md
|
- Kubernetes: guide/references/configuration/cli/trivy_kubernetes.md
|
||||||
- Login: guide/references/configuration/cli/trivy_login.md
|
|
||||||
- Logout: guide/references/configuration/cli/trivy_logout.md
|
|
||||||
- Module:
|
- Module:
|
||||||
- Module: guide/references/configuration/cli/trivy_module.md
|
- Module: guide/references/configuration/cli/trivy_module.md
|
||||||
- Module Install: guide/references/configuration/cli/trivy_module_install.md
|
- Module Install: guide/references/configuration/cli/trivy_module_install.md
|
||||||
|
|||||||
@@ -1,298 +0,0 @@
|
|||||||
package cloud
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
"net/url"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"reflect"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/samber/lo"
|
|
||||||
"github.com/zalando/go-keyring"
|
|
||||||
"golang.org/x/xerrors"
|
|
||||||
"gopkg.in/yaml.v3"
|
|
||||||
|
|
||||||
"github.com/aquasecurity/trivy/pkg/log"
|
|
||||||
"github.com/aquasecurity/trivy/pkg/utils/fsutils"
|
|
||||||
xhttp "github.com/aquasecurity/trivy/pkg/x/http"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
ServiceName = "trivy-cloud"
|
|
||||||
TokenKey = "token"
|
|
||||||
DefaultApiUrl = "https://api.trivy.dev"
|
|
||||||
DefaultTrivyServerUrl = "https://scan.trivy.dev"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Api struct {
|
|
||||||
URL string `yaml:"url"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type Scanning struct {
|
|
||||||
Enabled bool `yaml:"enabled"`
|
|
||||||
UploadResults bool `yaml:"upload-results"`
|
|
||||||
SecretConfig bool `yaml:"secret-config"`
|
|
||||||
MisconfigConfig bool `yaml:"misconfig-config"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type Server struct {
|
|
||||||
URL string `yaml:"url"`
|
|
||||||
Scanning Scanning `yaml:"scanning"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type Config struct {
|
|
||||||
Api Api `yaml:"api"`
|
|
||||||
Server Server `yaml:"server"`
|
|
||||||
IsLoggedIn bool `yaml:"-"`
|
|
||||||
Token string `yaml:"-"`
|
|
||||||
}
|
|
||||||
|
|
||||||
var defaultConfig = &Config{
|
|
||||||
Api: Api{
|
|
||||||
URL: DefaultApiUrl,
|
|
||||||
},
|
|
||||||
Server: Server{
|
|
||||||
URL: DefaultTrivyServerUrl,
|
|
||||||
Scanning: Scanning{},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
func getConfigPath() string {
|
|
||||||
configFileName := fmt.Sprintf("%s.yaml", ServiceName)
|
|
||||||
return filepath.Join(fsutils.TrivyHomeDir(), configFileName)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Config) Save() error {
|
|
||||||
if c.Token == "" && c.Server.URL == "" && c.Api.URL == "" {
|
|
||||||
return xerrors.New("no config to save, required fields are token, server url, and api url")
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := c.initFirstLogin(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := keyring.Set(ServiceName, TokenKey, c.Token); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
configPath := getConfigPath()
|
|
||||||
if err := os.MkdirAll(filepath.Dir(configPath), 0o700); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
configYaml, err := yaml.Marshal(c)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
yamlWithFrontmatter := append([]byte("---\n"), configYaml...)
|
|
||||||
return os.WriteFile(configPath, yamlWithFrontmatter, 0o600)
|
|
||||||
}
|
|
||||||
|
|
||||||
func Clear() error {
|
|
||||||
if err := keyring.Delete(ServiceName, TokenKey); err != nil {
|
|
||||||
if !errors.Is(err, keyring.ErrNotFound) {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
configPath := getConfigPath()
|
|
||||||
if err := os.Remove(configPath); err != nil {
|
|
||||||
if !errors.Is(err, os.ErrNotExist) {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// initFirstLogin initializes the default scanning settings to turn them on
|
|
||||||
// after this, the user can configure in the config using the config set/unset commands
|
|
||||||
func (c *Config) initFirstLogin() error {
|
|
||||||
if c.Token == "" {
|
|
||||||
// this isn't a login save, without a token it can't login
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var firstLogin bool
|
|
||||||
_, err := keyring.Get(ServiceName, TokenKey)
|
|
||||||
if err != nil {
|
|
||||||
if !errors.Is(err, keyring.ErrNotFound) {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
firstLogin = true
|
|
||||||
}
|
|
||||||
|
|
||||||
if firstLogin {
|
|
||||||
// if first login, turn on all scanning options
|
|
||||||
c.Server.Scanning.Enabled = true
|
|
||||||
c.Server.Scanning.UploadResults = true
|
|
||||||
c.Server.Scanning.MisconfigConfig = true
|
|
||||||
c.Server.Scanning.SecretConfig = true
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load loads the Trivy Cloud config from the config file and the keychain
|
|
||||||
// If the config file does not exist the default config is returned
|
|
||||||
func Load() (*Config, error) {
|
|
||||||
logger := log.WithPrefix(log.PrefixCloud)
|
|
||||||
var config Config
|
|
||||||
configPath := getConfigPath()
|
|
||||||
yamlData, err := os.ReadFile(configPath)
|
|
||||||
if err != nil {
|
|
||||||
if !errors.Is(err, os.ErrNotExist) {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
logger.Debug("No cloud config file found")
|
|
||||||
defaultCopy := *defaultConfig
|
|
||||||
return &defaultCopy, nil
|
|
||||||
}
|
|
||||||
if err := yaml.Unmarshal(yamlData, &config); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
token, err := keyring.Get(ServiceName, TokenKey)
|
|
||||||
if err != nil {
|
|
||||||
if !errors.Is(err, keyring.ErrNotFound) {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
logger.Debug("No token found in keychain")
|
|
||||||
config.Token = ""
|
|
||||||
return &config, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
config.Token = token
|
|
||||||
return &config, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify verifies the Trivy Cloud token and server URL and sets the global cloud config
|
|
||||||
// if the token is valid, the IsLoggedIn field is set to true and the global loggedIn variable is set to true
|
|
||||||
func (c *Config) Verify(ctx context.Context) error {
|
|
||||||
if c.Token == "" {
|
|
||||||
return xerrors.New("no token provided for verification")
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.Server.URL == "" {
|
|
||||||
return xerrors.New("no server URL provided for verification")
|
|
||||||
}
|
|
||||||
|
|
||||||
logger := log.WithPrefix(log.PrefixCloud)
|
|
||||||
|
|
||||||
client := xhttp.Client()
|
|
||||||
url, err := url.JoinPath(c.Server.URL, "verify")
|
|
||||||
if err != nil {
|
|
||||||
return xerrors.Errorf("failed to join server URL and verify path: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.Debug("Verifying Trivy Cloud token against server", log.String("verification_url", url))
|
|
||||||
req, err := http.NewRequestWithContext(ctx, http.MethodPost, url, http.NoBody)
|
|
||||||
if err != nil {
|
|
||||||
return xerrors.Errorf("failed to create verification request: %w", err)
|
|
||||||
}
|
|
||||||
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", c.Token))
|
|
||||||
resp, err := client.Do(req)
|
|
||||||
if err != nil {
|
|
||||||
return xerrors.Errorf("failed to verify token: %w", err)
|
|
||||||
}
|
|
||||||
defer resp.Body.Close()
|
|
||||||
if resp.StatusCode != http.StatusOK {
|
|
||||||
return xerrors.Errorf("failed to verify token: received status code %d", resp.StatusCode)
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.Debug("Trivy Cloud token verified successfully")
|
|
||||||
return nil
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// ListConfig shows the Trivy Cloud config in human readable format
|
|
||||||
func ListConfig() error {
|
|
||||||
cloudConfig, err := Load()
|
|
||||||
if err != nil {
|
|
||||||
return xerrors.Errorf("failed to load Trivy Cloud config file: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
var loggedIn bool
|
|
||||||
if cloudConfig.Verify(context.Background()) == nil {
|
|
||||||
loggedIn = true
|
|
||||||
} else {
|
|
||||||
loggedIn = false
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Println()
|
|
||||||
fmt.Println("Trivy Cloud Configuration")
|
|
||||||
fmt.Println("-------------------------")
|
|
||||||
fmt.Printf("Filepath: %s\n", getConfigPath())
|
|
||||||
fmt.Printf("Logged In: %s\n", lo.Ternary(loggedIn, "Yes", "No"))
|
|
||||||
fmt.Println()
|
|
||||||
|
|
||||||
fields := collectConfigFields(reflect.ValueOf(cloudConfig).Elem(), "")
|
|
||||||
maxKeyLen := 0
|
|
||||||
for _, field := range fields {
|
|
||||||
maxKeyLen = max(maxKeyLen, len(field.path))
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, field := range fields {
|
|
||||||
fmt.Printf("%-*s %s\n", maxKeyLen, field.path, formatValue(field.value))
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Println()
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type configField struct {
|
|
||||||
path string
|
|
||||||
value reflect.Value
|
|
||||||
}
|
|
||||||
|
|
||||||
func collectConfigFields(v reflect.Value, prefix string) []configField {
|
|
||||||
var fields []configField
|
|
||||||
t := v.Type()
|
|
||||||
|
|
||||||
for i := 0; i < t.NumField(); i++ {
|
|
||||||
field := t.Field(i)
|
|
||||||
fieldValue := v.Field(i)
|
|
||||||
|
|
||||||
yamlTag := field.Tag.Get("yaml")
|
|
||||||
if yamlTag == "-" || yamlTag == "" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
tagName := strings.Split(yamlTag, ",")[0]
|
|
||||||
fullPath := tagName
|
|
||||||
if prefix != "" {
|
|
||||||
fullPath = prefix + "." + tagName
|
|
||||||
}
|
|
||||||
if fieldValue.Kind() == reflect.Struct {
|
|
||||||
fields = append(fields, collectConfigFields(fieldValue, fullPath)...)
|
|
||||||
} else {
|
|
||||||
fields = append(fields, configField{
|
|
||||||
path: fullPath,
|
|
||||||
value: fieldValue,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return fields
|
|
||||||
}
|
|
||||||
|
|
||||||
func formatValue(v reflect.Value) string {
|
|
||||||
switch v.Kind() {
|
|
||||||
case reflect.Bool:
|
|
||||||
return lo.Ternary(v.Bool(), "Enabled", "Disabled")
|
|
||||||
case reflect.String:
|
|
||||||
return v.String()
|
|
||||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
|
||||||
return strconv.FormatInt(v.Int(), 10)
|
|
||||||
case reflect.Float32, reflect.Float64:
|
|
||||||
return fmt.Sprintf("%f", v.Float())
|
|
||||||
default:
|
|
||||||
return fmt.Sprintf("%v", v.Interface())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
package cloud
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
"os/exec"
|
|
||||||
"runtime"
|
|
||||||
|
|
||||||
"github.com/aquasecurity/trivy/pkg/log"
|
|
||||||
"github.com/aquasecurity/trivy/pkg/utils/fsutils"
|
|
||||||
)
|
|
||||||
|
|
||||||
// OpenConfigForEditing opens the Trivy Cloud config file for editing in the default editor specified in the EDITOR environment variable
|
|
||||||
func OpenConfigForEditing() error {
|
|
||||||
configPath := getConfigPath()
|
|
||||||
|
|
||||||
logger := log.WithPrefix(log.PrefixCloud)
|
|
||||||
if !fsutils.FileExists(configPath) {
|
|
||||||
logger.Debug("Trivy Cloud config file does not exist", log.String("config_path", configPath))
|
|
||||||
defaultConfig.Save()
|
|
||||||
configPath = getConfigPath()
|
|
||||||
}
|
|
||||||
|
|
||||||
editor := getEditCommand()
|
|
||||||
|
|
||||||
cmd := exec.Command(editor, configPath)
|
|
||||||
cmd.Stdin = os.Stdin
|
|
||||||
cmd.Stdout = os.Stdout
|
|
||||||
cmd.Stderr = os.Stderr
|
|
||||||
|
|
||||||
return cmd.Run()
|
|
||||||
}
|
|
||||||
|
|
||||||
func getEditCommand() string {
|
|
||||||
editor := os.Getenv("EDITOR")
|
|
||||||
if editor != "" {
|
|
||||||
return editor
|
|
||||||
}
|
|
||||||
|
|
||||||
// fallback to notepad for windows or vi for macos/linux
|
|
||||||
if runtime.GOOS == "windows" {
|
|
||||||
return "notepad"
|
|
||||||
}
|
|
||||||
return "vi"
|
|
||||||
}
|
|
||||||
@@ -1,147 +0,0 @@
|
|||||||
package cloud
|
|
||||||
|
|
||||||
import (
|
|
||||||
"reflect"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"golang.org/x/xerrors"
|
|
||||||
"gopkg.in/yaml.v3"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Set sets a nested field in the Trivy Cloud config
|
|
||||||
func Set(attribute string, value any) error {
|
|
||||||
config, err := Load()
|
|
||||||
if err != nil {
|
|
||||||
return xerrors.Errorf("failed to load Trivy Cloud config file: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := setNestedField(reflect.ValueOf(config).Elem(), attribute, value); err != nil {
|
|
||||||
return xerrors.Errorf("failed to set attribute %q: %w", attribute, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return config.Save()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unset sets a nested field in the Trivy Cloud config to its default value
|
|
||||||
func Unset(attribute string) error {
|
|
||||||
config, err := Load()
|
|
||||||
if err != nil {
|
|
||||||
return xerrors.Errorf("failed to load Trivy Cloud config file: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := unsetNestedField(reflect.ValueOf(config).Elem(), attribute); err != nil {
|
|
||||||
return xerrors.Errorf("failed to unset attribute %q: %w", attribute, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return config.Save()
|
|
||||||
}
|
|
||||||
|
|
||||||
func unsetNestedField(value reflect.Value, attribute string) error {
|
|
||||||
field, err := navigateToField(value, attribute)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
defaultField, err := navigateToField(reflect.ValueOf(defaultConfig).Elem(), attribute)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
field.Set(defaultField)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get gets a nested field from the Trivy Cloud config
|
|
||||||
func Get(attribute string) (any, error) {
|
|
||||||
return GetWithDefault[any](attribute, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetWithDefault gets a nested field from the Trivy Cloud config with a default value
|
|
||||||
func GetWithDefault[T any](attribute string, defaultValue T) (T, error) {
|
|
||||||
config, err := Load()
|
|
||||||
if err != nil {
|
|
||||||
return defaultValue, xerrors.Errorf("failed to load Trivy Cloud config file: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
field, err := navigateToField(reflect.ValueOf(config).Elem(), attribute)
|
|
||||||
if err != nil {
|
|
||||||
return defaultValue, xerrors.Errorf("failed to get attribute %q: %w", attribute, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return field.Interface().(T), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func setNestedField(v reflect.Value, path string, value any) error {
|
|
||||||
field, err := navigateToField(v, path)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
convertedValue, err := convertToType(value, field.Type())
|
|
||||||
if err != nil {
|
|
||||||
return xerrors.Errorf("failed to convert value: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
field.Set(convertedValue)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func convertToType(value any, targetType reflect.Type) (reflect.Value, error) {
|
|
||||||
val := reflect.ValueOf(value)
|
|
||||||
if val.Type().AssignableTo(targetType) {
|
|
||||||
return val, nil
|
|
||||||
}
|
|
||||||
targetPtr := reflect.New(targetType) // *T
|
|
||||||
targetInterface := targetPtr.Interface()
|
|
||||||
data, err := yaml.Marshal(value)
|
|
||||||
if err != nil {
|
|
||||||
return reflect.Value{}, xerrors.Errorf("failed to marshal value: %w", err)
|
|
||||||
}
|
|
||||||
if err := yaml.Unmarshal(data, targetInterface); err != nil {
|
|
||||||
return reflect.Value{}, xerrors.Errorf("failed to decode into %v: %w", targetType, err)
|
|
||||||
}
|
|
||||||
return targetPtr.Elem(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func navigateToField(v reflect.Value, path string) (reflect.Value, error) {
|
|
||||||
parts := strings.Split(path, ".")
|
|
||||||
if len(parts) == 0 {
|
|
||||||
return reflect.Value{}, xerrors.New("empty attribute path")
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, part := range parts {
|
|
||||||
fieldName := yamlTagToFieldName(v, part)
|
|
||||||
if fieldName == "" {
|
|
||||||
return reflect.Value{}, xerrors.Errorf("field %q not found in config", part)
|
|
||||||
}
|
|
||||||
|
|
||||||
field := v.FieldByName(fieldName)
|
|
||||||
if !field.IsValid() {
|
|
||||||
return reflect.Value{}, xerrors.Errorf("field %q not found", fieldName)
|
|
||||||
}
|
|
||||||
if !field.CanSet() {
|
|
||||||
return reflect.Value{}, xerrors.Errorf("field %q cannot be set", fieldName)
|
|
||||||
}
|
|
||||||
|
|
||||||
if i == len(parts)-1 {
|
|
||||||
return field, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
v = field
|
|
||||||
}
|
|
||||||
|
|
||||||
return reflect.Value{}, xerrors.New("unexpected end of path")
|
|
||||||
}
|
|
||||||
|
|
||||||
func yamlTagToFieldName(v reflect.Value, yamlTag string) string {
|
|
||||||
t := v.Type()
|
|
||||||
for i := 0; i < t.NumField(); i++ {
|
|
||||||
field := t.Field(i)
|
|
||||||
tag := field.Tag.Get("yaml")
|
|
||||||
tagName := strings.Split(tag, ",")[0]
|
|
||||||
if tagName == yamlTag {
|
|
||||||
return field.Name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
@@ -1,244 +0,0 @@
|
|||||||
package cloud
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
"github.com/zalando/go-keyring"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestSet(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
configToSet map[string]any
|
|
||||||
expected *Config
|
|
||||||
expectedError string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "success with valid config",
|
|
||||||
configToSet: map[string]any{"server.scanning.enabled": true},
|
|
||||||
expected: &Config{Api: Api{URL: "https://api.trivy.dev"}, Server: Server{URL: "https://scan.trivy.dev", Scanning: Scanning{Enabled: true, UploadResults: false, SecretConfig: false, MisconfigConfig: false}}, IsLoggedIn: false, Token: ""},
|
|
||||||
expectedError: "",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "success with valid config using off for a boolean",
|
|
||||||
configToSet: map[string]any{"server.scanning.enabled": "on"},
|
|
||||||
expected: &Config{Api: Api{URL: "https://api.trivy.dev"}, Server: Server{URL: "https://scan.trivy.dev", Scanning: Scanning{Enabled: true, UploadResults: false, SecretConfig: false, MisconfigConfig: false}}, IsLoggedIn: false, Token: ""},
|
|
||||||
expectedError: "",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "error with invalid config",
|
|
||||||
configToSet: map[string]any{"server.scanning.foo": false},
|
|
||||||
expected: &Config{Api: Api{URL: "https://api.trivy.dev"}, Server: Server{URL: "https://scan.trivy.dev", Scanning: Scanning{Enabled: false, UploadResults: false, SecretConfig: false, MisconfigConfig: false}}, IsLoggedIn: false, Token: ""},
|
|
||||||
expectedError: "field \"foo\" not found in config",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "error when setting boolean with yessir",
|
|
||||||
configToSet: map[string]any{"server.scanning.enabled": "yessir"},
|
|
||||||
expected: &Config{Api: Api{URL: "https://api.trivy.dev"}, Server: Server{URL: "https://scan.trivy.dev", Scanning: Scanning{Enabled: false, UploadResults: false, SecretConfig: false, MisconfigConfig: false}}, IsLoggedIn: false, Token: ""},
|
|
||||||
expectedError: "cannot unmarshal !!str `yessir` into bool",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "error when setting boolean with invalid value",
|
|
||||||
configToSet: map[string]any{"server.scanning.enabled": "invalid"},
|
|
||||||
expected: &Config{Api: Api{URL: "https://api.trivy.dev"}, Server: Server{URL: "https://scan.trivy.dev", Scanning: Scanning{Enabled: false, UploadResults: false, SecretConfig: false, MisconfigConfig: false}}, IsLoggedIn: false, Token: ""},
|
|
||||||
expectedError: "cannot unmarshal !!str `invalid` into bool",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
tempDir := t.TempDir()
|
|
||||||
t.Setenv("XDG_DATA_HOME", tempDir)
|
|
||||||
|
|
||||||
keyring.MockInit()
|
|
||||||
defer keyring.DeleteAll(ServiceName)
|
|
||||||
defer Clear()
|
|
||||||
|
|
||||||
for key, value := range tt.configToSet {
|
|
||||||
err := Set(key, value)
|
|
||||||
if tt.expectedError != "" {
|
|
||||||
require.ErrorContains(t, err, tt.expectedError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
require.NoError(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
config, err := Load()
|
|
||||||
require.NoError(t, err)
|
|
||||||
assert.Equal(t, tt.expected, config)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGet(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
primeToken bool
|
|
||||||
setupConfig *Config
|
|
||||||
attribute string
|
|
||||||
defaultValue any
|
|
||||||
expected any
|
|
||||||
expectedError string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "success with default config",
|
|
||||||
setupConfig: nil,
|
|
||||||
attribute: "server.scanning.enabled",
|
|
||||||
defaultValue: false,
|
|
||||||
expected: false,
|
|
||||||
expectedError: "",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "success with custom config",
|
|
||||||
primeToken: true,
|
|
||||||
setupConfig: &Config{
|
|
||||||
Token: "test",
|
|
||||||
Server: Server{
|
|
||||||
URL: "https://example.com",
|
|
||||||
Scanning: Scanning{
|
|
||||||
Enabled: false,
|
|
||||||
UploadResults: true,
|
|
||||||
SecretConfig: false,
|
|
||||||
MisconfigConfig: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Api: Api{URL: "https://api.example.com"},
|
|
||||||
},
|
|
||||||
attribute: "server.scanning.enabled",
|
|
||||||
defaultValue: false,
|
|
||||||
expected: false,
|
|
||||||
expectedError: "",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "error with invalid attribute",
|
|
||||||
setupConfig: nil,
|
|
||||||
attribute: "server.scanning.foo",
|
|
||||||
defaultValue: true,
|
|
||||||
expected: true,
|
|
||||||
expectedError: "field \"foo\" not found in config",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
tempDir := t.TempDir()
|
|
||||||
t.Setenv("XDG_DATA_HOME", tempDir)
|
|
||||||
|
|
||||||
keyring.MockInit()
|
|
||||||
defer keyring.DeleteAll(ServiceName)
|
|
||||||
defer Clear()
|
|
||||||
|
|
||||||
if tt.primeToken {
|
|
||||||
// add the key so the custom config isn't overwritten
|
|
||||||
require.NoError(t, keyring.Set(ServiceName, TokenKey, tt.setupConfig.Token))
|
|
||||||
}
|
|
||||||
|
|
||||||
if tt.setupConfig != nil {
|
|
||||||
err := tt.setupConfig.Save()
|
|
||||||
require.NoError(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
value, err := GetWithDefault(tt.attribute, tt.defaultValue)
|
|
||||||
if tt.expectedError != "" {
|
|
||||||
require.ErrorContains(t, err, tt.expectedError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
require.NoError(t, err)
|
|
||||||
assert.Equal(t, tt.expected, value)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestUnset(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
primeToken bool
|
|
||||||
setupConfig *Config
|
|
||||||
attribute string
|
|
||||||
expectedValue any
|
|
||||||
expectedError string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "success with default config",
|
|
||||||
setupConfig: defaultConfig,
|
|
||||||
attribute: "server.scanning.enabled",
|
|
||||||
expectedValue: false,
|
|
||||||
expectedError: "",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "success with custom config",
|
|
||||||
setupConfig: &Config{
|
|
||||||
Token: "test",
|
|
||||||
Server: Server{
|
|
||||||
URL: "https://example.com",
|
|
||||||
Scanning: Scanning{
|
|
||||||
Enabled: false,
|
|
||||||
UploadResults: true,
|
|
||||||
SecretConfig: false,
|
|
||||||
MisconfigConfig: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Api: Api{URL: "https://api.example.com"},
|
|
||||||
},
|
|
||||||
attribute: "server.scanning.enabled",
|
|
||||||
expectedValue: false,
|
|
||||||
expectedError: "",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "success with custom url reset",
|
|
||||||
setupConfig: &Config{
|
|
||||||
Token: "test",
|
|
||||||
Server: Server{
|
|
||||||
URL: "https://example.com",
|
|
||||||
Scanning: Scanning{
|
|
||||||
Enabled: false,
|
|
||||||
UploadResults: true,
|
|
||||||
SecretConfig: false,
|
|
||||||
MisconfigConfig: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Api: Api{URL: "https://api.custom.com"},
|
|
||||||
},
|
|
||||||
attribute: "api.url",
|
|
||||||
expectedValue: "https://api.trivy.dev",
|
|
||||||
expectedError: "",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "error with invalid attribute",
|
|
||||||
setupConfig: defaultConfig,
|
|
||||||
attribute: "server.scanning.foo",
|
|
||||||
expectedValue: true,
|
|
||||||
expectedError: "field \"foo\" not found in config",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
tempDir := t.TempDir()
|
|
||||||
t.Setenv("XDG_DATA_HOME", tempDir)
|
|
||||||
|
|
||||||
keyring.MockInit()
|
|
||||||
defer keyring.DeleteAll(ServiceName)
|
|
||||||
defer Clear()
|
|
||||||
|
|
||||||
if tt.primeToken {
|
|
||||||
// prime the token so it doesn't get overwritten
|
|
||||||
require.NoError(t, keyring.Set(ServiceName, TokenKey, tt.setupConfig.Token))
|
|
||||||
}
|
|
||||||
|
|
||||||
require.NoError(t, tt.setupConfig.Save())
|
|
||||||
err := Unset(tt.attribute)
|
|
||||||
if tt.expectedError != "" {
|
|
||||||
require.ErrorContains(t, err, tt.expectedError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
require.NoError(t, err)
|
|
||||||
value, err := Get(tt.attribute)
|
|
||||||
require.NoError(t, err)
|
|
||||||
assert.Equal(t, tt.expectedValue, value)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,345 +0,0 @@
|
|||||||
package cloud
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"io"
|
|
||||||
"net/http"
|
|
||||||
"net/http/httptest"
|
|
||||||
"os"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
"github.com/zalando/go-keyring"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestSave(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
config *Config
|
|
||||||
wantErr bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "empty config",
|
|
||||||
config: &Config{},
|
|
||||||
wantErr: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "config with all fields",
|
|
||||||
config: &Config{
|
|
||||||
Token: "test-token-123",
|
|
||||||
Server: Server{
|
|
||||||
URL: "https://example.com",
|
|
||||||
},
|
|
||||||
Api: Api{
|
|
||||||
URL: "https://api.example.com",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
wantErr: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "config without token",
|
|
||||||
config: &Config{
|
|
||||||
Server: Server{
|
|
||||||
URL: "https://example.com",
|
|
||||||
},
|
|
||||||
Api: Api{
|
|
||||||
URL: "https://api.example.com",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
wantErr: false,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
tempDir := t.TempDir()
|
|
||||||
t.Setenv("XDG_DATA_HOME", tempDir)
|
|
||||||
|
|
||||||
keyring.MockInit()
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
defer keyring.DeleteAll(ServiceName)
|
|
||||||
defer Clear()
|
|
||||||
|
|
||||||
err := tt.config.Save()
|
|
||||||
if tt.wantErr {
|
|
||||||
require.Error(t, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
config, err := Load()
|
|
||||||
if tt.wantErr {
|
|
||||||
require.Error(t, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
require.NoError(t, err)
|
|
||||||
assert.Equal(t, tt.config, config)
|
|
||||||
|
|
||||||
configPath := getConfigPath()
|
|
||||||
if tt.config.Server.URL != "" || tt.config.Api.URL != "" {
|
|
||||||
assert.FileExists(t, configPath)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestClear(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
createConfig bool
|
|
||||||
wantErr bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "success when nothing to clear",
|
|
||||||
wantErr: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "success when there is config to clear",
|
|
||||||
createConfig: true,
|
|
||||||
wantErr: false,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
tempDir := t.TempDir()
|
|
||||||
t.Setenv("XDG_DATA_HOME", tempDir)
|
|
||||||
|
|
||||||
keyring.MockInit()
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
defer keyring.DeleteAll(ServiceName)
|
|
||||||
defer Clear()
|
|
||||||
|
|
||||||
if tt.createConfig {
|
|
||||||
config := &Config{
|
|
||||||
Token: "testtoken",
|
|
||||||
Server: Server{
|
|
||||||
URL: "https://example.com",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
err := config.Save()
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
configPath := getConfigPath()
|
|
||||||
assert.FileExists(t, configPath)
|
|
||||||
}
|
|
||||||
|
|
||||||
err := Clear()
|
|
||||||
if tt.wantErr {
|
|
||||||
require.Error(t, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
require.NoError(t, err)
|
|
||||||
configPath := getConfigPath()
|
|
||||||
assert.NoFileExists(t, configPath)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestLoad(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
createConfig bool
|
|
||||||
expectDefault bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "success when there is config to load",
|
|
||||||
createConfig: true,
|
|
||||||
expectDefault: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "error when there is no config to load",
|
|
||||||
expectDefault: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
tempDir := t.TempDir()
|
|
||||||
t.Setenv("XDG_DATA_HOME", tempDir)
|
|
||||||
|
|
||||||
keyring.MockInit()
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
defer keyring.DeleteAll(ServiceName)
|
|
||||||
defer Clear()
|
|
||||||
|
|
||||||
token := "testtoken"
|
|
||||||
if tt.createConfig {
|
|
||||||
config := &Config{
|
|
||||||
Token: token,
|
|
||||||
Server: Server{
|
|
||||||
URL: "https://example.com",
|
|
||||||
},
|
|
||||||
Api: Api{
|
|
||||||
URL: "https://api.example.com",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
err := config.Save()
|
|
||||||
require.NoError(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
config, err := Load()
|
|
||||||
if tt.expectDefault {
|
|
||||||
assert.Equal(t, defaultConfig, config)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
require.NotNil(t, config)
|
|
||||||
require.NoError(t, err)
|
|
||||||
assert.Equal(t, token, config.Token)
|
|
||||||
assert.Equal(t, "https://example.com", config.Server.URL)
|
|
||||||
assert.Equal(t, "https://api.example.com", config.Api.URL)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestVerify(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
config *Config
|
|
||||||
status int
|
|
||||||
wantErr bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "success with valid config",
|
|
||||||
config: &Config{Token: "testtoken", Server: Server{URL: "https://example.com"}, Api: Api{URL: "https://api.example.com"}},
|
|
||||||
status: http.StatusOK,
|
|
||||||
wantErr: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "error with invalid config",
|
|
||||||
config: &Config{},
|
|
||||||
status: http.StatusUnauthorized,
|
|
||||||
wantErr: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
tempDir := t.TempDir()
|
|
||||||
t.Setenv("XDG_DATA_HOME", tempDir)
|
|
||||||
|
|
||||||
keyring.MockInit()
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
defer keyring.DeleteAll(ServiceName)
|
|
||||||
defer Clear()
|
|
||||||
|
|
||||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
assert.Equal(t, http.MethodPost, r.Method)
|
|
||||||
assert.Equal(t, "/verify", r.URL.Path)
|
|
||||||
w.WriteHeader(tt.status)
|
|
||||||
}))
|
|
||||||
defer server.Close()
|
|
||||||
|
|
||||||
tt.config.Server.URL = server.URL
|
|
||||||
|
|
||||||
err := tt.config.Verify(context.Background())
|
|
||||||
if tt.wantErr {
|
|
||||||
require.Error(t, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
require.NoError(t, err)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestListConfig(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
primeToken bool
|
|
||||||
setupConfig *Config
|
|
||||||
wantErr string
|
|
||||||
wantContains []string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "success with valid config",
|
|
||||||
primeToken: true,
|
|
||||||
setupConfig: &Config{
|
|
||||||
Token: "testtoken",
|
|
||||||
Server: Server{
|
|
||||||
URL: "https://example.com",
|
|
||||||
Scanning: Scanning{
|
|
||||||
Enabled: true,
|
|
||||||
UploadResults: false,
|
|
||||||
SecretConfig: true,
|
|
||||||
MisconfigConfig: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Api: Api{URL: "https://api.example.com"},
|
|
||||||
},
|
|
||||||
wantContains: []string{
|
|
||||||
"Trivy Cloud Configuration",
|
|
||||||
"Logged In: No",
|
|
||||||
"Filepath:",
|
|
||||||
"api.url",
|
|
||||||
"https://api.example.com",
|
|
||||||
"server.url",
|
|
||||||
"https://example.com",
|
|
||||||
"server.scanning.enabled",
|
|
||||||
"Enabled",
|
|
||||||
"server.scanning.upload-results",
|
|
||||||
"Disabled",
|
|
||||||
"server.scanning.secret-config",
|
|
||||||
"server.scanning.misconfig-config",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "success with default config",
|
|
||||||
setupConfig: nil,
|
|
||||||
wantContains: []string{
|
|
||||||
"Trivy Cloud Configuration",
|
|
||||||
"Logged In: No",
|
|
||||||
"api.url",
|
|
||||||
DefaultApiUrl,
|
|
||||||
"server.url",
|
|
||||||
DefaultTrivyServerUrl,
|
|
||||||
"server.scanning.enabled",
|
|
||||||
"server.scanning.upload-results",
|
|
||||||
"server.scanning.secret-config",
|
|
||||||
"server.scanning.misconfig-config",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
tempDir := t.TempDir()
|
|
||||||
t.Setenv("XDG_DATA_HOME", tempDir)
|
|
||||||
|
|
||||||
keyring.MockInit()
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
defer keyring.DeleteAll(ServiceName)
|
|
||||||
defer Clear()
|
|
||||||
|
|
||||||
if tt.primeToken {
|
|
||||||
// prime the token in the keyring so the custom config doesn't get overwritten
|
|
||||||
require.NoError(t, keyring.Set(ServiceName, TokenKey, tt.setupConfig.Token))
|
|
||||||
}
|
|
||||||
|
|
||||||
if tt.setupConfig != nil {
|
|
||||||
err := tt.setupConfig.Save()
|
|
||||||
require.NoError(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
r, w, err := os.Pipe()
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
originalStdout := os.Stdout
|
|
||||||
os.Stdout = w
|
|
||||||
|
|
||||||
errChan := make(chan error, 1)
|
|
||||||
go func() {
|
|
||||||
errChan <- ListConfig()
|
|
||||||
w.Close()
|
|
||||||
}()
|
|
||||||
|
|
||||||
output, _ := io.ReadAll(r)
|
|
||||||
os.Stdout = originalStdout
|
|
||||||
|
|
||||||
err = <-errChan
|
|
||||||
if tt.wantErr != "" {
|
|
||||||
require.ErrorContains(t, err, tt.wantErr)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
outputStr := string(output)
|
|
||||||
for _, want := range tt.wantContains {
|
|
||||||
assert.Contains(t, outputStr, want)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,119 +0,0 @@
|
|||||||
package hooks
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"context"
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
"net/url"
|
|
||||||
|
|
||||||
"golang.org/x/xerrors"
|
|
||||||
|
|
||||||
"github.com/aquasecurity/trivy/pkg/cloud"
|
|
||||||
"github.com/aquasecurity/trivy/pkg/flag"
|
|
||||||
"github.com/aquasecurity/trivy/pkg/log"
|
|
||||||
"github.com/aquasecurity/trivy/pkg/types"
|
|
||||||
xhttp "github.com/aquasecurity/trivy/pkg/x/http"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
presignedUploadUrl = "/trivy-reports/upload-url"
|
|
||||||
)
|
|
||||||
|
|
||||||
type CloudPlatformResultsHook struct {
|
|
||||||
name string
|
|
||||||
cloudConfig *cloud.Config
|
|
||||||
client *http.Client
|
|
||||||
logger *log.Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewResultsHook(cloudCfg *cloud.Config) *CloudPlatformResultsHook {
|
|
||||||
return &CloudPlatformResultsHook{
|
|
||||||
name: "Trivy Cloud Results Hook",
|
|
||||||
cloudConfig: cloudCfg,
|
|
||||||
client: xhttp.Client(),
|
|
||||||
logger: log.WithPrefix(log.PrefixCloud),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *CloudPlatformResultsHook) Name() string {
|
|
||||||
return h.name
|
|
||||||
}
|
|
||||||
|
|
||||||
// PreReport is not going go to be called so we return nil
|
|
||||||
func (h *CloudPlatformResultsHook) PreReport(_ context.Context, _ *types.Report, _ flag.Options) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *CloudPlatformResultsHook) PostReport(ctx context.Context, report *types.Report, _ flag.Options) error {
|
|
||||||
h.logger.Debug("PostReport called with report")
|
|
||||||
jsonReport, err := json.MarshalIndent(report, "", " ")
|
|
||||||
if err != nil {
|
|
||||||
return xerrors.Errorf("failed to marshal report to JSON: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return h.uploadResults(ctx, jsonReport)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *CloudPlatformResultsHook) uploadResults(ctx context.Context, jsonReport []byte) error {
|
|
||||||
uploadUrl, err := h.getPresignedUploadUrl(ctx)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to get presigned upload URL: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// create a new request to upload the results
|
|
||||||
req, err := http.NewRequestWithContext(ctx, http.MethodPut, uploadUrl, bytes.NewBuffer(jsonReport))
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to create upload request: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
req.Header.Set("Content-Type", "application/json")
|
|
||||||
resp, err := h.client.Do(req)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to upload results: %w", err)
|
|
||||||
}
|
|
||||||
defer resp.Body.Close()
|
|
||||||
|
|
||||||
if resp.StatusCode != http.StatusOK {
|
|
||||||
return fmt.Errorf("failed to upload results: received status code %d", resp.StatusCode)
|
|
||||||
}
|
|
||||||
|
|
||||||
h.logger.Info("Report uploaded successfully to Trivy Cloud")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *CloudPlatformResultsHook) getPresignedUploadUrl(ctx context.Context) (string, error) {
|
|
||||||
uploadUrl, err := url.JoinPath(h.cloudConfig.Api.URL, presignedUploadUrl)
|
|
||||||
if err != nil {
|
|
||||||
return "", fmt.Errorf("failed to join API URL and presigned upload URL: %w", err)
|
|
||||||
}
|
|
||||||
h.logger.Debug("Requesting result upload URL", log.String("uploadUrl", uploadUrl))
|
|
||||||
|
|
||||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, uploadUrl, http.NoBody)
|
|
||||||
if err != nil {
|
|
||||||
return "", fmt.Errorf("failed to create request: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
req.Header.Set("Authorization", "Bearer "+h.cloudConfig.Token)
|
|
||||||
resp, err := h.client.Do(req)
|
|
||||||
if err != nil {
|
|
||||||
return "", fmt.Errorf("failed to get upload URL: %w", err)
|
|
||||||
}
|
|
||||||
defer resp.Body.Close()
|
|
||||||
|
|
||||||
if resp.StatusCode != http.StatusOK {
|
|
||||||
return "", fmt.Errorf("failed to get upload URL: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// read the upload URL from the response
|
|
||||||
var uploadResponse struct {
|
|
||||||
UploadURL string `json:"uploadUrl"`
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := json.NewDecoder(resp.Body).Decode(&uploadResponse); err != nil {
|
|
||||||
return "", xerrors.Errorf("failed to decode upload URL response: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return uploadResponse.UploadURL, nil
|
|
||||||
}
|
|
||||||
@@ -17,7 +17,6 @@ import (
|
|||||||
"github.com/aquasecurity/trivy/pkg/commands/artifact"
|
"github.com/aquasecurity/trivy/pkg/commands/artifact"
|
||||||
"github.com/aquasecurity/trivy/pkg/commands/auth"
|
"github.com/aquasecurity/trivy/pkg/commands/auth"
|
||||||
"github.com/aquasecurity/trivy/pkg/commands/clean"
|
"github.com/aquasecurity/trivy/pkg/commands/clean"
|
||||||
"github.com/aquasecurity/trivy/pkg/commands/cloud"
|
|
||||||
"github.com/aquasecurity/trivy/pkg/commands/convert"
|
"github.com/aquasecurity/trivy/pkg/commands/convert"
|
||||||
"github.com/aquasecurity/trivy/pkg/commands/server"
|
"github.com/aquasecurity/trivy/pkg/commands/server"
|
||||||
"github.com/aquasecurity/trivy/pkg/fanal/analyzer"
|
"github.com/aquasecurity/trivy/pkg/fanal/analyzer"
|
||||||
@@ -82,10 +81,6 @@ func NewApp() *cobra.Command {
|
|||||||
ID: groupUtility,
|
ID: groupUtility,
|
||||||
Title: "Utility Commands",
|
Title: "Utility Commands",
|
||||||
},
|
},
|
||||||
&cobra.Group{
|
|
||||||
ID: cloud.GroupCloud,
|
|
||||||
Title: "Trivy Cloud Commands",
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
rootCmd.SetCompletionCommandGroupID(groupUtility)
|
rootCmd.SetCompletionCommandGroupID(groupUtility)
|
||||||
rootCmd.SetHelpCommandGroupID(groupUtility)
|
rootCmd.SetHelpCommandGroupID(groupUtility)
|
||||||
@@ -107,9 +102,6 @@ func NewApp() *cobra.Command {
|
|||||||
NewCleanCommand(globalFlags),
|
NewCleanCommand(globalFlags),
|
||||||
NewRegistryCommand(globalFlags),
|
NewRegistryCommand(globalFlags),
|
||||||
NewVEXCommand(globalFlags),
|
NewVEXCommand(globalFlags),
|
||||||
NewLoginCommand(globalFlags),
|
|
||||||
NewLogoutCommand(),
|
|
||||||
NewCloudCommand(),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if plugins := loadPluginCommands(); len(plugins) > 0 {
|
if plugins := loadPluginCommands(); len(plugins) > 0 {
|
||||||
@@ -216,8 +208,7 @@ func NewRootCommand(globalFlags *flag.GlobalFlagGroup) *cobra.Command {
|
|||||||
}
|
}
|
||||||
// Initialize logger
|
// Initialize logger
|
||||||
log.InitLogger(opts.Debug, opts.Quiet)
|
log.InitLogger(opts.Debug, opts.Quiet)
|
||||||
|
return nil
|
||||||
return cloud.CheckTrivyCloudStatus(cmd)
|
|
||||||
},
|
},
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
flags := flag.Flags{globalFlags}
|
flags := flag.Flags{globalFlags}
|
||||||
@@ -1422,149 +1413,6 @@ func NewVEXCommand(globalFlags *flag.GlobalFlagGroup) *cobra.Command {
|
|||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewLoginCommand(globalFlags *flag.GlobalFlagGroup) *cobra.Command {
|
|
||||||
loginFlags := &flag.Flags{
|
|
||||||
globalFlags,
|
|
||||||
flag.NewCloudFlagGroup(),
|
|
||||||
}
|
|
||||||
|
|
||||||
loginCmd := &cobra.Command{
|
|
||||||
Use: "login [flags]",
|
|
||||||
Short: "Log in to the Trivy Cloud platform",
|
|
||||||
Long: "Log in to the Trivy Cloud platform to enable scanning of images and repositories in the cloud using the token retrieved from the Trivy Cloud platform",
|
|
||||||
GroupID: cloud.GroupCloud,
|
|
||||||
Args: cobra.NoArgs,
|
|
||||||
Example: ` # Log in to the Trivy Cloud platform
|
|
||||||
$ trivy login --token <token>`,
|
|
||||||
PreRunE: func(cmd *cobra.Command, _ []string) error {
|
|
||||||
if err := loginFlags.Bind(cmd); err != nil {
|
|
||||||
return xerrors.Errorf("flag bind error: %w", err)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
},
|
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
|
||||||
if err := loginFlags.Bind(cmd); err != nil {
|
|
||||||
return xerrors.Errorf("flag bind error: %w", err)
|
|
||||||
}
|
|
||||||
cloudOptions, err := loginFlags.ToOptions(args)
|
|
||||||
if err != nil {
|
|
||||||
return xerrors.Errorf("flag error: %w", err)
|
|
||||||
}
|
|
||||||
return cloud.Login(cmd.Context(), cloudOptions)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
loginFlags.AddFlags(loginCmd)
|
|
||||||
loginCmd.SetFlagErrorFunc(flagErrorFunc)
|
|
||||||
|
|
||||||
return loginCmd
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewLogoutCommand() *cobra.Command {
|
|
||||||
cmd := &cobra.Command{
|
|
||||||
Use: "logout",
|
|
||||||
Short: "Log out of Trivy Cloud platform",
|
|
||||||
GroupID: cloud.GroupCloud,
|
|
||||||
Args: cobra.NoArgs,
|
|
||||||
RunE: func(_ *cobra.Command, _ []string) error {
|
|
||||||
return cloud.Logout()
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
return cmd
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewCloudCommand() *cobra.Command {
|
|
||||||
cloudCmd := &cobra.Command{
|
|
||||||
Use: "cloud subcommand",
|
|
||||||
Short: "Control Trivy Cloud platform integration settings",
|
|
||||||
GroupID: cloud.GroupCloud,
|
|
||||||
}
|
|
||||||
|
|
||||||
// add the group the sub commands so they don't check the login status
|
|
||||||
cloudCmd.AddGroup(&cobra.Group{
|
|
||||||
ID: cloud.GroupCloud,
|
|
||||||
Title: "Trivy Cloud Commands",
|
|
||||||
})
|
|
||||||
|
|
||||||
configCmd := &cobra.Command{
|
|
||||||
Use: "config subcommand",
|
|
||||||
Short: "Control Trivy Cloud configuration",
|
|
||||||
GroupID: cloud.GroupCloud,
|
|
||||||
}
|
|
||||||
|
|
||||||
configCmd.AddGroup(&cobra.Group{
|
|
||||||
ID: cloud.GroupCloud,
|
|
||||||
Title: "Trivy Cloud Configuration Commands",
|
|
||||||
})
|
|
||||||
|
|
||||||
configCmd.AddCommand(
|
|
||||||
&cobra.Command{
|
|
||||||
Use: "edit",
|
|
||||||
Short: "Edit Trivy Cloud configuration",
|
|
||||||
Long: "Edit Trivy Cloud platform configuration in the default editor specified in the EDITOR environment variable",
|
|
||||||
GroupID: cloud.GroupCloud,
|
|
||||||
RunE: func(_ *cobra.Command, _ []string) error {
|
|
||||||
return cloud.EditConfig()
|
|
||||||
},
|
|
||||||
},
|
|
||||||
&cobra.Command{
|
|
||||||
Use: "list",
|
|
||||||
Short: "List Trivy Cloud configuration",
|
|
||||||
Long: "List Trivy Cloud platform configuration in human readable format",
|
|
||||||
GroupID: cloud.GroupCloud,
|
|
||||||
RunE: func(_ *cobra.Command, _ []string) error {
|
|
||||||
return cloud.ListConfig()
|
|
||||||
},
|
|
||||||
},
|
|
||||||
&cobra.Command{
|
|
||||||
Use: "set [setting] [value]",
|
|
||||||
Short: "Set Trivy Cloud configuration",
|
|
||||||
Long: `Set a Trivy Cloud platform setting
|
|
||||||
|
|
||||||
Available config settings can be viewed by using the ` + "`trivy cloud config list`" + ` command`,
|
|
||||||
Example: ` $ trivy cloud config set server.scanning.enabled true
|
|
||||||
$ trivy cloud config set server.scanning.upload-results false`,
|
|
||||||
Args: cobra.ExactArgs(2),
|
|
||||||
GroupID: cloud.GroupCloud,
|
|
||||||
RunE: func(_ *cobra.Command, args []string) error {
|
|
||||||
return cloud.SetConfig(args[0], args[1])
|
|
||||||
},
|
|
||||||
},
|
|
||||||
&cobra.Command{
|
|
||||||
Use: "unset [setting]",
|
|
||||||
Short: "Unset Trivy Cloud configuration",
|
|
||||||
Long: `Unset a Trivy Cloud platform configuration and return it to the default setting
|
|
||||||
|
|
||||||
Available config settings can be viewed by using the ` + "`trivy cloud config list`" + ` command`,
|
|
||||||
Example: ` $ trivy cloud config unset server.scanning.enabled
|
|
||||||
$ trivy cloud config unset server.scanning.upload-results`,
|
|
||||||
Args: cobra.ExactArgs(1),
|
|
||||||
GroupID: cloud.GroupCloud,
|
|
||||||
RunE: func(_ *cobra.Command, args []string) error {
|
|
||||||
return cloud.UnsetConfig(args[0])
|
|
||||||
},
|
|
||||||
},
|
|
||||||
&cobra.Command{
|
|
||||||
Use: "get [setting]",
|
|
||||||
Short: "Get Trivy Cloud configuration",
|
|
||||||
Long: `Get a Trivy Cloud platform configuration
|
|
||||||
|
|
||||||
Available config settings can be viewed by using the ` + "`trivy cloud config list`" + ` command`,
|
|
||||||
Example: ` $ trivy cloud config get server.scanning.enabled
|
|
||||||
$ trivy cloud config get server.scanning.upload-results`,
|
|
||||||
Args: cobra.ExactArgs(1),
|
|
||||||
GroupID: cloud.GroupCloud,
|
|
||||||
RunE: func(_ *cobra.Command, args []string) error {
|
|
||||||
return cloud.GetConfig(args[0])
|
|
||||||
},
|
|
||||||
},
|
|
||||||
)
|
|
||||||
cloudCmd.AddCommand(configCmd)
|
|
||||||
|
|
||||||
return cloudCmd
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewVersionCommand(globalFlags *flag.GlobalFlagGroup) *cobra.Command {
|
func NewVersionCommand(globalFlags *flag.GlobalFlagGroup) *cobra.Command {
|
||||||
var versionFormat string
|
var versionFormat string
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
|
|||||||
@@ -1,120 +0,0 @@
|
|||||||
package cloud
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
|
||||||
"golang.org/x/xerrors"
|
|
||||||
|
|
||||||
"github.com/aquasecurity/trivy/pkg/cloud"
|
|
||||||
"github.com/aquasecurity/trivy/pkg/cloud/hooks"
|
|
||||||
"github.com/aquasecurity/trivy/pkg/extension"
|
|
||||||
"github.com/aquasecurity/trivy/pkg/flag"
|
|
||||||
"github.com/aquasecurity/trivy/pkg/log"
|
|
||||||
)
|
|
||||||
|
|
||||||
const GroupCloud = "cloud"
|
|
||||||
|
|
||||||
// Login performs a login to the Trivy Cloud Server service using the provided credentials.
|
|
||||||
func Login(ctx context.Context, opts flag.Options) error {
|
|
||||||
creds := opts.CloudOptions.LoginCredentials
|
|
||||||
if creds.Token == "" {
|
|
||||||
return xerrors.New("token is required for Trivy Cloud login")
|
|
||||||
}
|
|
||||||
if opts.CloudOptions.TrivyServerUrl == "" {
|
|
||||||
return xerrors.New("trivy server url is required for Trivy Cloud login")
|
|
||||||
}
|
|
||||||
if opts.CloudOptions.ApiUrl == "" {
|
|
||||||
return xerrors.New("api url is required for Trivy Cloud login")
|
|
||||||
}
|
|
||||||
|
|
||||||
// load the existing config or get the default
|
|
||||||
cloudConfig, err := cloud.Load()
|
|
||||||
if err != nil {
|
|
||||||
return xerrors.Errorf("failed to load Trivy Cloud config: %w", err)
|
|
||||||
}
|
|
||||||
cloudConfig.Token = creds.Token
|
|
||||||
cloudConfig.Server.URL = opts.CloudOptions.TrivyServerUrl
|
|
||||||
cloudConfig.Api.URL = opts.CloudOptions.ApiUrl
|
|
||||||
|
|
||||||
if err := cloudConfig.Verify(ctx); err != nil {
|
|
||||||
return xerrors.Errorf("failed to verify Trivy Cloud config: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := cloudConfig.Save(); err != nil {
|
|
||||||
return xerrors.Errorf("failed to save Trivy Cloud config: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
log.WithPrefix(log.PrefixCloud).Info("Trivy Cloud login successful")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Logout removes the Trivy cloud configuration from both keychain and config file.
|
|
||||||
func Logout() error {
|
|
||||||
if err := cloud.Clear(); err != nil {
|
|
||||||
return xerrors.Errorf("failed to clear Trivy Cloud configuration: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
log.WithPrefix(log.PrefixCloud).Info("Logged out of Trivy cloud and removed configuration")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// CheckTrivyCloudStatus checks if the Trivy Cloud configuration file exists and verifies the token.
|
|
||||||
// If the token is valid, it sets the environment variables TRIVY_SERVER and TRIVY_TOKEN.
|
|
||||||
func CheckTrivyCloudStatus(cmd *cobra.Command) error {
|
|
||||||
if cmd.GroupID == GroupCloud {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
logger := log.WithPrefix(log.PrefixCloud)
|
|
||||||
cloudConfig, err := cloud.Load()
|
|
||||||
if err != nil {
|
|
||||||
logger.Error("Failed to load Trivy Cloud config file", log.Err(err))
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if cloudConfig != nil && cloudConfig.Verify(cmd.Context()) == nil {
|
|
||||||
logger.Info("Trivy cloud is logged in")
|
|
||||||
if cloudConfig.Server.Scanning.Enabled {
|
|
||||||
logger.Info("Trivy Cloud server scanning is enabled")
|
|
||||||
os.Setenv("TRIVY_SERVER", cloudConfig.Server.URL)
|
|
||||||
os.Setenv("TRIVY_TOKEN_HEADER", "Authorization")
|
|
||||||
os.Setenv("TRIVY_TOKEN", fmt.Sprintf("Bearer %s", cloudConfig.Token))
|
|
||||||
}
|
|
||||||
|
|
||||||
if cloudConfig.Server.Scanning.UploadResults {
|
|
||||||
logger.Info("Trivy Cloud results upload is enabled")
|
|
||||||
// add hook to upload the results to Trivy Cloud
|
|
||||||
resultHook := hooks.NewResultsHook(cloudConfig)
|
|
||||||
extension.RegisterHook(resultHook)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func ListConfig() error {
|
|
||||||
return cloud.ListConfig()
|
|
||||||
}
|
|
||||||
|
|
||||||
func EditConfig() error {
|
|
||||||
return cloud.OpenConfigForEditing()
|
|
||||||
}
|
|
||||||
|
|
||||||
func SetConfig(attribute string, value any) error {
|
|
||||||
return cloud.Set(attribute, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
func UnsetConfig(attribute string) error {
|
|
||||||
return cloud.Unset(attribute)
|
|
||||||
}
|
|
||||||
func GetConfig(attribute string) error {
|
|
||||||
value, err := cloud.Get(attribute)
|
|
||||||
if err != nil {
|
|
||||||
return xerrors.Errorf("failed to get Trivy Cloud config: %w", err)
|
|
||||||
}
|
|
||||||
fmt.Println(value)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
@@ -1,145 +0,0 @@
|
|||||||
package cloud
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"net/http"
|
|
||||||
"net/http/httptest"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
"github.com/zalando/go-keyring"
|
|
||||||
|
|
||||||
"github.com/aquasecurity/trivy/pkg/cloud"
|
|
||||||
"github.com/aquasecurity/trivy/pkg/flag"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestLogout(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
createConfigFile bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "successful logout when the config file exists",
|
|
||||||
createConfigFile: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "successful logout when the config file does not exist",
|
|
||||||
createConfigFile: false,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
tempDir := t.TempDir()
|
|
||||||
t.Setenv("XDG_DATA_HOME", tempDir)
|
|
||||||
|
|
||||||
keyring.MockInit()
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
|
|
||||||
defer keyring.DeleteAll(cloud.ServiceName)
|
|
||||||
defer cloud.Clear()
|
|
||||||
cloud.Clear()
|
|
||||||
|
|
||||||
if tt.createConfigFile {
|
|
||||||
config := &cloud.Config{
|
|
||||||
Server: cloud.Server{
|
|
||||||
URL: "https://example.com",
|
|
||||||
},
|
|
||||||
Api: cloud.Api{
|
|
||||||
URL: "https://api.example.com",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
err := config.Save()
|
|
||||||
require.NoError(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
err := Logout()
|
|
||||||
require.NoError(t, err)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestLogin(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
token string
|
|
||||||
serverResponse int
|
|
||||||
wantErr string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "successful login with valid token",
|
|
||||||
token: "valid-token-123",
|
|
||||||
serverResponse: http.StatusOK,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "login fails with empty token",
|
|
||||||
token: "",
|
|
||||||
serverResponse: http.StatusOK,
|
|
||||||
wantErr: "token is required for Trivy Cloud login",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "login fails with server error",
|
|
||||||
token: "valid-token-123",
|
|
||||||
serverResponse: http.StatusUnauthorized,
|
|
||||||
wantErr: "failed to verify token: received status code 401",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "login fails with server internal error",
|
|
||||||
token: "valid-token-123",
|
|
||||||
serverResponse: http.StatusInternalServerError,
|
|
||||||
wantErr: "failed to verify token: received status code 500",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
tempDir := t.TempDir()
|
|
||||||
t.Setenv("XDG_DATA_HOME", tempDir)
|
|
||||||
|
|
||||||
keyring.MockInit()
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
defer keyring.DeleteAll(cloud.ServiceName)
|
|
||||||
|
|
||||||
defer cloud.Clear()
|
|
||||||
cloud.Clear()
|
|
||||||
|
|
||||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
assert.Equal(t, http.MethodPost, r.Method)
|
|
||||||
assert.Equal(t, "/verify", r.URL.Path)
|
|
||||||
|
|
||||||
if tt.token != "" {
|
|
||||||
expectedAuth := "Bearer " + tt.token
|
|
||||||
assert.Equal(t, expectedAuth, r.Header.Get("Authorization"))
|
|
||||||
}
|
|
||||||
|
|
||||||
w.WriteHeader(tt.serverResponse)
|
|
||||||
}))
|
|
||||||
defer server.Close()
|
|
||||||
|
|
||||||
opts := flag.Options{
|
|
||||||
CloudOptions: flag.CloudOptions{
|
|
||||||
LoginCredentials: flag.CloudLoginCredentials{
|
|
||||||
Token: tt.token,
|
|
||||||
},
|
|
||||||
ApiUrl: server.URL + "/api",
|
|
||||||
TrivyServerUrl: server.URL,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx := context.Background()
|
|
||||||
err := Login(ctx, opts)
|
|
||||||
|
|
||||||
if tt.wantErr != "" {
|
|
||||||
require.ErrorContains(t, err, tt.wantErr)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
config, err := cloud.Load()
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.Equal(t, tt.token, config.Token)
|
|
||||||
require.Equal(t, server.URL, config.Server.URL)
|
|
||||||
require.Equal(t, server.URL+"/api", config.Api.URL)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,75 +0,0 @@
|
|||||||
package flag
|
|
||||||
|
|
||||||
import "github.com/aquasecurity/trivy/pkg/cloud"
|
|
||||||
|
|
||||||
var (
|
|
||||||
CloudTokenFlag = Flag[string]{
|
|
||||||
Name: "token",
|
|
||||||
ConfigName: "cloud.token",
|
|
||||||
Usage: "Token used to athenticate with Trivy Cloud platform",
|
|
||||||
}
|
|
||||||
|
|
||||||
CloudApiUrlFlag = Flag[string]{
|
|
||||||
Name: "api-url",
|
|
||||||
ConfigName: "cloud.api-url",
|
|
||||||
Default: cloud.DefaultApiUrl,
|
|
||||||
Usage: "API URL for Trivy Cloud platform",
|
|
||||||
}
|
|
||||||
|
|
||||||
CloudTrivyServerUrlFlag = Flag[string]{
|
|
||||||
Name: "trivy-server-url",
|
|
||||||
ConfigName: "cloud.trivy_server_url",
|
|
||||||
Default: cloud.DefaultTrivyServerUrl,
|
|
||||||
Usage: "Trivy Server URL for Trivy Cloud platform",
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
type CloudFlagGroup struct {
|
|
||||||
CloudToken *Flag[string]
|
|
||||||
CloudApiUrl *Flag[string]
|
|
||||||
CloudTrivyServerUrl *Flag[string]
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewCloudFlagGroup() *CloudFlagGroup {
|
|
||||||
return &CloudFlagGroup{
|
|
||||||
CloudToken: CloudTokenFlag.Clone(),
|
|
||||||
CloudApiUrl: CloudApiUrlFlag.Clone(),
|
|
||||||
CloudTrivyServerUrl: CloudTrivyServerUrlFlag.Clone(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *CloudFlagGroup) Name() string {
|
|
||||||
return "Trivy Cloud"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *CloudFlagGroup) Flags() []Flagger {
|
|
||||||
return []Flagger{
|
|
||||||
f.CloudToken,
|
|
||||||
f.CloudApiUrl,
|
|
||||||
f.CloudTrivyServerUrl,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// CloudLoginCredentials is the credentials used to authenticate with Trivy Cloud platform
|
|
||||||
// In the future this would likely have more information stored for refresh tokens, etc
|
|
||||||
type CloudLoginCredentials struct {
|
|
||||||
Token string
|
|
||||||
}
|
|
||||||
|
|
||||||
type CloudOptions struct {
|
|
||||||
LoginCredentials CloudLoginCredentials
|
|
||||||
ApiUrl string
|
|
||||||
TrivyServerUrl string
|
|
||||||
}
|
|
||||||
|
|
||||||
// ToOptions converts the flags to options
|
|
||||||
func (f *CloudFlagGroup) ToOptions(opts *Options) error {
|
|
||||||
opts.CloudOptions = CloudOptions{
|
|
||||||
LoginCredentials: CloudLoginCredentials{
|
|
||||||
Token: f.CloudToken.Value(),
|
|
||||||
},
|
|
||||||
ApiUrl: f.CloudApiUrl.Value(),
|
|
||||||
TrivyServerUrl: f.CloudTrivyServerUrl.Value(),
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
@@ -406,7 +406,6 @@ type Options struct {
|
|||||||
RemoteOptions
|
RemoteOptions
|
||||||
RepoOptions
|
RepoOptions
|
||||||
ReportOptions
|
ReportOptions
|
||||||
CloudOptions
|
|
||||||
ScanOptions
|
ScanOptions
|
||||||
SecretOptions
|
SecretOptions
|
||||||
VulnerabilityOptions
|
VulnerabilityOptions
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ const (
|
|||||||
PrefixJavaDB = "javadb"
|
PrefixJavaDB = "javadb"
|
||||||
PrefixSPDX = "spdx"
|
PrefixSPDX = "spdx"
|
||||||
PrefixCycloneDX = "cyclonedx"
|
PrefixCycloneDX = "cyclonedx"
|
||||||
PrefixCloud = "cloud"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Logger is an alias of slog.Logger
|
// Logger is an alias of slog.Logger
|
||||||
|
|||||||
Reference in New Issue
Block a user