diff --git a/.github/workflows/auto-close-issue.yaml b/.github/workflows/auto-close-issue.yaml index 679b34bb1232..88495a3b7058 100644 --- a/.github/workflows/auto-close-issue.yaml +++ b/.github/workflows/auto-close-issue.yaml @@ -9,7 +9,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Close issue if user does not have write or admin permissions - uses: actions/github-script@v6 + uses: actions/github-script@v7 with: script: | // Get the issue creator's username diff --git a/.github/workflows/reusable-release.yaml b/.github/workflows/reusable-release.yaml index 4844ba19ae54..4850a45ad96c 100644 --- a/.github/workflows/reusable-release.yaml +++ b/.github/workflows/reusable-release.yaml @@ -27,7 +27,7 @@ jobs: contents: read # Not required for public repositories, but for clarity steps: - name: Maximize build space - uses: easimon/maximize-build-space@v8 + uses: easimon/maximize-build-space@v9 with: root-reserve-mb: 35840 # The Go cache (`~/.cache/go-build` and `~/go/pkg`) requires a lot of storage space. remove-android: 'true' diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 055a7ce46324..e2552b0d2566 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -89,7 +89,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Maximize build space - uses: easimon/maximize-build-space@v8 + uses: easimon/maximize-build-space@v9 with: root-reserve-mb: 35840 # The Go cache (`~/.cache/go-build` and `~/go/pkg`) requires a lot of storage space. remove-android: "true" @@ -140,7 +140,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Maximize build space - uses: easimon/maximize-build-space@v8 + uses: easimon/maximize-build-space@v9 with: root-reserve-mb: 35840 # The Go cache (`~/.cache/go-build` and `~/go/pkg`) requires a lot of storage space. remove-android: 'true' @@ -173,7 +173,7 @@ jobs: DOCKER_CLI_EXPERIMENTAL: "enabled" steps: - name: Maximize build space - uses: easimon/maximize-build-space@v8 + uses: easimon/maximize-build-space@v9 with: root-reserve-mb: 35840 # The Go cache (`~/.cache/go-build` and `~/go/pkg`) requires a lot of storage space. remove-android: 'true' diff --git a/Dockerfile b/Dockerfile index 43d6ddeeb0ed..f8a548e2af86 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM alpine:3.18.4 +FROM alpine:3.18.5 RUN apk --no-cache add ca-certificates git COPY trivy /usr/local/bin/trivy COPY contrib/*.tpl contrib/ diff --git a/Dockerfile.canary b/Dockerfile.canary index 1ef0d0307810..93a38cbc5138 100644 --- a/Dockerfile.canary +++ b/Dockerfile.canary @@ -1,4 +1,4 @@ -FROM alpine:3.18.4 +FROM alpine:3.18.5 RUN apk --no-cache add ca-certificates git # binaries were created with GoReleaser diff --git a/cmd/trivy/main.go b/cmd/trivy/main.go index d07ec31e817e..e2c545975315 100644 --- a/cmd/trivy/main.go +++ b/cmd/trivy/main.go @@ -25,7 +25,7 @@ func run() error { if !plugin.IsPredefined(runAsPlugin) { return xerrors.Errorf("unknown plugin: %s", runAsPlugin) } - if err := plugin.RunWithArgs(context.Background(), runAsPlugin, os.Args[1:]); err != nil { + if err := plugin.RunWithURL(context.Background(), runAsPlugin, plugin.RunOptions{Args: os.Args[1:]}); err != nil { return xerrors.Errorf("plugin error: %w", err) } return nil diff --git a/docs/docs/advanced/modules.md b/docs/docs/advanced/modules.md index 71a56a0cdc32..f12d87b8df79 100644 --- a/docs/docs/advanced/modules.md +++ b/docs/docs/advanced/modules.md @@ -328,7 +328,7 @@ Put the built binary to the module directory that is under the home directory by ```bash $ mkdir -p ~/.trivy/modules -$ cp spring4shell.wasm ~/.trivy/modules +$ cp wordpress.wasm ~/.trivy/modules ``` ## Distribute Your Module diff --git a/docs/docs/advanced/plugins.md b/docs/docs/advanced/plugins.md index 390b9cfa565e..dfdfb31d8c0d 100644 --- a/docs/docs/advanced/plugins.md +++ b/docs/docs/advanced/plugins.md @@ -182,8 +182,51 @@ $ trivy myplugin Hello from Trivy demo plugin! ``` +## Plugin Types +Plugins are typically intended to be used as subcommands of Trivy, +but some plugins can be invoked as part of Trivy's built-in commands. +Currently, the following type of plugin is experimentally supported: + +- Output plugins + +### Output Plugins + +!!! warning "EXPERIMENTAL" + This feature might change without preserving backwards compatibility. + +Trivy supports "output plugins" which process Trivy's output, +such as by transforming the output format or sending it elsewhere. +For instance, in the case of image scanning, the output plugin can be called as follows: + +```shell +$ trivy image --format json --output plugin= [--output-plugin-arg ] +``` + +Since scan results are passed to the plugin via standard input, plugins must be capable of handling standard input. + +!!! warning + To avoid Trivy hanging, you need to read all data from `Stdin` before the plugin exits successfully or stops with an error. + +While the example passes JSON to the plugin, other formats like SBOM can also be passed (e.g., `--format cyclonedx`). + +If a plugin requires flags or other arguments, they can be passed using `--output-plugin-arg`. +This is directly forwarded as arguments to the plugin. +For example, `--output plugin=myplugin --output-plugin-arg "--foo --bar=baz"` translates to `myplugin --foo --bar=baz` in execution. + +An example of the output plugin is available [here](https://github.com/aquasecurity/trivy-output-plugin-count). +It can be used as below: + +```shell +# Install the plugin first +$ trivy plugin install github.com/aquasecurity/trivy-output-plugin-count + +# Call the output plugin in image scanning +$ trivy image --format json --output plugin=count --output-plugin-arg "--published-after 2023-10-01" debian:12 +``` + ## Example -https://github.com/aquasecurity/trivy-plugin-kubectl +- https://github.com/aquasecurity/trivy-plugin-kubectl +- https://github.com/aquasecurity/trivy-output-plugin-count [kubectl]: https://kubernetes.io/docs/tasks/extend-kubectl/kubectl-plugins/ [helm]: https://helm.sh/docs/topics/plugins/ diff --git a/docs/docs/configuration/reporting.md b/docs/docs/configuration/reporting.md index 17aa6fd973ec..93468222e99b 100644 --- a/docs/docs/configuration/reporting.md +++ b/docs/docs/configuration/reporting.md @@ -1,6 +1,6 @@ # Reporting -## Supported Formats +## Format Trivy supports the following formats: - Table @@ -373,6 +373,33 @@ $ trivy image --format template --template "@/usr/local/share/trivy/templates/ht ### SBOM See [here](../supply-chain/sbom.md) for details. +## Output +Trivy supports the following output destinations: + +- File +- Plugin + +### File +By specifying `--output `, you can output the results to a file. +Here is an example: + +``` +$ trivy image --format json --output result.json debian:12 +``` + +### Plugin +!!! warning "EXPERIMENTAL" + This feature might change without preserving backwards compatibility. + +Plugins capable of receiving Trivy's results via standard input, called "output plugin", can be seamlessly invoked using the `--output` flag. + +``` +$ trivy [--format ] --output plugin= [--output-plugin-arg ] +``` + +This is useful for cases where you want to convert the output into a custom format, or when you want to send the output somewhere. +For more details, please check [here](../advanced/plugins.md#output-plugins). + ## Converting To generate multiple reports, you can generate the JSON report first and convert it to other formats with the `convert` subcommand. diff --git a/docs/docs/references/configuration/cli/trivy_aws.md b/docs/docs/references/configuration/cli/trivy_aws.md index 590162972b39..0218ccb1e987 100644 --- a/docs/docs/references/configuration/cli/trivy_aws.md +++ b/docs/docs/references/configuration/cli/trivy_aws.md @@ -86,7 +86,9 @@ trivy aws [flags] --include-non-failures include successes and exceptions, available with '--scanners misconfig' --list-all-pkgs enabling the option will output all packages regardless of vulnerability --max-cache-age duration The maximum age of the cloud cache. Cached data will be requeried from the cloud provider if it is older than this. (default 24h0m0s) + --misconfig-scanners strings comma-separated list of misconfig scanners to use for misconfiguration scanning (default [azure-arm,cloudformation,dockerfile,helm,kubernetes,terraform,terraformplan]) -o, --output string output file name + --output-plugin-arg string [EXPERIMENTAL] output plugin arguments --policy-bundle-repository string OCI registry URL to retrieve policy bundle from (default "ghcr.io/aquasecurity/trivy-policies:0") --policy-namespaces strings Rego namespaces --region string AWS Region to scan diff --git a/docs/docs/references/configuration/cli/trivy_config.md b/docs/docs/references/configuration/cli/trivy_config.md index 0d26452a10b1..79d99cad7331 100644 --- a/docs/docs/references/configuration/cli/trivy_config.md +++ b/docs/docs/references/configuration/cli/trivy_config.md @@ -29,8 +29,10 @@ trivy config [flags] DIR --ignorefile string specify .trivyignore file (default ".trivyignore") --include-non-failures include successes and exceptions, available with '--scanners misconfig' --k8s-version string specify k8s version to validate outdated api by it (example: 1.21.0) + --misconfig-scanners strings comma-separated list of misconfig scanners to use for misconfiguration scanning (default [azure-arm,cloudformation,dockerfile,helm,kubernetes,terraform,terraformplan]) --module-dir string specify directory to the wasm modules that will be loaded (default "$HOME/.trivy/modules") -o, --output string output file name + --output-plugin-arg string [EXPERIMENTAL] output plugin arguments --password strings password. Comma-separated passwords allowed. TRIVY_PASSWORD should be used for security reasons. --policy-bundle-repository string OCI registry URL to retrieve policy bundle from (default "ghcr.io/aquasecurity/trivy-policies:0") --policy-namespaces strings Rego namespaces diff --git a/docs/docs/references/configuration/cli/trivy_convert.md b/docs/docs/references/configuration/cli/trivy_convert.md index 9ef4cc5583b0..409e1009951d 100644 --- a/docs/docs/references/configuration/cli/trivy_convert.md +++ b/docs/docs/references/configuration/cli/trivy_convert.md @@ -18,19 +18,20 @@ trivy convert [flags] RESULT_JSON ### Options ``` - --compliance string compliance report to generate - --dependency-tree [EXPERIMENTAL] show dependency origin tree of vulnerable packages - --exit-code int specify exit code when any security issues are found - --exit-on-eol int exit with the specified code when the OS reaches end of service/life - -f, --format string format (table,json,template,sarif,cyclonedx,spdx,spdx-json,github,cosign-vuln) (default "table") - -h, --help help for convert - --ignore-policy string specify the Rego file path to evaluate each vulnerability - --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 strings severities of security issues to be displayed (UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL) (default [UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL]) - -t, --template string output template + --compliance string compliance report to generate + --dependency-tree [EXPERIMENTAL] show dependency origin tree of vulnerable packages + --exit-code int specify exit code when any security issues are found + --exit-on-eol int exit with the specified code when the OS reaches end of service/life + -f, --format string format (table,json,template,sarif,cyclonedx,spdx,spdx-json,github,cosign-vuln) (default "table") + -h, --help help for convert + --ignore-policy string specify the Rego file path to evaluate each vulnerability + --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 + --output-plugin-arg string [EXPERIMENTAL] output plugin arguments + --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 ``` ### Options inherited from parent commands diff --git a/docs/docs/references/configuration/cli/trivy_filesystem.md b/docs/docs/references/configuration/cli/trivy_filesystem.md index 89d034caaa4d..c09c46f69575 100644 --- a/docs/docs/references/configuration/cli/trivy_filesystem.md +++ b/docs/docs/references/configuration/cli/trivy_filesystem.md @@ -51,10 +51,12 @@ trivy filesystem [flags] PATH --license-confidence-level float specify license classifier's confidence level (default 0.9) --license-full eagerly look for licenses in source code headers and license files --list-all-pkgs enabling the option will output all packages regardless of vulnerability + --misconfig-scanners strings comma-separated list of misconfig scanners to use for misconfiguration scanning (default [azure-arm,cloudformation,dockerfile,helm,kubernetes,terraform,terraformplan]) --module-dir string specify directory to the wasm modules that will be loaded (default "$HOME/.trivy/modules") --no-progress suppress progress bar --offline-scan do not issue API requests to identify dependencies -o, --output string output file name + --output-plugin-arg string [EXPERIMENTAL] output plugin arguments --parallel int number of goroutines enabled for parallel scanning, set 0 to auto-detect parallelism (default 5) --password strings password. Comma-separated passwords allowed. TRIVY_PASSWORD should be used for security reasons. --policy-bundle-repository string OCI registry URL to retrieve policy bundle from (default "ghcr.io/aquasecurity/trivy-policies:0") diff --git a/docs/docs/references/configuration/cli/trivy_image.md b/docs/docs/references/configuration/cli/trivy_image.md index 10ac0518944b..c08206a51a5b 100644 --- a/docs/docs/references/configuration/cli/trivy_image.md +++ b/docs/docs/references/configuration/cli/trivy_image.md @@ -69,10 +69,12 @@ trivy image [flags] IMAGE_NAME --license-confidence-level float specify license classifier's confidence level (default 0.9) --license-full eagerly look for licenses in source code headers and license files --list-all-pkgs enabling the option will output all packages regardless of vulnerability + --misconfig-scanners strings comma-separated list of misconfig scanners to use for misconfiguration scanning (default [azure-arm,cloudformation,dockerfile,helm,kubernetes,terraform,terraformplan]) --module-dir string specify directory to the wasm modules that will be loaded (default "$HOME/.trivy/modules") --no-progress suppress progress bar --offline-scan do not issue API requests to identify dependencies -o, --output string output file name + --output-plugin-arg string [EXPERIMENTAL] output plugin arguments --parallel int number of goroutines enabled for parallel scanning, set 0 to auto-detect parallelism (default 5) --password strings password. Comma-separated passwords allowed. TRIVY_PASSWORD should be used for security reasons. --platform string set platform in the form os/arch if image is multi-platform capable diff --git a/docs/docs/references/configuration/cli/trivy_kubernetes.md b/docs/docs/references/configuration/cli/trivy_kubernetes.md index 93d44ad04c3e..9599ca493d84 100644 --- a/docs/docs/references/configuration/cli/trivy_kubernetes.md +++ b/docs/docs/references/configuration/cli/trivy_kubernetes.md @@ -60,11 +60,14 @@ trivy kubernetes [flags] { cluster | all | specific resources like kubectl. eg: --k8s-version string specify k8s version to validate outdated api by it (example: 1.21.0) --kubeconfig string specify the kubeconfig file path to use --list-all-pkgs enabling the option will output all packages regardless of vulnerability + --misconfig-scanners strings comma-separated list of misconfig scanners to use for misconfiguration scanning (default [azure-arm,cloudformation,dockerfile,helm,kubernetes,terraform,terraformplan]) -n, --namespace string specify a namespace to scan --no-progress suppress progress bar + --node-collector-imageref string indicate the image reference for the node-collector scan job (default "ghcr.io/aquasecurity/node-collector:0.0.9") --node-collector-namespace string specify the namespace in which the node-collector job should be deployed (default "trivy-temp") --offline-scan do not issue API requests to identify dependencies -o, --output string output file name + --output-plugin-arg string [EXPERIMENTAL] output plugin arguments --parallel int number of goroutines enabled for parallel scanning, set 0 to auto-detect parallelism (default 5) --password strings password. Comma-separated passwords allowed. TRIVY_PASSWORD should be used for security reasons. --policy-bundle-repository string OCI registry URL to retrieve policy bundle from (default "ghcr.io/aquasecurity/trivy-policies:0") diff --git a/docs/docs/references/configuration/cli/trivy_repository.md b/docs/docs/references/configuration/cli/trivy_repository.md index a88e9be5bf30..4f2a9f65d30b 100644 --- a/docs/docs/references/configuration/cli/trivy_repository.md +++ b/docs/docs/references/configuration/cli/trivy_repository.md @@ -51,10 +51,12 @@ trivy repository [flags] (REPO_PATH | REPO_URL) --license-confidence-level float specify license classifier's confidence level (default 0.9) --license-full eagerly look for licenses in source code headers and license files --list-all-pkgs enabling the option will output all packages regardless of vulnerability + --misconfig-scanners strings comma-separated list of misconfig scanners to use for misconfiguration scanning (default [azure-arm,cloudformation,dockerfile,helm,kubernetes,terraform,terraformplan]) --module-dir string specify directory to the wasm modules that will be loaded (default "$HOME/.trivy/modules") --no-progress suppress progress bar --offline-scan do not issue API requests to identify dependencies -o, --output string output file name + --output-plugin-arg string [EXPERIMENTAL] output plugin arguments --parallel int number of goroutines enabled for parallel scanning, set 0 to auto-detect parallelism (default 5) --password strings password. Comma-separated passwords allowed. TRIVY_PASSWORD should be used for security reasons. --policy-bundle-repository string OCI registry URL to retrieve policy bundle from (default "ghcr.io/aquasecurity/trivy-policies:0") diff --git a/docs/docs/references/configuration/cli/trivy_rootfs.md b/docs/docs/references/configuration/cli/trivy_rootfs.md index d04ee44ba113..aaa120285021 100644 --- a/docs/docs/references/configuration/cli/trivy_rootfs.md +++ b/docs/docs/references/configuration/cli/trivy_rootfs.md @@ -53,10 +53,12 @@ trivy rootfs [flags] ROOTDIR --license-confidence-level float specify license classifier's confidence level (default 0.9) --license-full eagerly look for licenses in source code headers and license files --list-all-pkgs enabling the option will output all packages regardless of vulnerability + --misconfig-scanners strings comma-separated list of misconfig scanners to use for misconfiguration scanning (default [azure-arm,cloudformation,dockerfile,helm,kubernetes,terraform,terraformplan]) --module-dir string specify directory to the wasm modules that will be loaded (default "$HOME/.trivy/modules") --no-progress suppress progress bar --offline-scan do not issue API requests to identify dependencies -o, --output string output file name + --output-plugin-arg string [EXPERIMENTAL] output plugin arguments --parallel int number of goroutines enabled for parallel scanning, set 0 to auto-detect parallelism (default 5) --password strings password. Comma-separated passwords allowed. TRIVY_PASSWORD should be used for security reasons. --policy-bundle-repository string OCI registry URL to retrieve policy bundle from (default "ghcr.io/aquasecurity/trivy-policies:0") diff --git a/docs/docs/references/configuration/cli/trivy_sbom.md b/docs/docs/references/configuration/cli/trivy_sbom.md index 9f899ac977cb..b0fd202863b0 100644 --- a/docs/docs/references/configuration/cli/trivy_sbom.md +++ b/docs/docs/references/configuration/cli/trivy_sbom.md @@ -42,6 +42,7 @@ trivy sbom [flags] SBOM_PATH --no-progress suppress progress bar --offline-scan do not issue API requests to identify dependencies -o, --output string output file name + --output-plugin-arg string [EXPERIMENTAL] output plugin arguments --redis-ca string redis ca file location, if using redis as cache backend --redis-cert string redis certificate file location, if using redis as cache backend --redis-key string redis key file location, if using redis as cache backend diff --git a/docs/docs/references/configuration/cli/trivy_vm.md b/docs/docs/references/configuration/cli/trivy_vm.md index eb6506c7585d..2b004b6992e9 100644 --- a/docs/docs/references/configuration/cli/trivy_vm.md +++ b/docs/docs/references/configuration/cli/trivy_vm.md @@ -47,10 +47,12 @@ trivy vm [flags] VM_IMAGE --include-non-failures include successes and exceptions, available with '--scanners misconfig' --java-db-repository string OCI repository to retrieve trivy-java-db from (default "ghcr.io/aquasecurity/trivy-java-db") --list-all-pkgs enabling the option will output all packages regardless of vulnerability + --misconfig-scanners strings comma-separated list of misconfig scanners to use for misconfiguration scanning (default [azure-arm,cloudformation,dockerfile,helm,kubernetes,terraform,terraformplan]) --module-dir string specify directory to the wasm modules that will be loaded (default "$HOME/.trivy/modules") --no-progress suppress progress bar --offline-scan do not issue API requests to identify dependencies -o, --output string output file name + --output-plugin-arg string [EXPERIMENTAL] output plugin arguments --parallel int number of goroutines enabled for parallel scanning, set 0 to auto-detect parallelism (default 5) --policy-bundle-repository string OCI registry URL to retrieve policy bundle from (default "ghcr.io/aquasecurity/trivy-policies:0") --redis-ca string redis ca file location, if using redis as cache backend diff --git a/docs/docs/references/configuration/config-file.md b/docs/docs/references/configuration/config-file.md index b85cfded4667..23b5a3778345 100644 --- a/docs/docs/references/configuration/config-file.md +++ b/docs/docs/references/configuration/config-file.md @@ -266,6 +266,12 @@ misconfiguration: # Same as '--include-non-failures' # Default is false include-non-failures: false + + # Same as '--miconfig-scanners' + # Default is all scanners + scanners: + - dockerfile + - terraform # helm value override configurations # set individual values diff --git a/docs/docs/scanner/misconfiguration/index.md b/docs/docs/scanner/misconfiguration/index.md index 8a2606a31a4e..23c883a70ab1 100644 --- a/docs/docs/scanner/misconfiguration/index.md +++ b/docs/docs/scanner/misconfiguration/index.md @@ -315,6 +315,15 @@ Failures: 2 (MEDIUM: 2, HIGH: 0, CRITICAL: 0) This section describes misconfiguration-specific configuration. Other common options are documented [here](../../configuration/index.md). +### Enabling a subset of misconfiguration scanners +It's possible to only enable certain misconfiguration scanners if you prefer. You can do so by passing the `--misconfig-scanners` option. +This flag takes a comma-separated list of configuration scanner types. +```bash +trivy config --misconfig-scanners=terraform,dockerfile . +``` + +Will only scan for misconfigurations that pertain to Terraform and Dockerfiles. + ### Pass custom policies You can pass policy files or directories including your custom policies through `--policy` option. This can be repeated for specifying multiple files or directories. diff --git a/go.mod b/go.mod index f3f27278c603..2251df877847 100644 --- a/go.mod +++ b/go.mod @@ -4,14 +4,14 @@ go 1.21 require ( github.com/Azure/azure-sdk-for-go v68.0.0+incompatible - github.com/Azure/azure-sdk-for-go/sdk/azcore v1.7.1 - github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.1 + github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.0 + github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.4.0 github.com/BurntSushi/toml v1.3.2 github.com/CycloneDX/cyclonedx-go v0.7.2 github.com/GoogleCloudPlatform/docker-credential-gcr v2.0.5+incompatible github.com/Masterminds/sprig/v3 v3.2.3 github.com/NYTimes/gziphandler v1.1.1 - github.com/alicebob/miniredis/v2 v2.30.4 + github.com/alicebob/miniredis/v2 v2.31.0 github.com/aquasecurity/bolt-fixtures v0.0.0-20200903104109-d34e7f983986 github.com/aquasecurity/defsec v0.93.2-0.20231120220217-6818261529c8 github.com/aquasecurity/go-dep-parser v0.0.0-20231120074854-8322cc2242bf @@ -27,7 +27,7 @@ require ( github.com/aquasecurity/trivy-db v0.0.0-20231005141211-4fc651f7ac8d github.com/aquasecurity/trivy-iac v0.7.0 github.com/aquasecurity/trivy-java-db v0.0.0-20230209231723-7cddb1406728 - github.com/aquasecurity/trivy-kubernetes v0.5.9-0.20231129133524-978b21aff81d + github.com/aquasecurity/trivy-kubernetes v0.5.9-0.20231203080602-50a069120091 github.com/aquasecurity/trivy-policies v0.6.1-0.20231120231532-f6f2330bf842 github.com/aws/aws-sdk-go-v2 v1.22.1 github.com/aws/aws-sdk-go-v2/config v1.18.45 @@ -44,13 +44,13 @@ require ( github.com/docker/docker v24.0.7+incompatible github.com/docker/go-connections v0.4.0 github.com/fatih/color v1.15.0 - github.com/go-git/go-git/v5 v5.8.1 + github.com/go-git/go-git/v5 v5.10.1 github.com/go-openapi/runtime v0.26.0 github.com/go-openapi/strfmt v0.21.7 github.com/go-redis/redis/v8 v8.11.5 github.com/golang-jwt/jwt v3.2.2+incompatible github.com/golang/protobuf v1.5.3 - github.com/google/go-containerregistry v0.16.1 + github.com/google/go-containerregistry v0.17.0 github.com/google/licenseclassifier/v2 v2.0.0 github.com/google/uuid v1.3.1 github.com/google/wire v0.5.0 @@ -72,6 +72,7 @@ require ( github.com/masahiro331/go-mvn-version v0.0.0-20210429150710-d3157d602a08 github.com/masahiro331/go-vmdk-parser v0.0.0-20221225061455-612096e4bbbd github.com/masahiro331/go-xfs-filesystem v0.0.0-20230608043311-a335f4599b70 + github.com/mattn/go-shellwords v1.0.12 github.com/mitchellh/hashstructure/v2 v2.0.2 github.com/mitchellh/mapstructure v1.5.0 github.com/moby/buildkit v0.11.6 @@ -124,7 +125,7 @@ require ( dario.cat/mergo v1.0.0 // indirect github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 // indirect github.com/AdamKorcz/go-118-fuzz-build v0.0.0-20230306123547-8075edf89bb0 // indirect - github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 // indirect + github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.0 // indirect github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect github.com/Azure/go-autorest v14.2.0+incompatible // indirect github.com/Azure/go-autorest/autorest v0.11.29 // indirect @@ -141,9 +142,8 @@ require ( github.com/Microsoft/go-winio v0.6.1 // indirect github.com/Microsoft/hcsshim v0.11.1 // indirect github.com/OneOfOne/xxhash v1.2.8 // indirect - github.com/ProtonMail/go-crypto v0.0.0-20230717121422-5aa5874ade95 // indirect + github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371 // indirect github.com/VividCortex/ewma v1.2.0 // indirect - github.com/acomagu/bufpipe v1.0.4 // indirect github.com/agext/levenshtein v1.2.3 // indirect github.com/agnivade/levenshtein v1.1.1 // indirect github.com/alecthomas/chroma v0.10.0 // indirect @@ -236,7 +236,7 @@ require ( github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/go-errors/errors v1.4.2 // indirect github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect - github.com/go-git/go-billy/v5 v5.4.1 // indirect + github.com/go-git/go-billy/v5 v5.5.0 // indirect github.com/go-gorp/gorp/v3 v3.1.0 // indirect github.com/go-ini/ini v1.67.0 // indirect github.com/go-logr/logr v1.3.0 // indirect @@ -342,7 +342,7 @@ require ( github.com/sergi/go-diff v1.2.0 // indirect github.com/shibumi/go-pathspec v1.3.0 // indirect github.com/shopspring/decimal v1.3.1 // indirect - github.com/skeema/knownhosts v1.2.0 // indirect + github.com/skeema/knownhosts v1.2.1 // indirect github.com/spf13/afero v1.9.5 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/stretchr/objx v0.5.0 // indirect diff --git a/go.sum b/go.sum index 0e21905e46ba..25c06c78abbd 100644 --- a/go.sum +++ b/go.sum @@ -199,12 +199,12 @@ github.com/AdamKorcz/go-118-fuzz-build v0.0.0-20230306123547-8075edf89bb0/go.mod github.com/Azure/azure-sdk-for-go v16.2.1+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= github.com/Azure/azure-sdk-for-go v68.0.0+incompatible h1:fcYLmCpyNYRnvJbPerq7U0hS+6+I79yEDJBqVNcqUzU= github.com/Azure/azure-sdk-for-go v68.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.7.1 h1:/iHxaJhsFr0+xVFfbMr5vxz848jyiWuIEDhYq3y5odY= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.7.1/go.mod h1:bjGvMhVMb+EEm3VRNQawDMUyMMjo+S5ewNjflkep/0Q= -github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.1 h1:LNHhpdK7hzUcx/k1LIcuh5k7k1LGIWLQfCjaneSj7Fc= -github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.1/go.mod h1:uE9zaUfEQT/nbQjVi2IblCG9iaLtZsuYZ8ne+PuQ02M= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 h1:sXr+ck84g/ZlZUOZiNELInmMgOsuGwdjjVkEIde0OtY= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0/go.mod h1:okt5dMMTOFjX/aovMlrjvvXoPMBVSPzk9185BT0+eZM= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.0 h1:fb8kj/Dh4CSwgsOzHeZY4Xh68cFVbzXx+ONXGMY//4w= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.0/go.mod h1:uReU2sSxZExRPBAg3qKzmAucSi51+SP1OhohieR821Q= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.4.0 h1:BMAjVKJM0U/CYF27gA0ZMmXGkOcvfFtD0oHVZ1TIPRI= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.4.0/go.mod h1:1fXstnBMas5kzG+S3q8UoJcmyU6nUeunJcMDHcRYHhs= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.0 h1:d81/ng9rET2YqdVkVwkb6EXeRrLJIwyGnJcAlAWKwhs= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.0/go.mod h1:s4kgfzA0covAXNicZHDMN58jExvcng2mC/DepXiF1EI= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= @@ -240,6 +240,7 @@ github.com/CycloneDX/cyclonedx-go v0.7.2 h1:kKQ0t1dPOlugSIYVOMiMtFqeXI2wp/f5DBId github.com/CycloneDX/cyclonedx-go v0.7.2/go.mod h1:K2bA+324+Og0X84fA8HhN2X066K7Bxz4rpMQ4ZhjtSk= github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60= github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= +github.com/DmitriyVTitov/size v1.5.0/go.mod h1:le6rNI4CoLQV1b9gzp1+3d7hMAD/uu2QcJ+aYbNgiU0= github.com/GoogleCloudPlatform/docker-credential-gcr v2.0.5+incompatible h1:juIaKLLVhqzP55d8x4cSVgwyQv76Z55/fRv/UBr2KkQ= github.com/GoogleCloudPlatform/docker-credential-gcr v2.0.5+incompatible/go.mod h1:BB1eHdMLYEFuFdBlRMb0N7YGVdM5s6Pt0njxgvfbGGs= github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ= @@ -284,16 +285,14 @@ github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMo github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/OneOfOne/xxhash v1.2.8 h1:31czK/TI9sNkxIKfaUfGlU47BAxQ0ztGgd9vPyqimf8= github.com/OneOfOne/xxhash v1.2.8/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q= -github.com/ProtonMail/go-crypto v0.0.0-20230717121422-5aa5874ade95 h1:KLq8BE0KwCL+mmXnjLWEAOYO+2l2AE4YMmqG1ZpZHBs= -github.com/ProtonMail/go-crypto v0.0.0-20230717121422-5aa5874ade95/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0= +github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371 h1:kkhsdkhsCvIsutKu5zLMgWtgh9YxGCNAw8Ad8hjwfYg= +github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d h1:UrqY+r/OJnIp5u0s1SbQ8dVfLCZJsnvazdBP5hS4iRs= github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ= github.com/VividCortex/ewma v1.2.0 h1:f58SaIzcDXrSy3kWaHNvuJgJ3Nmz59Zji6XoJR/q1ow= github.com/VividCortex/ewma v1.2.0/go.mod h1:nz4BbCtbLyFDeC9SUHbtcT5644juEuWfUAUnGx7j5l4= -github.com/acomagu/bufpipe v1.0.4 h1:e3H4WUzM3npvo5uv95QuJM3cQspFNtFBzvJ2oNjKIDQ= -github.com/acomagu/bufpipe v1.0.4/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4= github.com/agext/levenshtein v1.2.3 h1:YB2fHEn0UJagG8T1rrWknE3ZQzWM06O8AMAatNn7lmo= github.com/agext/levenshtein v1.2.3/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= github.com/agnivade/levenshtein v1.1.1 h1:QY8M92nrzkmr798gCo3kmMyqXFzdQVpxLlGPRBij0P8= @@ -307,8 +306,8 @@ github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRF github.com/alexflint/go-filemutex v0.0.0-20171022225611-72bdc8eae2ae/go.mod h1:CgnQgUtFrFz9mxFNtED3jI5tLDjKlOM+oUF/sTk6ps0= github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a h1:HbKu58rmZpUGpz5+4FfNmIU+FmZg2P3Xaj2v2bfNWmk= github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc= -github.com/alicebob/miniredis/v2 v2.30.4 h1:8S4/o1/KoUArAGbGwPxcwf0krlzceva2XVOSchFS7Eo= -github.com/alicebob/miniredis/v2 v2.30.4/go.mod h1:b25qWj4fCEsBeAAR2mlb0ufImGC6uH3VlUfb/HS5zKg= +github.com/alicebob/miniredis/v2 v2.31.0 h1:ObEFUNlJwoIiyjxdrYF0QIDE7qXcLc7D3WpSH4c22PU= +github.com/alicebob/miniredis/v2 v2.31.0/go.mod h1:UB/T2Uztp7MlFSDakaX1sTXUv5CASoprx0wulRT6HBg= github.com/anchore/go-struct-converter v0.0.0-20221118182256-c68fdcfa2092 h1:aM1rlcoLz8y5B2r4tTLMiVTrMtpfY0O8EScKJxaSaEc= github.com/anchore/go-struct-converter v0.0.0-20221118182256-c68fdcfa2092/go.mod h1:rYqSE9HbjzpHTI74vwPvae4ZVYZd1lue2ta6xHPdblA= github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8= @@ -353,8 +352,8 @@ github.com/aquasecurity/trivy-iac v0.7.0 h1:L2/mqQJD1iwY4xOr1un5Prg51epYBQgM34JV github.com/aquasecurity/trivy-iac v0.7.0/go.mod h1:GG9Y2YylH3e16PoJ0RUZ+C0Xw93Gic/5fwdkKjKwwqU= github.com/aquasecurity/trivy-java-db v0.0.0-20230209231723-7cddb1406728 h1:0eS+V7SXHgqoT99tV1mtMW6HL4HdoB9qGLMCb1fZp8A= github.com/aquasecurity/trivy-java-db v0.0.0-20230209231723-7cddb1406728/go.mod h1:Ldya37FLi0e/5Cjq2T5Bty7cFkzUDwTcPeQua+2M8i8= -github.com/aquasecurity/trivy-kubernetes v0.5.9-0.20231129133524-978b21aff81d h1:tv/Dpl5NhjDMdTLY3sXHJXGSpg2m6GikHwyNrpk/+aY= -github.com/aquasecurity/trivy-kubernetes v0.5.9-0.20231129133524-978b21aff81d/go.mod h1:Yh+tmpPtbqVWYONrAuapImHfD1ghZgnZHLlMBA6Ukfg= +github.com/aquasecurity/trivy-kubernetes v0.5.9-0.20231203080602-50a069120091 h1:OTJMSbvKQYxbQ2NQ8Nht2NSL1bL36YfBCrlsGGxHPlI= +github.com/aquasecurity/trivy-kubernetes v0.5.9-0.20231203080602-50a069120091/go.mod h1:Yh+tmpPtbqVWYONrAuapImHfD1ghZgnZHLlMBA6Ukfg= github.com/aquasecurity/trivy-policies v0.6.1-0.20231120231532-f6f2330bf842 h1:RnxM3eTcwPlA/WBwnmaEpeEk3WOCDcnz7yTIFxVL7us= github.com/aquasecurity/trivy-policies v0.6.1-0.20231120231532-f6f2330bf842/go.mod h1:BmEeSFgmBjo3avCli71736sy0veGcSUzGATupp1MCgA= github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0 h1:jfIu9sQUG6Ig+0+Ap1h4unLjW6YQJpKZVmUzxsD4E/Q= @@ -764,8 +763,8 @@ github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25Kn github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= -github.com/elazarl/goproxy v0.0.0-20221015165544-a0805db90819 h1:RIB4cRk+lBqKK3Oy0r2gRX4ui7tuhiZq2SuTtTCi0/0= -github.com/elazarl/goproxy v0.0.0-20221015165544-a0805db90819/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM= +github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a h1:mATvB/9r/3gvcejNsXKSkQ6lcIaNec2nyfOdlTBR2lU= +github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM= github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= github.com/emicklei/go-restful/v3 v3.10.1 h1:rc42Y5YTp7Am7CS630D7JmhRjq4UlEUuEKfrDac4bSQ= @@ -817,12 +816,12 @@ github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxI github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI= github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic= -github.com/go-git/go-billy/v5 v5.4.1 h1:Uwp5tDRkPr+l/TnbHOQzp+tmJfLceOlbVucgpTz8ix4= -github.com/go-git/go-billy/v5 v5.4.1/go.mod h1:vjbugF6Fz7JIflbVpl1hJsGjSHNltrSw45YK/ukIvQg= -github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20230305113008-0c11038e723f h1:Pz0DHeFij3XFhoBRGUDPzSJ+w2UcK5/0JvF8DRI58r8= -github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20230305113008-0c11038e723f/go.mod h1:8LHG1a3SRW71ettAD/jW13h8c6AqjVSeL11RAdgaqpo= -github.com/go-git/go-git/v5 v5.8.1 h1:Zo79E4p7TRk0xoRgMq0RShiTHGKcKI4+DI6BfJc/Q+A= -github.com/go-git/go-git/v5 v5.8.1/go.mod h1:FHFuoD6yGz5OSKEBK+aWN9Oah0q54Jxl0abmj6GnqAo= +github.com/go-git/go-billy/v5 v5.5.0 h1:yEY4yhzCDuMGSv83oGxiBotRzhwhNr8VZyphhiu+mTU= +github.com/go-git/go-billy/v5 v5.5.0/go.mod h1:hmexnoNsr2SJU1Ju67OaNz5ASJY3+sHgFRpCtpDCKow= +github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4= +github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII= +github.com/go-git/go-git/v5 v5.10.1 h1:tu8/D8i+TWxgKpzQ3Vc43e+kkhXqtsZCKI/egajKnxk= +github.com/go-git/go-git/v5 v5.10.1/go.mod h1:uEuHjxkHap8kAl//V5F/nNWwqIYtP/402ddd05mp0wg= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -1030,8 +1029,8 @@ github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-containerregistry v0.6.0/go.mod h1:euCCtNbZ6tKqi1E72vwDj2xZcN5ttKpZLfa/wSo5iLw= -github.com/google/go-containerregistry v0.16.1 h1:rUEt426sR6nyrL3gt+18ibRcvYpKYdpsa5ZW7MA08dQ= -github.com/google/go-containerregistry v0.16.1/go.mod h1:u0qB2l7mvtWVR5kNcbFIhFY1hLbf8eeGapA+vbFDCtQ= +github.com/google/go-containerregistry v0.17.0 h1:5p+zYs/R4VGHkhyvgWurWrpJ2hW4Vv9fQI+GzdcwXLk= +github.com/google/go-containerregistry v0.17.0/go.mod h1:u0qB2l7mvtWVR5kNcbFIhFY1hLbf8eeGapA+vbFDCtQ= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= @@ -1307,8 +1306,6 @@ github.com/masahiro331/go-vmdk-parser v0.0.0-20221225061455-612096e4bbbd h1:Y30E github.com/masahiro331/go-vmdk-parser v0.0.0-20221225061455-612096e4bbbd/go.mod h1:5f7mCJGW9cJb8SDn3z8qodGxpMCOo8d/2nls/tiwRrw= github.com/masahiro331/go-xfs-filesystem v0.0.0-20230608043311-a335f4599b70 h1:X6W6raTo07X0q4pvSI/68Pj/Ic4iIU2CfQU65OH0Zhc= github.com/masahiro331/go-xfs-filesystem v0.0.0-20230608043311-a335f4599b70/go.mod h1:QKBZqdn6teT0LK3QhAf3K6xakItd1LonOShOEC44idQ= -github.com/matryer/is v1.2.0 h1:92UTHpy8CDwaJ08GqLDzhhuixiBUUD1p3AU6PHddz4A= -github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= @@ -1329,6 +1326,8 @@ github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU= github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mattn/go-shellwords v1.0.3/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o= +github.com/mattn/go-shellwords v1.0.12 h1:M2zGm7EW6UQJvDeQxo4T51eKPurbeFbe8WtebGE2xrk= +github.com/mattn/go-shellwords v1.0.12/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y= github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y= github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= @@ -1434,8 +1433,8 @@ github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGV github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc= -github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE= -github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg= +github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI= +github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M= github.com/open-policy-agent/opa v0.57.0 h1:DftxYfOEHOheXvO2Q6HCIM2ZVdKrvnF4cZlU9C64MIQ= github.com/open-policy-agent/opa v0.57.0/go.mod h1:3FY6GNSbUqOhjCdvTXCBJ2rNuh66p/XrIc2owr/hSwo= github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= @@ -1559,8 +1558,8 @@ github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6L github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= -github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= +github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= +github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= github.com/rubenv/sql-migrate v1.5.2 h1:bMDqOnrJVV/6JQgQ/MxOpU+AdO8uzYYA/TxFUBzFtS0= github.com/rubenv/sql-migrate v1.5.2/go.mod h1:H38GW8Vqf8F0Su5XignRyaRcbXbJunSWxs+kmzlg0Is= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= @@ -1601,8 +1600,8 @@ github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= -github.com/skeema/knownhosts v1.2.0 h1:h9r9cf0+u7wSE+M183ZtMGgOJKiL96brpaz5ekfJCpM= -github.com/skeema/knownhosts v1.2.0/go.mod h1:g4fPeYpque7P0xefxtGzV81ihjC8sX2IqpAoNkjxbMo= +github.com/skeema/knownhosts v1.2.1 h1:SHWdIUa82uGZz+F+47k8SY4QhhI291cXCpopT1lK2AQ= +github.com/skeema/knownhosts v1.2.1/go.mod h1:xYbVRSPxqBZFrdmDyMmsOs+uX1UZC3nTN3ThzgDxUwo= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= diff --git a/pkg/cloud/aws/commands/run.go b/pkg/cloud/aws/commands/run.go index 0562dbf72e21..a4541e9f0544 100644 --- a/pkg/cloud/aws/commands/run.go +++ b/pkg/cloud/aws/commands/run.go @@ -129,7 +129,6 @@ func filterServices(opt *flag.Options) error { } func Run(ctx context.Context, opt flag.Options) error { - ctx, cancel := context.WithTimeout(ctx, opt.GlobalOptions.Timeout) defer cancel() @@ -168,7 +167,7 @@ func Run(ctx context.Context, opt flag.Options) error { } r := report.New(cloud.ProviderAWS, opt.Account, opt.Region, res, opt.Services) - if err := report.Write(r, opt, cached); err != nil { + if err := report.Write(ctx, r, opt, cached); err != nil { return xerrors.Errorf("unable to write results: %w", err) } diff --git a/pkg/cloud/report/report.go b/pkg/cloud/report/report.go index 6c7b1ac6d874..8c4fa3861b8e 100644 --- a/pkg/cloud/report/report.go +++ b/pkg/cloud/report/report.go @@ -59,8 +59,8 @@ func (r *Report) Failed() bool { } // Write writes the results in the give format -func Write(rep *Report, opt flag.Options, fromCache bool) error { - output, cleanup, err := opt.OutputWriter() +func Write(ctx context.Context, rep *Report, opt flag.Options, fromCache bool) error { + output, cleanup, err := opt.OutputWriter(ctx) if err != nil { return xerrors.Errorf("failed to create output file: %w", err) } @@ -72,8 +72,6 @@ func Write(rep *Report, opt flag.Options, fromCache bool) error { var filtered []types.Result - ctx := context.Background() - // filter results for _, resultsAtTime := range rep.Results { for _, res := range resultsAtTime.Results { @@ -137,7 +135,7 @@ func Write(rep *Report, opt flag.Options, fromCache bool) error { return nil default: - return pkgReport.Write(base, opt) + return pkgReport.Write(ctx, base, opt) } } diff --git a/pkg/cloud/report/resource_test.go b/pkg/cloud/report/resource_test.go index cb17c2658d57..3f909b8d3b3f 100644 --- a/pkg/cloud/report/resource_test.go +++ b/pkg/cloud/report/resource_test.go @@ -2,6 +2,7 @@ package report import ( "bytes" + "context" "testing" "github.com/stretchr/testify/assert" @@ -111,7 +112,7 @@ No problems detected. output := bytes.NewBuffer(nil) tt.options.SetOutputWriter(output) - require.NoError(t, Write(report, tt.options, tt.fromCache)) + require.NoError(t, Write(context.Background(), report, tt.options, tt.fromCache)) assert.Equal(t, "AWS", report.Provider) assert.Equal(t, tt.options.AWSOptions.Account, report.AccountID) diff --git a/pkg/cloud/report/result_test.go b/pkg/cloud/report/result_test.go index f0ef85d4d564..6afc67305c4f 100644 --- a/pkg/cloud/report/result_test.go +++ b/pkg/cloud/report/result_test.go @@ -2,6 +2,7 @@ package report import ( "bytes" + "context" "strings" "testing" @@ -70,7 +71,7 @@ See https://avd.aquasec.com/misconfig/avd-aws-9999 output := bytes.NewBuffer(nil) tt.options.SetOutputWriter(output) - require.NoError(t, Write(report, tt.options, tt.fromCache)) + require.NoError(t, Write(context.Background(), report, tt.options, tt.fromCache)) assert.Equal(t, "AWS", report.Provider) assert.Equal(t, tt.options.AWSOptions.Account, report.AccountID) diff --git a/pkg/cloud/report/service_test.go b/pkg/cloud/report/service_test.go index b60e6f37c7ce..507f3ff31466 100644 --- a/pkg/cloud/report/service_test.go +++ b/pkg/cloud/report/service_test.go @@ -2,6 +2,7 @@ package report import ( "bytes" + "context" "github.com/aquasecurity/trivy/pkg/clock" "testing" "time" @@ -322,7 +323,7 @@ Scan Overview for AWS Account output := bytes.NewBuffer(nil) tt.options.SetOutputWriter(output) - require.NoError(t, Write(report, tt.options, tt.fromCache)) + require.NoError(t, Write(context.Background(), report, tt.options, tt.fromCache)) assert.Equal(t, "AWS", report.Provider) assert.Equal(t, tt.options.AWSOptions.Account, report.AccountID) diff --git a/pkg/commands/app.go b/pkg/commands/app.go index fe39fb57925c..dac78354075b 100644 --- a/pkg/commands/app.go +++ b/pkg/commands/app.go @@ -124,7 +124,7 @@ func loadPluginCommands() []*cobra.Command { Short: p.Usage, GroupID: groupPlugin, RunE: func(cmd *cobra.Command, args []string) error { - if err = p.Run(cmd.Context(), args); err != nil { + if err = p.Run(cmd.Context(), plugin.RunOptions{Args: args}); err != nil { return xerrors.Errorf("plugin error: %w", err) } return nil @@ -773,7 +773,7 @@ func NewPluginCommand() *cobra.Command { Short: "Run a plugin on the fly", Args: cobra.MinimumNArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - return plugin.RunWithArgs(cmd.Context(), args[0], args[1:]) + return plugin.RunWithURL(cmd.Context(), args[0], plugin.RunOptions{Args: args[1:]}) }, }, &cobra.Command{ diff --git a/pkg/commands/artifact/run.go b/pkg/commands/artifact/run.go index 0d935f86e016..5c32c6d2b250 100644 --- a/pkg/commands/artifact/run.go +++ b/pkg/commands/artifact/run.go @@ -6,6 +6,7 @@ import ( "fmt" "github.com/hashicorp/go-multierror" + "github.com/samber/lo" "github.com/spf13/viper" "golang.org/x/exp/slices" "golang.org/x/xerrors" @@ -90,7 +91,7 @@ type Runner interface { // Filter filter a report Filter(ctx context.Context, opts flag.Options, report types.Report) (types.Report, error) // Report a writes a report - Report(opts flag.Options, report types.Report) error + Report(ctx context.Context, opts flag.Options, report types.Report) error // Close closes runner Close(ctx context.Context) error } @@ -279,8 +280,8 @@ func (r *runner) Filter(ctx context.Context, opts flag.Options, report types.Rep return report, nil } -func (r *runner) Report(opts flag.Options, report types.Report) error { - if err := pkgReport.Write(report, opts); err != nil { +func (r *runner) Report(ctx context.Context, opts flag.Options, report types.Report) error { + if err := pkgReport.Write(ctx, report, opts); err != nil { return xerrors.Errorf("unable to write results: %w", err) } @@ -450,7 +451,7 @@ func Run(ctx context.Context, opts flag.Options, targetKind TargetKind) (err err return xerrors.Errorf("filter error: %w", err) } - if err = r.Report(opts, report); err != nil { + if err = r.Report(ctx, opts, report); err != nil { return xerrors.Errorf("report error: %w", err) } @@ -480,6 +481,14 @@ func disabledAnalyzers(opts flag.Options) []analyzer.Type { analyzers = append(analyzers, analyzer.TypeSecret) } + // Filter only enabled misconfiguration scanners + ma, err := filterMisconfigAnalyzers(opts.MisconfigScanners, analyzer.TypeConfigFiles) + if err != nil { + log.Logger.Errorf("Invalid misconfig scanners specified: %s defaulting to use all misconfig scanners", opts.MisconfigScanners) + } else { + analyzers = append(analyzers, ma...) + } + // Do not perform misconfiguration scanning when it is not specified. if !opts.Scanners.AnyEnabled(types.MisconfigScanner, types.RBACScanner) { analyzers = append(analyzers, analyzer.TypeConfigFiles...) @@ -512,6 +521,16 @@ func disabledAnalyzers(opts flag.Options) []analyzer.Type { return analyzers } +func filterMisconfigAnalyzers(included, all []analyzer.Type) ([]analyzer.Type, error) { + _, missing := lo.Difference(all, included) + if len(missing) > 0 { + return nil, xerrors.Errorf("invalid misconfiguration scanner specified %s valid scanners: %s", missing, all) + } + + log.Logger.Debugf("Enabling misconfiguration scanners: %s", included) + return lo.Without(all, included...), nil +} + func initScannerConfig(opts flag.Options, cacheClient cache.Cache) (ScannerConfig, types.ScanOptions, error) { target := opts.Target if opts.Input != "" { diff --git a/pkg/commands/convert/run.go b/pkg/commands/convert/run.go index 490864a14bdd..9045e54bfa3d 100644 --- a/pkg/commands/convert/run.go +++ b/pkg/commands/convert/run.go @@ -16,6 +16,9 @@ import ( ) func Run(ctx context.Context, opts flag.Options) (err error) { + ctx, cancel := context.WithTimeout(ctx, opts.Timeout) + defer cancel() + f, err := os.Open(opts.Target) if err != nil { return xerrors.Errorf("file open error: %w", err) @@ -37,7 +40,7 @@ func Run(ctx context.Context, opts flag.Options) (err error) { } log.Logger.Debug("Writing report to output...") - if err = report.Write(r, opts); err != nil { + if err = report.Write(ctx, r, opts); err != nil { return xerrors.Errorf("unable to write results: %w", err) } diff --git a/pkg/flag/kubernetes_flags.go b/pkg/flag/kubernetes_flags.go index 3bd3ac25d496..5ba74c7de919 100644 --- a/pkg/flag/kubernetes_flags.go +++ b/pkg/flag/kubernetes_flags.go @@ -82,6 +82,12 @@ var ( Default: []string{}, Usage: "indicate the node labels that the node-collector job should exclude from scanning (example: kubernetes.io/arch:arm64,team:dev)", } + NodeCollectorImageRef = Flag{ + Name: "node-collector-imageref", + ConfigName: "node.collector.imageref", + Default: "ghcr.io/aquasecurity/node-collector:0.0.9", + Usage: "indicate the image reference for the node-collector scan job", + } ) type K8sFlagGroup struct { @@ -91,6 +97,7 @@ type K8sFlagGroup struct { Components *Flag K8sVersion *Flag Tolerations *Flag + NodeCollectorImageRef *Flag AllNamespaces *Flag NodeCollectorNamespace *Flag ExcludeOwned *Flag @@ -104,6 +111,7 @@ type K8sOptions struct { Components []string K8sVersion string Tolerations []corev1.Toleration + NodeCollectorImageRef string AllNamespaces bool NodeCollectorNamespace string ExcludeOwned bool @@ -122,6 +130,7 @@ func NewK8sFlagGroup() *K8sFlagGroup { NodeCollectorNamespace: &NodeCollectorNamespace, ExcludeOwned: &ExcludeOwned, ExcludeNodes: &ExcludeNodes, + NodeCollectorImageRef: &NodeCollectorImageRef, } } @@ -141,6 +150,7 @@ func (f *K8sFlagGroup) Flags() []*Flag { f.NodeCollectorNamespace, f.ExcludeOwned, f.ExcludeNodes, + f.NodeCollectorImageRef, } } @@ -171,6 +181,7 @@ func (f *K8sFlagGroup) ToOptions() (K8sOptions, error) { NodeCollectorNamespace: getString(f.NodeCollectorNamespace), ExcludeOwned: getBool(f.ExcludeOwned), ExcludeNodes: exludeNodeLabels, + NodeCollectorImageRef: getString(f.NodeCollectorImageRef), }, nil } diff --git a/pkg/flag/misconf_flags.go b/pkg/flag/misconf_flags.go index 38f8c837fa4a..10db4bb81421 100644 --- a/pkg/flag/misconf_flags.go +++ b/pkg/flag/misconf_flags.go @@ -3,7 +3,9 @@ package flag import ( "fmt" + "github.com/aquasecurity/trivy/pkg/fanal/analyzer" "github.com/aquasecurity/trivy/pkg/policy" + xstrings "github.com/aquasecurity/trivy/pkg/x/strings" ) // e.g. config yaml: @@ -73,6 +75,12 @@ var ( Default: fmt.Sprintf("%s:%d", policy.BundleRepository, policy.BundleVersion), Usage: "OCI registry URL to retrieve policy bundle from", } + MisconfigScannersFlag = Flag{ + Name: "misconfig-scanners", + ConfigName: "misconfiguration.scanners", + Default: xstrings.ToStringSlice(analyzer.TypeConfigFiles), + Usage: "comma-separated list of misconfig scanners to use for misconfiguration scanning", + } ) // MisconfFlagGroup composes common printer flag structs used for commands providing misconfiguration scanning. @@ -89,6 +97,7 @@ type MisconfFlagGroup struct { TerraformTFVars *Flag CloudformationParamVars *Flag TerraformExcludeDownloaded *Flag + MisconfigScanners *Flag } type MisconfOptions struct { @@ -104,6 +113,7 @@ type MisconfOptions struct { TerraformTFVars []string CloudFormationParamVars []string TfExcludeDownloaded bool + MisconfigScanners []analyzer.Type } func NewMisconfFlagGroup() *MisconfFlagGroup { @@ -119,6 +129,7 @@ func NewMisconfFlagGroup() *MisconfFlagGroup { TerraformTFVars: &TfVarsFlag, CloudformationParamVars: &CfParamsFlag, TerraformExcludeDownloaded: &TerraformExcludeDownloaded, + MisconfigScanners: &MisconfigScannersFlag, } } @@ -138,6 +149,7 @@ func (f *MisconfFlagGroup) Flags() []*Flag { f.TerraformTFVars, f.TerraformExcludeDownloaded, f.CloudformationParamVars, + f.MisconfigScanners, } } @@ -153,5 +165,6 @@ func (f *MisconfFlagGroup) ToOptions() (MisconfOptions, error) { TerraformTFVars: getStringSlice(f.TerraformTFVars), CloudFormationParamVars: getStringSlice(f.CloudformationParamVars), TfExcludeDownloaded: getBool(f.TerraformExcludeDownloaded), + MisconfigScanners: getUnderlyingStringSlice[analyzer.Type](f.MisconfigScanners), }, nil } diff --git a/pkg/flag/options.go b/pkg/flag/options.go index b231705f50da..fb3d69eaa396 100644 --- a/pkg/flag/options.go +++ b/pkg/flag/options.go @@ -1,6 +1,7 @@ package flag import ( + "context" "fmt" "io" "os" @@ -17,6 +18,7 @@ import ( "github.com/aquasecurity/trivy/pkg/fanal/analyzer" ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" "github.com/aquasecurity/trivy/pkg/log" + "github.com/aquasecurity/trivy/pkg/plugin" "github.com/aquasecurity/trivy/pkg/result" "github.com/aquasecurity/trivy/pkg/types" "github.com/aquasecurity/trivy/pkg/version" @@ -173,19 +175,46 @@ func (o *Options) SetOutputWriter(w io.Writer) { // OutputWriter returns an output writer. // If the output file is not specified, it returns os.Stdout. -func (o *Options) OutputWriter() (io.Writer, func(), error) { - if o.outputWriter != nil { - return o.outputWriter, func() {}, nil +func (o *Options) OutputWriter(ctx context.Context) (io.Writer, func() error, error) { + cleanup := func() error { return nil } + switch { + case o.outputWriter != nil: + return o.outputWriter, cleanup, nil + case o.Output == "": + return os.Stdout, cleanup, nil + case strings.HasPrefix(o.Output, "plugin="): + return o.outputPluginWriter(ctx) } - if o.Output != "" { - f, err := os.Create(o.Output) - if err != nil { - return nil, nil, xerrors.Errorf("failed to create output file: %w", err) + f, err := os.Create(o.Output) + if err != nil { + return nil, nil, xerrors.Errorf("failed to create output file: %w", err) + } + return f, f.Close, nil +} + +func (o *Options) outputPluginWriter(ctx context.Context) (io.Writer, func() error, error) { + pluginName := strings.TrimPrefix(o.Output, "plugin=") + + pr, pw := io.Pipe() + wait, err := plugin.Start(ctx, pluginName, plugin.RunOptions{ + Args: o.OutputPluginArgs, + Stdin: pr, + }) + if err != nil { + return nil, nil, xerrors.Errorf("plugin start: %w", err) + } + + cleanup := func() error { + if err = pw.Close(); err != nil { + return xerrors.Errorf("failed to close pipe: %w", err) } - return f, func() { _ = f.Close() }, nil + if err = wait(); err != nil { + return xerrors.Errorf("plugin error: %w", err) + } + return nil } - return os.Stdout, func() {}, nil + return pw, cleanup, nil } func addFlag(cmd *cobra.Command, flag *Flag) { diff --git a/pkg/flag/report_flags.go b/pkg/flag/report_flags.go index 50304f5d7883..54554be3d126 100644 --- a/pkg/flag/report_flags.go +++ b/pkg/flag/report_flags.go @@ -3,6 +3,7 @@ package flag import ( "strings" + "github.com/mattn/go-shellwords" "github.com/samber/lo" "golang.org/x/exp/slices" "golang.org/x/xerrors" @@ -86,6 +87,12 @@ var ( Default: "", Usage: "output file name", } + OutputPluginArgFlag = Flag{ + Name: "output-plugin-arg", + ConfigName: "output-plugin-arg", + Default: "", + Usage: "[EXPERIMENTAL] output plugin arguments", + } SeverityFlag = Flag{ Name: "severity", ConfigName: "severity", @@ -105,49 +112,52 @@ var ( // ReportFlagGroup composes common printer flag structs // used for commands requiring reporting logic. type ReportFlagGroup struct { - Format *Flag - ReportFormat *Flag - Template *Flag - DependencyTree *Flag - ListAllPkgs *Flag - IgnoreFile *Flag - IgnorePolicy *Flag - ExitCode *Flag - ExitOnEOL *Flag - Output *Flag - Severity *Flag - Compliance *Flag + Format *Flag + ReportFormat *Flag + Template *Flag + DependencyTree *Flag + ListAllPkgs *Flag + IgnoreFile *Flag + IgnorePolicy *Flag + ExitCode *Flag + ExitOnEOL *Flag + Output *Flag + OutputPluginArg *Flag + Severity *Flag + Compliance *Flag } type ReportOptions struct { - Format types.Format - ReportFormat string - Template string - DependencyTree bool - ListAllPkgs bool - IgnoreFile string - ExitCode int - ExitOnEOL int - IgnorePolicy string - Output string - Severities []dbTypes.Severity - Compliance spec.ComplianceSpec + Format types.Format + ReportFormat string + Template string + DependencyTree bool + ListAllPkgs bool + IgnoreFile string + ExitCode int + ExitOnEOL int + IgnorePolicy string + Output string + OutputPluginArgs []string + Severities []dbTypes.Severity + Compliance spec.ComplianceSpec } func NewReportFlagGroup() *ReportFlagGroup { return &ReportFlagGroup{ - Format: &FormatFlag, - ReportFormat: &ReportFormatFlag, - Template: &TemplateFlag, - DependencyTree: &DependencyTreeFlag, - ListAllPkgs: &ListAllPkgsFlag, - IgnoreFile: &IgnoreFileFlag, - IgnorePolicy: &IgnorePolicyFlag, - ExitCode: &ExitCodeFlag, - ExitOnEOL: &ExitOnEOLFlag, - Output: &OutputFlag, - Severity: &SeverityFlag, - Compliance: &ComplianceFlag, + Format: &FormatFlag, + ReportFormat: &ReportFormatFlag, + Template: &TemplateFlag, + DependencyTree: &DependencyTreeFlag, + ListAllPkgs: &ListAllPkgsFlag, + IgnoreFile: &IgnoreFileFlag, + IgnorePolicy: &IgnorePolicyFlag, + ExitCode: &ExitCodeFlag, + ExitOnEOL: &ExitOnEOLFlag, + Output: &OutputFlag, + OutputPluginArg: &OutputPluginArgFlag, + Severity: &SeverityFlag, + Compliance: &ComplianceFlag, } } @@ -167,6 +177,7 @@ func (f *ReportFlagGroup) Flags() []*Flag { f.ExitCode, f.ExitOnEOL, f.Output, + f.OutputPluginArg, f.Severity, f.Compliance, } @@ -216,19 +227,28 @@ func (f *ReportFlagGroup) ToOptions() (ReportOptions, error) { return ReportOptions{}, xerrors.Errorf("unable to load compliance spec: %w", err) } + var outputPluginArgs []string + if arg := getString(f.OutputPluginArg); arg != "" { + outputPluginArgs, err = shellwords.Parse(arg) + if err != nil { + return ReportOptions{}, xerrors.Errorf("unable to parse output plugin argument: %w", err) + } + } + return ReportOptions{ - Format: format, - ReportFormat: getString(f.ReportFormat), - Template: template, - DependencyTree: dependencyTree, - ListAllPkgs: listAllPkgs, - IgnoreFile: getString(f.IgnoreFile), - ExitCode: getInt(f.ExitCode), - ExitOnEOL: getInt(f.ExitOnEOL), - IgnorePolicy: getString(f.IgnorePolicy), - Output: getString(f.Output), - Severities: toSeverity(getStringSlice(f.Severity)), - Compliance: cs, + Format: format, + ReportFormat: getString(f.ReportFormat), + Template: template, + DependencyTree: dependencyTree, + ListAllPkgs: listAllPkgs, + IgnoreFile: getString(f.IgnoreFile), + ExitCode: getInt(f.ExitCode), + ExitOnEOL: getInt(f.ExitOnEOL), + IgnorePolicy: getString(f.IgnorePolicy), + Output: getString(f.Output), + OutputPluginArgs: outputPluginArgs, + Severities: toSeverity(getStringSlice(f.Severity)), + Compliance: cs, }, nil } diff --git a/pkg/flag/report_flags_test.go b/pkg/flag/report_flags_test.go index 9155addbbe64..c2e92fc5fcbd 100644 --- a/pkg/flag/report_flags_test.go +++ b/pkg/flag/report_flags_test.go @@ -18,20 +18,20 @@ import ( func TestReportFlagGroup_ToOptions(t *testing.T) { type fields struct { - format types.Format - template string - dependencyTree bool - listAllPkgs bool - ignoreUnfixed bool - ignoreFile string - exitCode int - exitOnEOSL bool - ignorePolicy string - output string - severities string - compliane string - - debug bool + format types.Format + template string + dependencyTree bool + listAllPkgs bool + ignoreUnfixed bool + ignoreFile string + exitCode int + exitOnEOSL bool + ignorePolicy string + output string + outputPluginArgs string + severities string + compliance string + debug bool } tests := []struct { name string @@ -63,8 +63,7 @@ func TestReportFlagGroup_ToOptions(t *testing.T) { severities: "CRITICAL", format: "cyclonedx", listAllPkgs: false, - - debug: true, + debug: true, }, wantLogs: []string{ `["cyclonedx" "spdx" "spdx-json" "github"] automatically enables '--list-all-pkgs'.`, @@ -138,10 +137,26 @@ func TestReportFlagGroup_ToOptions(t *testing.T) { ListAllPkgs: true, }, }, + { + name: "happy path with output plugin args", + fields: fields{ + output: "plugin=count", + outputPluginArgs: "--publish-after 2023-10-01 --publish-before 2023-10-02", + }, + want: flag.ReportOptions{ + Output: "plugin=count", + OutputPluginArgs: []string{ + "--publish-after", + "2023-10-01", + "--publish-before", + "2023-10-02", + }, + }, + }, { name: "happy path with compliance", fields: fields{ - compliane: "@testdata/example-spec.yaml", + compliance: "@testdata/example-spec.yaml", severities: dbTypes.SeverityLow.String(), }, want: flag.ReportOptions{ @@ -187,22 +202,24 @@ func TestReportFlagGroup_ToOptions(t *testing.T) { viper.Set(flag.ExitCodeFlag.ConfigName, tt.fields.exitCode) viper.Set(flag.ExitOnEOLFlag.ConfigName, tt.fields.exitOnEOSL) viper.Set(flag.OutputFlag.ConfigName, tt.fields.output) + viper.Set(flag.OutputPluginArgFlag.ConfigName, tt.fields.outputPluginArgs) viper.Set(flag.SeverityFlag.ConfigName, tt.fields.severities) - viper.Set(flag.ComplianceFlag.ConfigName, tt.fields.compliane) + viper.Set(flag.ComplianceFlag.ConfigName, tt.fields.compliance) // Assert options f := &flag.ReportFlagGroup{ - Format: &flag.FormatFlag, - Template: &flag.TemplateFlag, - DependencyTree: &flag.DependencyTreeFlag, - ListAllPkgs: &flag.ListAllPkgsFlag, - IgnoreFile: &flag.IgnoreFileFlag, - IgnorePolicy: &flag.IgnorePolicyFlag, - ExitCode: &flag.ExitCodeFlag, - ExitOnEOL: &flag.ExitOnEOLFlag, - Output: &flag.OutputFlag, - Severity: &flag.SeverityFlag, - Compliance: &flag.ComplianceFlag, + Format: &flag.FormatFlag, + Template: &flag.TemplateFlag, + DependencyTree: &flag.DependencyTreeFlag, + ListAllPkgs: &flag.ListAllPkgsFlag, + IgnoreFile: &flag.IgnoreFileFlag, + IgnorePolicy: &flag.IgnorePolicyFlag, + ExitCode: &flag.ExitCodeFlag, + ExitOnEOL: &flag.ExitOnEOLFlag, + Output: &flag.OutputFlag, + OutputPluginArg: &flag.OutputPluginArgFlag, + Severity: &flag.SeverityFlag, + Compliance: &flag.ComplianceFlag, } got, err := f.ToOptions() diff --git a/pkg/k8s/commands/cluster.go b/pkg/k8s/commands/cluster.go index 9d29e43b9dc9..bf28f26f5d7f 100644 --- a/pkg/k8s/commands/cluster.go +++ b/pkg/k8s/commands/cluster.go @@ -29,7 +29,11 @@ func clusterRun(ctx context.Context, opts flag.Options, cluster k8s.Cluster) err } case types.FormatJSON, types.FormatTable: if opts.Scanners.AnyEnabled(types.MisconfigScanner) && slices.Contains(opts.Components, "infra") { - artifacts, err = trivyk8s.New(cluster, log.Logger).ListArtifactAndNodeInfo(ctx, opts.NodeCollectorNamespace, opts.ExcludeNodes, opts.Tolerations...) + artifacts, err = trivyk8s.New(cluster, log.Logger, trivyk8s.WithExcludeOwned(opts.ExcludeOwned)).ListArtifactAndNodeInfo(ctx, + trivyk8s.WithScanJobNamespace(opts.NodeCollectorNamespace), + trivyk8s.WithIgnoreLabels(opts.ExcludeNodes), + trivyk8s.WithScanJobImageRef(opts.NodeCollectorImageRef), + trivyk8s.WithTolerations(opts.Tolerations)) if err != nil { return xerrors.Errorf("get k8s artifacts with node info error: %w", err) } diff --git a/pkg/k8s/commands/run.go b/pkg/k8s/commands/run.go index 9207363342c6..ec3e61385c65 100644 --- a/pkg/k8s/commands/run.go +++ b/pkg/k8s/commands/run.go @@ -101,7 +101,7 @@ func (r *runner) run(ctx context.Context, artifacts []*k8sArtifacts.Artifact) er return xerrors.Errorf("k8s scan error: %w", err) } - output, cleanup, err := r.flagOpts.OutputWriter() + output, cleanup, err := r.flagOpts.OutputWriter(ctx) if err != nil { return xerrors.Errorf("failed to create output file: %w", err) } diff --git a/pkg/plugin/plugin.go b/pkg/plugin/plugin.go index 34eeb7eb3e1d..f96f02a80c00 100644 --- a/pkg/plugin/plugin.go +++ b/pkg/plugin/plugin.go @@ -3,6 +3,7 @@ package plugin import ( "context" "fmt" + "io" "os" "os/exec" "path/filepath" @@ -57,21 +58,55 @@ type Selector struct { Arch string } -// Run runs the plugin -func (p Plugin) Run(ctx context.Context, args []string) error { +type RunOptions struct { + Args []string + Stdin io.Reader +} + +func (p Plugin) Cmd(ctx context.Context, opts RunOptions) (*exec.Cmd, error) { platform, err := p.selectPlatform() if err != nil { - return xerrors.Errorf("platform selection error: %w", err) + return nil, xerrors.Errorf("platform selection error: %w", err) } execFile := filepath.Join(dir(), p.Name, platform.Bin) - cmd := exec.CommandContext(ctx, execFile, args...) + cmd := exec.CommandContext(ctx, execFile, opts.Args...) cmd.Stdin = os.Stdin + if opts.Stdin != nil { + cmd.Stdin = opts.Stdin + } cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr cmd.Env = os.Environ() + return cmd, nil +} + +type Wait func() error + +// Start starts the plugin +// +// After a successful call to Start the Wait method must be called. +func (p Plugin) Start(ctx context.Context, opts RunOptions) (Wait, error) { + cmd, err := p.Cmd(ctx, opts) + if err != nil { + return nil, xerrors.Errorf("cmd: %w", err) + } + + if err = cmd.Start(); err != nil { + return nil, xerrors.Errorf("plugin start: %w", err) + } + return cmd.Wait, nil +} + +// Run runs the plugin +func (p Plugin) Run(ctx context.Context, opts RunOptions) error { + cmd, err := p.Cmd(ctx, opts) + if err != nil { + return xerrors.Errorf("cmd: %w", err) + } + // If an error is found during the execution of the plugin, figure // out if the error was from not being able to execute the plugin or // an error set by the plugin itself. @@ -79,10 +114,8 @@ func (p Plugin) Run(ctx context.Context, args []string) error { if _, ok := err.(*exec.ExitError); !ok { return xerrors.Errorf("exit: %w", err) } - return xerrors.Errorf("plugin exec: %w", err) } - return nil } @@ -186,18 +219,9 @@ func Uninstall(name string) error { // Information gets the information about an installed plugin func Information(name string) (string, error) { - pluginDir := filepath.Join(dir(), name) - - if _, err := os.Stat(pluginDir); err != nil { - if os.IsNotExist(err) { - return "", xerrors.Errorf("could not find a plugin called '%s', did you install it?", name) - } - return "", xerrors.Errorf("stat error: %w", err) - } - - plugin, err := loadMetadata(pluginDir) + plugin, err := load(name) if err != nil { - return "", xerrors.Errorf("unable to load metadata: %w", err) + return "", xerrors.Errorf("plugin load error: %w", err) } return fmt.Sprintf(` @@ -230,19 +254,11 @@ func List() (string, error) { // Update updates an existing plugin func Update(name string) error { - pluginDir := filepath.Join(dir(), name) - - if _, err := os.Stat(pluginDir); err != nil { - if os.IsNotExist(err) { - return xerrors.Errorf("could not find a plugin called '%s' to update: %w", name, err) - } - return err - } - - plugin, err := loadMetadata(pluginDir) + plugin, err := load(name) if err != nil { - return err + return xerrors.Errorf("plugin load error: %w", err) } + log.Logger.Infof("Updating plugin '%s'", name) updated, err := Install(nil, plugin.Repository, true) if err != nil { @@ -280,15 +296,29 @@ func LoadAll() ([]Plugin, error) { return plugins, nil } -// RunWithArgs runs the plugin with arguments -func RunWithArgs(ctx context.Context, url string, args []string) error { - pl, err := Install(ctx, url, false) +// Start starts the plugin +func Start(ctx context.Context, name string, opts RunOptions) (Wait, error) { + plugin, err := load(name) + if err != nil { + return nil, xerrors.Errorf("plugin load error: %w", err) + } + + wait, err := plugin.Start(ctx, opts) + if err != nil { + return nil, xerrors.Errorf("unable to run %s plugin: %w", plugin.Name, err) + } + return wait, nil +} + +// RunWithURL runs the plugin with URL +func RunWithURL(ctx context.Context, url string, opts RunOptions) error { + plugin, err := Install(ctx, url, false) if err != nil { return xerrors.Errorf("plugin install error: %w", err) } - if err = pl.Run(ctx, args); err != nil { - return xerrors.Errorf("unable to run %s plugin: %w", pl.Name, err) + if err = plugin.Run(ctx, opts); err != nil { + return xerrors.Errorf("unable to run %s plugin: %w", plugin.Name, err) } return nil } @@ -298,6 +328,23 @@ func IsPredefined(name string) bool { return ok } +func load(name string) (Plugin, error) { + pluginDir := filepath.Join(dir(), name) + if _, err := os.Stat(pluginDir); err != nil { + if os.IsNotExist(err) { + return Plugin{}, xerrors.Errorf("could not find a plugin called '%s', did you install it?", name) + } + return Plugin{}, xerrors.Errorf("plugin stat error: %w", err) + } + + plugin, err := loadMetadata(pluginDir) + if err != nil { + return Plugin{}, xerrors.Errorf("unable to load plugin metadata: %w", err) + } + + return plugin, nil +} + func loadMetadata(dir string) (Plugin, error) { filePath := filepath.Join(dir, configFile) f, err := os.Open(filePath) diff --git a/pkg/plugin/plugin_test.go b/pkg/plugin/plugin_test.go index 6839d7eb7c9d..f9ee7aac2b89 100644 --- a/pkg/plugin/plugin_test.go +++ b/pkg/plugin/plugin_test.go @@ -29,13 +29,10 @@ func TestPlugin_Run(t *testing.T) { GOOS string GOARCH string } - type args struct { - args []string - } tests := []struct { name string fields fields - args args + opts plugin.RunOptions wantErr string }{ { @@ -162,7 +159,7 @@ func TestPlugin_Run(t *testing.T) { GOARCH: tt.fields.GOARCH, } - err := p.Run(context.Background(), tt.args.args) + err := p.Run(context.Background(), tt.opts) if tt.wantErr != "" { require.NotNil(t, err) assert.Contains(t, err.Error(), tt.wantErr) @@ -338,7 +335,7 @@ description: A simple test plugin` // Get Information for unknown plugin info, err = plugin.Information("unknown") require.Error(t, err) - assert.Equal(t, "could not find a plugin called 'unknown', did you install it?", err.Error()) + assert.ErrorContains(t, err, "could not find a plugin called 'unknown', did you install it?") } func TestLoadAll1(t *testing.T) { diff --git a/pkg/report/writer.go b/pkg/report/writer.go index 648a9372f534..e53cad0e0463 100644 --- a/pkg/report/writer.go +++ b/pkg/report/writer.go @@ -1,6 +1,8 @@ package report import ( + "context" + "errors" "io" "strings" "sync" @@ -24,12 +26,16 @@ const ( ) // Write writes the result to output, format as passed in argument -func Write(report types.Report, option flag.Options) error { - output, cleanup, err := option.OutputWriter() +func Write(ctx context.Context, report types.Report, option flag.Options) (err error) { + output, cleanup, err := option.OutputWriter(ctx) if err != nil { return xerrors.Errorf("failed to create a file: %w", err) } - defer cleanup() + defer func() { + if cerr := cleanup(); cerr != nil { + err = errors.Join(err, cerr) + } + }() // Compliance report if option.Compliance.Spec.ID != "" { @@ -91,9 +97,10 @@ func Write(report types.Report, option flag.Options) error { return xerrors.Errorf("unknown format: %v", option.Format) } - if err := writer.Write(report); err != nil { + if err = writer.Write(report); err != nil { return xerrors.Errorf("failed to write results: %w", err) } + return nil }