refactor: rename security-checks to scanners (#3467)

This commit is contained in:
Teppei Fukuda
2023-01-23 16:53:06 +02:00
committed by GitHub
parent aaf845d02e
commit e1076085d9
53 changed files with 1100 additions and 719 deletions

View File

@@ -54,7 +54,7 @@ Trivy is integrated with many popular platforms and applications. The complete l
### General usage ### General usage
```bash ```bash
trivy <target> [--security-checks <scanner1,scanner2>] <subject> trivy <target> [--scanners <scanner1,scanner2>] <subject>
``` ```
Examples: Examples:
@@ -71,7 +71,7 @@ https://user-images.githubusercontent.com/1161307/171013513-95f18734-233d-45d3-a
</details> </details>
```bash ```bash
trivy fs --security-checks vuln,secret,config myproject/ trivy fs --scanners vuln,secret,config myproject/
``` ```
<details> <details>

View File

@@ -21,7 +21,7 @@ You need to pass `--sbom-sources rekor` so that Trivy will look for SBOM attesta
$ trivy image --sbom-sources rekor otms61/alpine:3.7.3 [~/src/github.com/aquasecurity/trivy] $ trivy image --sbom-sources rekor otms61/alpine:3.7.3 [~/src/github.com/aquasecurity/trivy]
2022-09-16T17:37:13.258+0900 INFO Vulnerability scanning is enabled 2022-09-16T17:37:13.258+0900 INFO Vulnerability scanning is enabled
2022-09-16T17:37:13.258+0900 INFO Secret scanning is enabled 2022-09-16T17:37:13.258+0900 INFO Secret scanning is enabled
2022-09-16T17:37:13.258+0900 INFO If your scanning is slow, please try '--security-checks vuln' to disable secret scanning 2022-09-16T17:37:13.258+0900 INFO If your scanning is slow, please try '--scanners vuln' to disable secret scanning
2022-09-16T17:37:13.258+0900 INFO Please see also https://aquasecurity.github.io/trivy/dev/docs/secret/scanning/#recommendation for faster secret detection 2022-09-16T17:37:13.258+0900 INFO Please see also https://aquasecurity.github.io/trivy/dev/docs/secret/scanning/#recommendation for faster secret detection
2022-09-16T17:37:14.827+0900 INFO Detected SBOM format: cyclonedx-json 2022-09-16T17:37:14.827+0900 INFO Detected SBOM format: cyclonedx-json
2022-09-16T17:37:14.901+0900 INFO Found SBOM (cyclonedx) attestation in Rekor 2022-09-16T17:37:14.901+0900 INFO Found SBOM (cyclonedx) attestation in Rekor
@@ -105,7 +105,7 @@ Total: 1 (UNKNOWN: 0, LOW: 0, MEDIUM: 0, HIGH: 1, CRITICAL: 0)
Also, it is applied to non-packaged binaries even in container images. Also, it is applied to non-packaged binaries even in container images.
```bash ```bash
$ trivy image --sbom-sources rekor --security-checks vuln alpine-with-bat $ trivy image --sbom-sources rekor --scanners vuln alpine-with-bat
2022-10-25T13:40:14.920+0300 INFO Vulnerability scanning is enabled 2022-10-25T13:40:14.920+0300 INFO Vulnerability scanning is enabled
2022-10-25T13:40:18.047+0300 INFO Found SBOM attestation in Rekor: bat 2022-10-25T13:40:18.047+0300 INFO Found SBOM attestation in Rekor: bat
2022-10-25T13:40:18.186+0300 INFO Detected OS: alpine 2022-10-25T13:40:18.186+0300 INFO Detected OS: alpine

View File

@@ -27,12 +27,12 @@ Filter by severity:
$ trivy k8s --severity=CRITICAL --report=all cluster $ trivy k8s --severity=CRITICAL --report=all cluster
``` ```
Filter by security check (Vulnerabilities, Secrets or Misconfigurations): Filter by scanners (Vulnerabilities, Secrets or Misconfigurations):
``` ```
$ trivy k8s --security-checks=secret --report=summary cluster $ trivy k8s --scanners=secret --report=summary cluster
# or # or
$ trivy k8s --security-checks=config --report=summary cluster $ trivy k8s --scanners=config --report=summary cluster
``` ```
Scan a specific namespace: Scan a specific namespace:
@@ -263,16 +263,16 @@ Severities: C=CRITICAL H=HIGH M=MEDIUM L=LOW U=UNKNOWN
The infra checks are based on CIS Benchmarks recommendations for kubernetes. The infra checks are based on CIS Benchmarks recommendations for kubernetes.
If you want filter only for the infra checks, you can use the flag `--components` along with the `--security-checks=config` If you want filter only for the infra checks, you can use the flag `--components` along with the `--scanners=config`
``` ```
$ trivy k8s cluster --report summary --components=infra --security-checks=config # scan only infra $ trivy k8s cluster --report summary --components=infra --scanners=config # scan only infra
``` ```
Or, to filter for all other checks besides the infra checks, you can: Or, to filter for all other checks besides the infra checks, you can:
``` ```
$ trivy k8s cluster --report summary --components=workload --security-checks=config # scan all components besides infra $ trivy k8s cluster --report summary --components=workload --scanners=config # scan all components besides infra
``` ```

View File

@@ -47,10 +47,10 @@ License checking classifies the identified licenses and map the classification t
This section shows how to scan license in container image and filesystem. This section shows how to scan license in container image and filesystem.
### Standard scanning ### Standard scanning
Specify an image name with `--security-checks license`. Specify an image name with `--scanners license`.
``` shell ``` shell
$ trivy image --security-checks license --severity UNKNOWN,HIGH,CRITICAL alpine:3.15 $ trivy image --scanners license --severity UNKNOWN,HIGH,CRITICAL alpine:3.15
2022-07-13T17:28:39.526+0300 INFO License scanning is enabled 2022-07-13T17:28:39.526+0300 INFO License scanning is enabled
OS Packages (license) OS Packages (license)
@@ -78,7 +78,7 @@ Total: 6 (UNKNOWN: 0, HIGH: 6, CRITICAL: 0)
Specify `--license-full` Specify `--license-full`
``` shell ``` shell
$ trivy image --security-checks license --severity UNKNOWN,HIGH,CRITICAL --license-full grafana/grafana $ trivy image --scanners license --severity UNKNOWN,HIGH,CRITICAL --license-full grafana/grafana
2022-07-13T17:48:40.905+0300 INFO Full license scanning is enabled 2022-07-13T17:48:40.905+0300 INFO Full license scanning is enabled
OS Packages (license) OS Packages (license)
@@ -141,7 +141,7 @@ Trivy has number of configuration flags for use with license scanning;
Trivy license scanning can ignore licenses that are identified to explicitly remove them from the results using the `--ignored-licenses` flag; Trivy license scanning can ignore licenses that are identified to explicitly remove them from the results using the `--ignored-licenses` flag;
```shell ```shell
$ trivy image --security-checks license --ignored-licenses MPL-2.0,MIT --severity LOW grafana/grafana:latest $ trivy image --scanners license --ignored-licenses MPL-2.0,MIT --severity LOW grafana/grafana:latest
2022-07-13T18:15:28.605Z INFO License scanning is enabled 2022-07-13T18:15:28.605Z INFO License scanning is enabled
OS Packages (license) OS Packages (license)

View File

@@ -37,28 +37,28 @@ $ trivy config [YOUR_IaC_DIRECTORY]
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
``` ```
You can also enable misconfiguration detection in container image, filesystem and git repository scanning via `--security-checks config`. You can also enable misconfiguration detection in container image, filesystem and git repository scanning via `--scanners config`.
```bash ```bash
$ trivy image --security-checks config IMAGE_NAME $ trivy image --scanners config IMAGE_NAME
``` ```
```bash ```bash
$ trivy fs --security-checks config /path/to/dir $ trivy fs --scanners config /path/to/dir
``` ```
!!! note !!! note
Misconfiguration detection is not enabled by default in `image`, `fs` and `repo` subcommands. Misconfiguration detection is not enabled by default in `image`, `fs` and `repo` subcommands.
Unlike the `config` subcommand, `image`, `fs` and `repo` subcommands can also scan for vulnerabilities and secrets at the same time. Unlike the `config` subcommand, `image`, `fs` and `repo` subcommands can also scan for vulnerabilities and secrets at the same time.
You can specify `--security-checks vuln,config,secret` to enable vulnerability and secret detection as well as misconfiguration detection. You can specify `--scanners vuln,config,secret` to enable vulnerability and secret detection as well as misconfiguration detection.
!!! example !!! example
``` bash ``` bash
$ ls myapp/ $ ls myapp/
Dockerfile Pipfile.lock Dockerfile Pipfile.lock
$ trivy fs --security-checks vuln,config,secret --severity HIGH,CRITICAL myapp/ $ trivy fs --scanners vuln,config,secret --severity HIGH,CRITICAL myapp/
2022-05-16T13:42:21.440+0100 INFO Number of language-specific files: 1 2022-05-16T13:42:21.440+0100 INFO Number of language-specific files: 1
2022-05-16T13:42:21.440+0100 INFO Detecting pipenv vulnerabilities... 2022-05-16T13:42:21.440+0100 INFO Detecting pipenv vulnerabilities...
2022-05-16T13:42:21.440+0100 INFO Detected config files: 1 2022-05-16T13:42:21.440+0100 INFO Detected config files: 1

View File

@@ -9,7 +9,7 @@ Aliases:
Scan Flags Scan Flags
--offline-scan do not issue API requests to identify dependencies --offline-scan do not issue API requests to identify dependencies
--security-checks string comma-separated list of what security issues to detect (vuln,config,secret) (default "vuln,secret") --scanners string comma-separated list of what security issues to detect (vuln,config,secret) (default "vuln,secret")
--skip-dirs strings specify the directories where the traversal is skipped --skip-dirs strings specify the directories where the traversal is skipped
--skip-files strings specify the file paths to skip traversal --skip-files strings specify the file paths to skip traversal
@@ -47,8 +47,8 @@ Vulnerability Flags
Misconfiguration Flags Misconfiguration Flags
--config-data strings specify paths from which data for the Rego policies will be recursively loaded --config-data strings specify paths from which data for the Rego policies will be recursively loaded
--config-policy strings specify paths to the Rego policy files directory, applying config files --config-policy strings specify paths to the Rego policy files directory, applying config files
--file-patterns strings specify config file patterns, available with '--security-checks config' --file-patterns strings specify config file patterns, available with '--scanners config'
--include-non-failures include successes and exceptions, available with '--security-checks config' --include-non-failures include successes and exceptions, available with '--scanners config'
--policy-namespaces strings Rego namespaces --policy-namespaces strings Rego namespaces
--trace enable more verbose trace output for custom queries --trace enable more verbose trace output for custom queries

View File

@@ -32,8 +32,8 @@ Cache Flags
Misconfiguration Flags Misconfiguration Flags
--config-data strings specify paths from which data for the Rego policies will be recursively loaded --config-data strings specify paths from which data for the Rego policies will be recursively loaded
--config-policy strings specify paths to the Rego policy files directory, applying config files --config-policy strings specify paths to the Rego policy files directory, applying config files
--file-patterns strings specify config file patterns, available with '--security-checks config' --file-patterns strings specify config file patterns, available with '--scanners config'
--include-non-failures include successes and exceptions, available with '--security-checks config' --include-non-failures include successes and exceptions, available with '--scanners config'
--policy-namespaces strings Rego namespaces --policy-namespaces strings Rego namespaces
--trace enable more verbose trace output for custom queries --trace enable more verbose trace output for custom queries

View File

@@ -18,7 +18,7 @@ Examples:
Scan Flags Scan Flags
--offline-scan do not issue API requests to identify dependencies --offline-scan do not issue API requests to identify dependencies
--security-checks string comma-separated list of what security issues to detect (vuln,config,secret) (default "vuln,secret") --scanners string comma-separated list of what security issues to detect (vuln,config,secret) (default "vuln,secret")
--skip-dirs strings specify the directories where the traversal is skipped --skip-dirs strings specify the directories where the traversal is skipped
--skip-files strings specify the file paths to skip traversal --skip-files strings specify the file paths to skip traversal
@@ -55,8 +55,8 @@ Vulnerability Flags
Misconfiguration Flags Misconfiguration Flags
--config-data strings specify paths from which data for the Rego policies will be recursively loaded --config-data strings specify paths from which data for the Rego policies will be recursively loaded
--config-policy strings specify paths to the Rego policy files directory, applying config files --config-policy strings specify paths to the Rego policy files directory, applying config files
--file-patterns strings specify config file patterns, available with '--security-checks config' --file-patterns strings specify config file patterns, available with '--scanners config'
--include-non-failures include successes and exceptions, available with '--security-checks config' --include-non-failures include successes and exceptions, available with '--scanners config'
--policy-namespaces strings Rego namespaces --policy-namespaces strings Rego namespaces
--trace enable more verbose trace output for custom queries --trace enable more verbose trace output for custom queries

View File

@@ -33,7 +33,7 @@ Examples:
Scan Flags Scan Flags
--offline-scan do not issue API requests to identify dependencies --offline-scan do not issue API requests to identify dependencies
--security-checks string comma-separated list of what security issues to detect (vuln,config,secret) (default "vuln,secret") --scanners string comma-separated list of what security issues to detect (vuln,config,secret) (default "vuln,secret")
--skip-dirs strings specify the directories where the traversal is skipped --skip-dirs strings specify the directories where the traversal is skipped
--skip-files strings specify the file paths to skip traversal --skip-files strings specify the file paths to skip traversal
@@ -73,8 +73,8 @@ Vulnerability Flags
Misconfiguration Flags Misconfiguration Flags
--config-data strings specify paths from which data for the Rego policies will be recursively loaded --config-data strings specify paths from which data for the Rego policies will be recursively loaded
--config-policy strings specify paths to the Rego policy files directory, applying config files --config-policy strings specify paths to the Rego policy files directory, applying config files
--file-patterns strings specify config file patterns, available with '--security-checks config' --file-patterns strings specify config file patterns, available with '--scanners config'
--include-non-failures include successes and exceptions, available with '--security-checks config' --include-non-failures include successes and exceptions, available with '--scanners config'
--policy-namespaces strings Rego namespaces --policy-namespaces strings Rego namespaces
--trace enable more verbose trace output for custom queries --trace enable more verbose trace output for custom queries

View File

@@ -15,7 +15,7 @@ Examples:
Scan Flags Scan Flags
--offline-scan do not issue API requests to identify dependencies --offline-scan do not issue API requests to identify dependencies
--security-checks string comma-separated list of what security issues to detect (vuln,config,secret) (default "vuln,secret") --scanners string comma-separated list of what security issues to detect (vuln,config,secret) (default "vuln,secret")
--skip-dirs strings specify the directories where the traversal is skipped --skip-dirs strings specify the directories where the traversal is skipped
--skip-files strings specify the file paths to skip traversal --skip-files strings specify the file paths to skip traversal
@@ -52,8 +52,8 @@ Vulnerability Flags
Misconfiguration Flags Misconfiguration Flags
--config-data strings specify paths from which data for the Rego policies will be recursively loaded --config-data strings specify paths from which data for the Rego policies will be recursively loaded
--config-policy strings specify paths to the Rego policy files directory, applying config files --config-policy strings specify paths to the Rego policy files directory, applying config files
--file-patterns strings specify config file patterns, available with '--security-checks config' --file-patterns strings specify config file patterns, available with '--scanners config'
--include-non-failures include successes and exceptions, available with '--security-checks config' --include-non-failures include successes and exceptions, available with '--scanners config'
--policy-namespaces strings Rego namespaces --policy-namespaces strings Rego namespaces
--trace enable more verbose trace output for custom queries --trace enable more verbose trace output for custom queries

View File

@@ -21,7 +21,7 @@ Scan Flags
--offline-scan do not issue API requests to identify dependencies --offline-scan do not issue API requests to identify dependencies
--rekor-url string [EXPERIMENTAL] address of rekor STL server (default "https://rekor.sigstore.dev") --rekor-url string [EXPERIMENTAL] address of rekor STL server (default "https://rekor.sigstore.dev")
--sbom-sources strings [EXPERIMENTAL] try to retrieve SBOM from the specified sources (rekor) --sbom-sources strings [EXPERIMENTAL] try to retrieve SBOM from the specified sources (rekor)
--security-checks strings comma-separated list of what security issues to detect (vuln,config,secret,license) (default [vuln,secret]) --scanners strings comma-separated list of what security issues to detect (vuln,config,secret,license) (default [vuln,secret])
--skip-dirs strings specify the directories where the traversal is skipped --skip-dirs strings specify the directories where the traversal is skipped
--skip-files strings specify the file paths to skip traversal --skip-files strings specify the file paths to skip traversal
@@ -60,7 +60,7 @@ Misconfiguration Flags
--helm-set-file strings specify Helm values from respective files specified via the command line (can specify multiple or separate values with commas: key1=path1,key2=path2) --helm-set-file strings specify Helm values from respective files specified via the command line (can specify multiple or separate values with commas: key1=path1,key2=path2)
--helm-set-string strings specify Helm string values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2) --helm-set-string strings specify Helm string values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)
--helm-values strings specify paths to override the Helm values.yaml files --helm-values strings specify paths to override the Helm values.yaml files
--include-non-failures include successes and exceptions, available with '--security-checks config' --include-non-failures include successes and exceptions, available with '--scanners config'
--tf-vars strings specify paths to override the Terraform tfvars files --tf-vars strings specify paths to override the Terraform tfvars files
Secret Flags Secret Flags

View File

@@ -19,7 +19,7 @@ Examples:
Scan Flags Scan Flags
--offline-scan do not issue API requests to identify dependencies --offline-scan do not issue API requests to identify dependencies
--security-checks string comma-separated list of what security issues to detect (vuln,config,secret) (default "vuln,secret") --scanners string comma-separated list of what security issues to detect (vuln,config,secret) (default "vuln,secret")
--skip-dirs strings specify the directories where the traversal is skipped --skip-dirs strings specify the directories where the traversal is skipped
--skip-files strings specify the file paths to skip traversal --skip-files strings specify the file paths to skip traversal

View File

@@ -102,9 +102,9 @@ scan:
# Default is false # Default is false
offline-scan: false offline-scan: false
# Same as '--security-checks' # Same as '--scanners'
# Default depends on subcommand # Default depends on subcommand
security-checks: scanners:
- vuln - vuln
- config - config
- secret - secret

View File

@@ -15,7 +15,7 @@ By default, `--format cyclonedx` represents SBOM and doesn't include vulnerabili
``` ```
$ trivy image --format cyclonedx --output result.json alpine:3.15 $ trivy image --format cyclonedx --output result.json alpine:3.15
2022-07-19T07:47:27.624Z INFO "--format cyclonedx" disables security checks. Specify "--security-checks vuln" explicitly if you want to include vulnerabilities in the CycloneDX report. 2022-07-19T07:47:27.624Z INFO "--format cyclonedx" disables security scanning. Specify "--scanners vuln" explicitly if you want to include vulnerabilities in the CycloneDX report.
``` ```
<details> <details>
@@ -239,10 +239,10 @@ $ cat result.json | jq .
</details> </details>
If you want to include vulnerabilities, you can enable vulnerability scanning via `--security-checks vuln`. If you want to include vulnerabilities, you can enable vulnerability scanning via `--scanners vuln`.
``` ```
$ trivy image --security-checks vuln --format cyclonedx --output result.json alpine:3.15 $ trivy image --scanners vuln --format cyclonedx --output result.json alpine:3.15
``` ```
## Scanning ## Scanning

View File

@@ -48,10 +48,10 @@ aws-account-id
``` ```
## Disable secret scanning ## Disable secret scanning
If you need vulnerability scanning only, you can disable secret scanning via the `--security-checks` flag. If you need vulnerability scanning only, you can disable secret scanning via the `--scanners` flag.
``` shell ``` shell
$ trivy image --security-checks vuln alpine:3.15 $ trivy image --scanners vuln alpine:3.15
``` ```
## With configuration file ## With configuration file

View File

@@ -106,10 +106,10 @@ All rules are disabled except for the ones you specify, so it runs very fast.
On the other hand, you should use `disable-rules` if you just want to disable some built-in rules. On the other hand, you should use `disable-rules` if you just want to disable some built-in rules.
See the [enable-rules][enable-rules] and [disable-rules][disable-rules] sections for the detail. See the [enable-rules][enable-rules] and [disable-rules][disable-rules] sections for the detail.
If you don't need secret scanning, you can disable it via the `--security-checks` flag. If you don't need secret scanning, you can disable it via the `--scanners` flag.
```shell ```shell
$ trivy image --security-checks vuln alpine:3.15 $ trivy image --scanners vuln alpine:3.15
``` ```

View File

@@ -19,11 +19,11 @@ $ trivy vm ami:${your_ami_id}
### Example ### Example
```shell ```shell
$ trivy vm --security-checks vuln ami:ami-0123456789abcdefg $ trivy vm --scanners vuln ami:ami-0123456789abcdefg
``` ```
!!! tip !!! tip
The scanning could be faster if you enable only vulnerability scanning (`--security-checks vuln`) because Trivy tries to download only necessary blocks for vulnerability detection. The scanning could be faster if you enable only vulnerability scanning (`--scanners vuln`) because Trivy tries to download only necessary blocks for vulnerability detection.
If you want to scan a AMI of non-default setting region, you can set any region via `--aws-region` option. If you want to scan a AMI of non-default setting region, you can set any region via `--aws-region` option.
@@ -52,11 +52,11 @@ $ trivy vm ebs:${your_ebs_snapshot_id}
### Example ### Example
```shell ```shell
$ trivy vm --security-checks vuln ebs:snap-0123456789abcdefg $ trivy vm --scanners vuln ebs:snap-0123456789abcdefg
``` ```
!!! tip !!! tip
The scanning could be faster if you enable only vulnerability scanning (`--security-checks vuln`) because Trivy tries to download only necessary blocks for vulnerability detection. The scanning could be faster if you enable only vulnerability scanning (`--scanners vuln`) because Trivy tries to download only necessary blocks for vulnerability detection.
If you want to scan an EBS Snapshot of non-default setting region, you can set any region via `--aws-region` option. If you want to scan an EBS Snapshot of non-default setting region, you can set any region via `--aws-region` option.

View File

@@ -16,7 +16,7 @@ To scan VM images, you can use the `vm` subcommand.
Pass the path to your local VM image file. Pass the path to your local VM image file.
```bash ```bash
$ trivy vm --security-checks vuln disk.vmdk $ trivy vm --scanners vuln disk.vmdk
``` ```
<details> <details>

View File

@@ -40,7 +40,7 @@ The following table provides an outline of the features Trivy offers.
33.25 MiB / 33.25 MiB [------------------------------] 100.00% 4.20 MiB p/s 8.1s 33.25 MiB / 33.25 MiB [------------------------------] 100.00% 4.20 MiB p/s 8.1s
2022-07-27T09:30:21.756Z INFO Vulnerability scanning is enabled 2022-07-27T09:30:21.756Z INFO Vulnerability scanning is enabled
2022-07-27T09:30:21.756Z INFO Secret scanning is enabled 2022-07-27T09:30:21.756Z INFO Secret scanning is enabled
2022-07-27T09:30:21.756Z INFO If your scanning is slow, please try '--security-checks vuln' to disable secret scanning 2022-07-27T09:30:21.756Z INFO If your scanning is slow, please try '--scanners vuln' to disable secret scanning
2022-07-27T09:30:21.756Z INFO Please see also https://aquasecurity.github.io/trivy/v0.30.4/docs/secret/scanning/#recommendation for faster secret detection 2022-07-27T09:30:21.756Z INFO Please see also https://aquasecurity.github.io/trivy/v0.30.4/docs/secret/scanning/#recommendation for faster secret detection
2022-07-27T09:30:22.205Z INFO Detected OS: cbl-mariner 2022-07-27T09:30:22.205Z INFO Detected OS: cbl-mariner
2022-07-27T09:30:22.205Z INFO Detecting CBL-Mariner vulnerabilities... 2022-07-27T09:30:22.205Z INFO Detecting CBL-Mariner vulnerabilities...

View File

@@ -37,7 +37,7 @@ $ trivy image --platform=linux/arm alpine:3.16.1
``` ```
2022-10-25T21:00:50.972+0300 INFO Vulnerability scanning is enabled 2022-10-25T21:00:50.972+0300 INFO Vulnerability scanning is enabled
2022-10-25T21:00:50.972+0300 INFO Secret scanning is enabled 2022-10-25T21:00:50.972+0300 INFO Secret scanning is enabled
2022-10-25T21:00:50.972+0300 INFO If your scanning is slow, please try '--security-checks vuln' to disable secret scanning 2022-10-25T21:00:50.972+0300 INFO If your scanning is slow, please try '--scanners vuln' to disable secret scanning
2022-10-25T21:00:50.972+0300 INFO Please see also https://aquasecurity.github.io/trivy/dev/docs/secret/scanning/#recommendation for faster secret detection 2022-10-25T21:00:50.972+0300 INFO Please see also https://aquasecurity.github.io/trivy/dev/docs/secret/scanning/#recommendation for faster secret detection
2022-10-25T21:00:56.190+0300 INFO Detected OS: alpine 2022-10-25T21:00:56.190+0300 INFO Detected OS: alpine
2022-10-25T21:00:56.190+0300 INFO Detecting Alpine vulnerabilities... 2022-10-25T21:00:56.190+0300 INFO Detecting Alpine vulnerabilities...

View File

@@ -58,7 +58,7 @@ Trivy is integrated with many popular platforms and applications. The complete l
### General usage ### General usage
```bash ```bash
trivy <target> [--security-checks <scanner1,scanner2>] <subject> trivy <target> [--scanners <scanner1,scanner2>] <subject>
``` ```
Examples: Examples:
@@ -80,7 +80,7 @@ trivy image python:3.4-alpine
</details> </details>
```bash ```bash
trivy fs --security-checks vuln,secret,config myproject/ trivy fs --scanners vuln,secret,config myproject/
``` ```
<details> <details>

View File

@@ -150,7 +150,7 @@ trivy:
# Image report # Image report
- ./trivy image --exit-code 0 --format template --template "@contrib/gitlab-codequality.tpl" -o gl-codeclimate-image.json $IMAGE - ./trivy image --exit-code 0 --format template --template "@contrib/gitlab-codequality.tpl" -o gl-codeclimate-image.json $IMAGE
# Filesystem report # Filesystem report
- ./trivy filesystem --security-checks config,vuln --exit-code 0 --format template --template "@contrib/gitlab-codequality.tpl" -o gl-codeclimate-fs.json . - ./trivy filesystem --scanners config,vuln --exit-code 0 --format template --template "@contrib/gitlab-codequality.tpl" -o gl-codeclimate-fs.json .
# Combine report # Combine report
- apk update && apk add jq - apk update && apk add jq
- jq -s 'add' gl-codeclimate-image.json gl-codeclimate-fs.json > gl-codeclimate.json - jq -s 'add' gl-codeclimate-image.json gl-codeclimate-fs.json > gl-codeclimate.json

View File

@@ -14,7 +14,7 @@ scan:
- /usr/lib - /usr/lib
- /usr/include - /usr/include
security-checks: scanners:
- vuln - vuln
- secret - secret
vulnerability: vulnerability:

View File

@@ -11,11 +11,13 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/aquasecurity/trivy/pkg/types"
) )
func TestFilesystem(t *testing.T) { func TestFilesystem(t *testing.T) {
type args struct { type args struct {
securityChecks string scanners string
severity []string severity []string
ignoreIDs []string ignoreIDs []string
policyPaths []string policyPaths []string
@@ -39,210 +41,210 @@ func TestFilesystem(t *testing.T) {
{ {
name: "gomod", name: "gomod",
args: args{ args: args{
securityChecks: "vuln", scanners: types.VulnerabilityScanner,
input: "testdata/fixtures/fs/gomod", input: "testdata/fixtures/fs/gomod",
}, },
golden: "testdata/gomod.json.golden", golden: "testdata/gomod.json.golden",
}, },
{ {
name: "gomod with skip files", name: "gomod with skip files",
args: args{ args: args{
securityChecks: "vuln", scanners: types.VulnerabilityScanner,
input: "testdata/fixtures/fs/gomod", input: "testdata/fixtures/fs/gomod",
skipFiles: []string{"testdata/fixtures/fs/gomod/submod2/go.mod"}, skipFiles: []string{"testdata/fixtures/fs/gomod/submod2/go.mod"},
}, },
golden: "testdata/gomod-skip.json.golden", golden: "testdata/gomod-skip.json.golden",
}, },
{ {
name: "gomod with skip dirs", name: "gomod with skip dirs",
args: args{ args: args{
securityChecks: "vuln", scanners: types.VulnerabilityScanner,
input: "testdata/fixtures/fs/gomod", input: "testdata/fixtures/fs/gomod",
skipDirs: []string{"testdata/fixtures/fs/gomod/submod2"}, skipDirs: []string{"testdata/fixtures/fs/gomod/submod2"},
}, },
golden: "testdata/gomod-skip.json.golden", golden: "testdata/gomod-skip.json.golden",
}, },
{ {
name: "nodejs", name: "nodejs",
args: args{ args: args{
securityChecks: "vuln", scanners: types.VulnerabilityScanner,
input: "testdata/fixtures/fs/nodejs", input: "testdata/fixtures/fs/nodejs",
listAllPkgs: true, listAllPkgs: true,
}, },
golden: "testdata/nodejs.json.golden", golden: "testdata/nodejs.json.golden",
}, },
{ {
name: "yarn", name: "yarn",
args: args{ args: args{
securityChecks: "vuln", scanners: types.VulnerabilityScanner,
input: "testdata/fixtures/fs/yarn", input: "testdata/fixtures/fs/yarn",
listAllPkgs: true, listAllPkgs: true,
}, },
golden: "testdata/yarn.json.golden", golden: "testdata/yarn.json.golden",
}, },
{ {
name: "pnpm", name: "pnpm",
args: args{ args: args{
securityChecks: "vuln", scanners: types.VulnerabilityScanner,
input: "testdata/fixtures/fs/pnpm", input: "testdata/fixtures/fs/pnpm",
}, },
golden: "testdata/pnpm.json.golden", golden: "testdata/pnpm.json.golden",
}, },
{ {
name: "pip", name: "pip",
args: args{ args: args{
securityChecks: "vuln", scanners: types.VulnerabilityScanner,
listAllPkgs: true, listAllPkgs: true,
input: "testdata/fixtures/fs/pip", input: "testdata/fixtures/fs/pip",
}, },
golden: "testdata/pip.json.golden", golden: "testdata/pip.json.golden",
}, },
{ {
name: "pom", name: "pom",
args: args{ args: args{
securityChecks: "vuln", scanners: types.VulnerabilityScanner,
input: "testdata/fixtures/fs/pom", input: "testdata/fixtures/fs/pom",
}, },
golden: "testdata/pom.json.golden", golden: "testdata/pom.json.golden",
}, },
{ {
name: "gradle", name: "gradle",
args: args{ args: args{
securityChecks: "vuln", scanners: types.VulnerabilityScanner,
input: "testdata/fixtures/fs/gradle", input: "testdata/fixtures/fs/gradle",
}, },
golden: "testdata/gradle.json.golden", golden: "testdata/gradle.json.golden",
}, },
{ {
name: "conan", name: "conan",
args: args{ args: args{
securityChecks: "vuln", scanners: types.VulnerabilityScanner,
listAllPkgs: true, listAllPkgs: true,
input: "testdata/fixtures/fs/conan", input: "testdata/fixtures/fs/conan",
}, },
golden: "testdata/conan.json.golden", golden: "testdata/conan.json.golden",
}, },
{ {
name: "nuget", name: "nuget",
args: args{ args: args{
securityChecks: "vuln", scanners: types.VulnerabilityScanner,
listAllPkgs: true, listAllPkgs: true,
input: "testdata/fixtures/fs/nuget", input: "testdata/fixtures/fs/nuget",
}, },
golden: "testdata/nuget.json.golden", golden: "testdata/nuget.json.golden",
}, },
{ {
name: "dotnet", name: "dotnet",
args: args{ args: args{
securityChecks: "vuln", scanners: types.VulnerabilityScanner,
listAllPkgs: true, listAllPkgs: true,
input: "testdata/fixtures/fs/dotnet", input: "testdata/fixtures/fs/dotnet",
}, },
golden: "testdata/dotnet.json.golden", golden: "testdata/dotnet.json.golden",
}, },
{ {
name: "cocoapods", name: "cocoapods",
args: args{ args: args{
securityChecks: "vuln", scanners: types.VulnerabilityScanner,
listAllPkgs: true, listAllPkgs: true,
input: "testdata/fixtures/fs/cocoapods", input: "testdata/fixtures/fs/cocoapods",
}, },
golden: "testdata/cocoapods.json.golden", golden: "testdata/cocoapods.json.golden",
}, },
{ {
name: "pubspec.lock", name: "pubspec.lock",
args: args{ args: args{
securityChecks: "vuln", scanners: types.VulnerabilityScanner,
listAllPkgs: true, listAllPkgs: true,
input: "testdata/fixtures/fs/pubspec", input: "testdata/fixtures/fs/pubspec",
}, },
golden: "testdata/pubspec.lock.json.golden", golden: "testdata/pubspec.lock.json.golden",
}, },
{ {
name: "mix.lock", name: "mix.lock",
args: args{ args: args{
securityChecks: "vuln", scanners: types.VulnerabilityScanner,
listAllPkgs: true, listAllPkgs: true,
input: "testdata/fixtures/fs/mixlock", input: "testdata/fixtures/fs/mixlock",
}, },
golden: "testdata/mix.lock.json.golden", golden: "testdata/mix.lock.json.golden",
}, },
{ {
name: "dockerfile", name: "dockerfile",
args: args{ args: args{
securityChecks: "config", scanners: types.MisconfigScanner,
input: "testdata/fixtures/fs/dockerfile", input: "testdata/fixtures/fs/dockerfile",
namespaces: []string{"testing"}, namespaces: []string{"testing"},
}, },
golden: "testdata/dockerfile.json.golden", golden: "testdata/dockerfile.json.golden",
}, },
{ {
name: "dockerfile with custom file pattern", name: "dockerfile with custom file pattern",
args: args{ args: args{
securityChecks: "config", scanners: types.MisconfigScanner,
input: "testdata/fixtures/fs/dockerfile_file_pattern", input: "testdata/fixtures/fs/dockerfile_file_pattern",
namespaces: []string{"testing"}, namespaces: []string{"testing"},
filePatterns: []string{"dockerfile:Customfile"}, filePatterns: []string{"dockerfile:Customfile"},
}, },
golden: "testdata/dockerfile_file_pattern.json.golden", golden: "testdata/dockerfile_file_pattern.json.golden",
}, },
{ {
name: "dockerfile with rule exception", name: "dockerfile with rule exception",
args: args{ args: args{
securityChecks: "config", scanners: types.MisconfigScanner,
policyPaths: []string{"testdata/fixtures/fs/rule-exception/policy"}, policyPaths: []string{"testdata/fixtures/fs/rule-exception/policy"},
input: "testdata/fixtures/fs/rule-exception", input: "testdata/fixtures/fs/rule-exception",
}, },
golden: "testdata/dockerfile-rule-exception.json.golden", golden: "testdata/dockerfile-rule-exception.json.golden",
}, },
{ {
name: "dockerfile with namespace exception", name: "dockerfile with namespace exception",
args: args{ args: args{
securityChecks: "config", scanners: types.MisconfigScanner,
policyPaths: []string{"testdata/fixtures/fs/namespace-exception/policy"}, policyPaths: []string{"testdata/fixtures/fs/namespace-exception/policy"},
input: "testdata/fixtures/fs/namespace-exception", input: "testdata/fixtures/fs/namespace-exception",
}, },
golden: "testdata/dockerfile-namespace-exception.json.golden", golden: "testdata/dockerfile-namespace-exception.json.golden",
}, },
{ {
name: "dockerfile with custom policies", name: "dockerfile with custom policies",
args: args{ args: args{
securityChecks: "config", scanners: types.MisconfigScanner,
policyPaths: []string{"testdata/fixtures/fs/custom-policy/policy"}, policyPaths: []string{"testdata/fixtures/fs/custom-policy/policy"},
namespaces: []string{"user"}, namespaces: []string{"user"},
input: "testdata/fixtures/fs/custom-policy", input: "testdata/fixtures/fs/custom-policy",
}, },
golden: "testdata/dockerfile-custom-policies.json.golden", golden: "testdata/dockerfile-custom-policies.json.golden",
}, },
{ {
name: "tarball helm chart scanning with builtin policies", name: "tarball helm chart scanning with builtin policies",
args: args{ args: args{
securityChecks: "config", scanners: types.MisconfigScanner,
input: "testdata/fixtures/fs/helm", input: "testdata/fixtures/fs/helm",
}, },
golden: "testdata/helm.json.golden", golden: "testdata/helm.json.golden",
}, },
{ {
name: "helm chart directory scanning with builtin policies", name: "helm chart directory scanning with builtin policies",
args: args{ args: args{
securityChecks: "config", scanners: types.MisconfigScanner,
input: "testdata/fixtures/fs/helm_testchart", input: "testdata/fixtures/fs/helm_testchart",
}, },
golden: "testdata/helm_testchart.json.golden", golden: "testdata/helm_testchart.json.golden",
}, },
{ {
name: "helm chart directory scanning with value overrides using set", name: "helm chart directory scanning with value overrides using set",
args: args{ args: args{
securityChecks: "config", scanners: types.MisconfigScanner,
input: "testdata/fixtures/fs/helm_testchart", input: "testdata/fixtures/fs/helm_testchart",
helmSet: []string{"securityContext.runAsUser=0"}, helmSet: []string{"securityContext.runAsUser=0"},
}, },
golden: "testdata/helm_testchart.overridden.json.golden", golden: "testdata/helm_testchart.overridden.json.golden",
}, },
{ {
name: "helm chart directory scanning with value overrides using value file", name: "helm chart directory scanning with value overrides using value file",
args: args{ args: args{
securityChecks: "config", scanners: types.MisconfigScanner,
input: "testdata/fixtures/fs/helm_testchart", input: "testdata/fixtures/fs/helm_testchart",
helmValuesFile: []string{"testdata/fixtures/fs/helm_values/values.yaml"}, helmValuesFile: []string{"testdata/fixtures/fs/helm_values/values.yaml"},
}, },
@@ -251,17 +253,17 @@ func TestFilesystem(t *testing.T) {
{ {
name: "helm chart directory scanning with builtin policies and non string Chart name", name: "helm chart directory scanning with builtin policies and non string Chart name",
args: args{ args: args{
securityChecks: "config", scanners: types.MisconfigScanner,
input: "testdata/fixtures/fs/helm_badname", input: "testdata/fixtures/fs/helm_badname",
}, },
golden: "testdata/helm_badname.json.golden", golden: "testdata/helm_badname.json.golden",
}, },
{ {
name: "secrets", name: "secrets",
args: args{ args: args{
securityChecks: "vuln,secret", scanners: "vuln,secret",
input: "testdata/fixtures/fs/secrets", input: "testdata/fixtures/fs/secrets",
secretConfig: "testdata/fixtures/fs/secrets/trivy-secret.yaml", secretConfig: "testdata/fixtures/fs/secrets/trivy-secret.yaml",
}, },
golden: "testdata/secrets.json.golden", golden: "testdata/secrets.json.golden",
}, },
@@ -305,12 +307,19 @@ func TestFilesystem(t *testing.T) {
} }
osArgs := []string{ osArgs := []string{
"-q", "--cache-dir", cacheDir, command, "--skip-db-update", "--skip-policy-update", "-q",
"--format", format, "--offline-scan", "--cache-dir",
cacheDir,
command,
"--skip-db-update",
"--skip-policy-update",
"--format",
format,
"--offline-scan",
} }
if tt.args.securityChecks != "" { if tt.args.scanners != "" {
osArgs = append(osArgs, "--security-checks", tt.args.securityChecks) osArgs = append(osArgs, "--scanners", tt.args.scanners)
} }
if len(tt.args.policyPaths) != 0 { if len(tt.args.policyPaths) != 0 {

View File

@@ -75,8 +75,15 @@ func TestVM(t *testing.T) {
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
osArgs := []string{ osArgs := []string{
"--cache-dir", cacheDir, "vm", "--security-checks", "vuln", "-q", "--skip-db-update", "--cache-dir",
"--format", tt.args.format, cacheDir,
"vm",
"--scanners",
"vuln",
"-q",
"--skip-db-update",
"--format",
tt.args.format,
} }
tmpDir := t.TempDir() tmpDir := t.TempDir()

View File

@@ -581,7 +581,7 @@ func NewConfigCommand(globalFlags *flag.GlobalFlagGroup) *cobra.Command {
options.DisabledAnalyzers = append(analyzer.TypeOSes, analyzer.TypeLanguages...) options.DisabledAnalyzers = append(analyzer.TypeOSes, analyzer.TypeLanguages...)
// Scan only for misconfigurations // Scan only for misconfigurations
options.SecurityChecks = []string{types.SecurityCheckConfig} options.Scanners = []string{types.MisconfigScanner}
return artifact.Run(cmd.Context(), options, artifact.TargetFilesystem) return artifact.Run(cmd.Context(), options, artifact.TargetFilesystem)
}, },
@@ -743,15 +743,15 @@ func NewModuleCommand(globalFlags *flag.GlobalFlagGroup) *cobra.Command {
func NewKubernetesCommand(globalFlags *flag.GlobalFlagGroup) *cobra.Command { func NewKubernetesCommand(globalFlags *flag.GlobalFlagGroup) *cobra.Command {
scanFlags := flag.NewScanFlagGroup() scanFlags := flag.NewScanFlagGroup()
securityChecks := flag.SecurityChecksFlag scanners := flag.ScannersFlag
securityChecks.Value = fmt.Sprintf( // overwrite the default value scanners.Value = fmt.Sprintf( // overwrite the default value
"%s,%s,%s,%s", "%s,%s,%s,%s",
types.SecurityCheckVulnerability, types.VulnerabilityScanner,
types.SecurityCheckConfig, types.MisconfigScanner,
types.SecurityCheckSecret, types.SecretScanner,
types.SecurityCheckRbac, types.RBACScanner,
) )
scanFlags.SecurityChecks = &securityChecks scanFlags.Scanners = &scanners
reportFlagGroup := flag.NewReportFlagGroup() reportFlagGroup := flag.NewReportFlagGroup()
compliance := flag.ComplianceFlag compliance := flag.ComplianceFlag
@@ -908,7 +908,7 @@ func NewVMCommand(globalFlags *flag.GlobalFlagGroup) *cobra.Command {
Aliases: []string{}, Aliases: []string{},
Short: "[EXPERIMENTAL] Scan a virtual machine image", Short: "[EXPERIMENTAL] Scan a virtual machine image",
Example: ` # Scan your AWS AMI Example: ` # Scan your AWS AMI
$ trivy vm --security-checks vuln ami:${your_ami_id} $ trivy vm --scanners vuln ami:${your_ami_id}
# Scan your AWS EBS snapshot # Scan your AWS EBS snapshot
$ trivy vm ebs:${your_ebs_snapshot_id} $ trivy vm ebs:${your_ebs_snapshot_id}
@@ -949,7 +949,7 @@ func NewSBOMCommand(globalFlags *flag.GlobalFlagGroup) *cobra.Command {
reportFlagGroup.ReportFormat = nil // TODO: support --report summary reportFlagGroup.ReportFormat = nil // TODO: support --report summary
scanFlags := flag.NewScanFlagGroup() scanFlags := flag.NewScanFlagGroup()
scanFlags.SecurityChecks = nil // disable '--security-checks' as it always scans for vulnerabilities scanFlags.Scanners = nil // disable '--scanners' as it always scans for vulnerabilities
sbomFlags := &flag.Flags{ sbomFlags := &flag.Flags{
CacheFlagGroup: flag.NewCacheFlagGroup(), CacheFlagGroup: flag.NewCacheFlagGroup(),
@@ -989,7 +989,7 @@ func NewSBOMCommand(globalFlags *flag.GlobalFlagGroup) *cobra.Command {
} }
// Scan vulnerabilities // Scan vulnerabilities
options.SecurityChecks = []string{types.SecurityCheckVulnerability} options.Scanners = []string{types.VulnerabilityScanner}
return artifact.Run(cmd.Context(), options, artifact.TargetSBOM) return artifact.Run(cmd.Context(), options, artifact.TargetSBOM)
}, },

View File

@@ -46,8 +46,12 @@ const (
) )
var ( var (
defaultPolicyNamespaces = []string{"appshield", "defsec", "builtin"} defaultPolicyNamespaces = []string{
SkipScan = errors.New("skip subsequent processes") "appshield",
"defsec",
"builtin",
}
SkipScan = errors.New("skip subsequent processes")
) )
// InitializeScanner defines the initialize function signature of scanner // InitializeScanner defines the initialize function signature of scanner
@@ -293,7 +297,7 @@ func (r *runner) Report(opts flag.Options, report types.Report) error {
func (r *runner) initDB(opts flag.Options) error { func (r *runner) initDB(opts flag.Options) error {
// When scanning config files or running as client mode, it doesn't need to download the vulnerability database. // When scanning config files or running as client mode, it doesn't need to download the vulnerability database.
if opts.ServerAddr != "" || !slices.Contains(opts.SecurityChecks, types.SecurityCheckVulnerability) { if opts.ServerAddr != "" || !slices.Contains(opts.Scanners, types.VulnerabilityScanner) {
return nil return nil
} }
@@ -448,19 +452,19 @@ func disabledAnalyzers(opts flag.Options) []analyzer.Type {
} }
// Do not perform secret scanning when it is not specified. // Do not perform secret scanning when it is not specified.
if !slices.Contains(opts.SecurityChecks, types.SecurityCheckSecret) { if !slices.Contains(opts.Scanners, types.SecretScanner) {
analyzers = append(analyzers, analyzer.TypeSecret) analyzers = append(analyzers, analyzer.TypeSecret)
} }
// Do not perform misconfiguration scanning when it is not specified. // Do not perform misconfiguration scanning when it is not specified.
if !slices.Contains(opts.SecurityChecks, types.SecurityCheckConfig) && if !slices.Contains(opts.Scanners, types.MisconfigScanner) &&
!slices.Contains(opts.SecurityChecks, types.SecurityCheckRbac) { !slices.Contains(opts.Scanners, types.RBACScanner) {
analyzers = append(analyzers, analyzer.TypeConfigFiles...) analyzers = append(analyzers, analyzer.TypeConfigFiles...)
} }
// Scanning file headers and license files is expensive. // Scanning file headers and license files is expensive.
// It is performed only when '--security-checks license' and '--license-full' are specified. // It is performed only when '--scanners license' and '--license-full' are specified.
if !slices.Contains(opts.SecurityChecks, types.SecurityCheckLicense) || !opts.LicenseFull { if !slices.Contains(opts.Scanners, types.LicenseScanner) || !opts.LicenseFull {
analyzers = append(analyzers, analyzer.TypeLicenseFile) analyzers = append(analyzers, analyzer.TypeLicenseFile)
} }
@@ -479,7 +483,7 @@ func initScannerConfig(opts flag.Options, cacheClient cache.Cache) (ScannerConfi
scanOptions := types.ScanOptions{ scanOptions := types.ScanOptions{
VulnType: opts.VulnType, VulnType: opts.VulnType,
SecurityChecks: opts.SecurityChecks, Scanners: opts.Scanners,
ScanRemovedPackages: opts.ScanRemovedPkgs, // this is valid only for 'image' subcommand ScanRemovedPackages: opts.ScanRemovedPkgs, // this is valid only for 'image' subcommand
Platform: opts.Platform, // this is valid only for 'image' subcommand Platform: opts.Platform, // this is valid only for 'image' subcommand
ListAllPackages: opts.ListAllPkgs, ListAllPackages: opts.ListAllPkgs,
@@ -487,7 +491,7 @@ func initScannerConfig(opts flag.Options, cacheClient cache.Cache) (ScannerConfi
FilePatterns: opts.FilePatterns, FilePatterns: opts.FilePatterns,
} }
if slices.Contains(opts.SecurityChecks, types.SecurityCheckVulnerability) { if slices.Contains(opts.Scanners, types.VulnerabilityScanner) {
log.Logger.Info("Vulnerability scanning is enabled") log.Logger.Info("Vulnerability scanning is enabled")
log.Logger.Debugf("Vulnerability type: %s", scanOptions.VulnType) log.Logger.Debugf("Vulnerability type: %s", scanOptions.VulnType)
} }
@@ -506,7 +510,7 @@ func initScannerConfig(opts flag.Options, cacheClient cache.Cache) (ScannerConfi
// ScannerOption is filled only when config scanning is enabled. // ScannerOption is filled only when config scanning is enabled.
var configScannerOptions config.ScannerOption var configScannerOptions config.ScannerOption
if slices.Contains(opts.SecurityChecks, types.SecurityCheckConfig) { if slices.Contains(opts.Scanners, types.MisconfigScanner) {
log.Logger.Info("Misconfiguration scanning is enabled") log.Logger.Info("Misconfiguration scanning is enabled")
configScannerOptions = config.ScannerOption{ configScannerOptions = config.ScannerOption{
Trace: opts.Trace, Trace: opts.Trace,
@@ -523,16 +527,16 @@ func initScannerConfig(opts flag.Options, cacheClient cache.Cache) (ScannerConfi
} }
// Do not load config file for secret scanning // Do not load config file for secret scanning
if slices.Contains(opts.SecurityChecks, types.SecurityCheckSecret) { if slices.Contains(opts.Scanners, types.SecretScanner) {
ver := canonicalVersion(opts.AppVersion) ver := canonicalVersion(opts.AppVersion)
log.Logger.Info("Secret scanning is enabled") log.Logger.Info("Secret scanning is enabled")
log.Logger.Info("If your scanning is slow, please try '--security-checks vuln' to disable secret scanning") log.Logger.Info("If your scanning is slow, please try '--scanners vuln' to disable secret scanning")
log.Logger.Infof("Please see also https://aquasecurity.github.io/trivy/%s/docs/secret/scanning/#recommendation for faster secret detection", ver) log.Logger.Infof("Please see also https://aquasecurity.github.io/trivy/%s/docs/secret/scanning/#recommendation for faster secret detection", ver)
} else { } else {
opts.SecretConfigPath = "" opts.SecretConfigPath = ""
} }
if slices.Contains(opts.SecurityChecks, types.SecurityCheckLicense) { if slices.Contains(opts.Scanners, types.LicenseScanner) {
if opts.LicenseFull { if opts.LicenseFull {
log.Logger.Info("Full license scanning is enabled") log.Logger.Info("Full license scanning is enabled")
} else { } else {

View File

@@ -61,13 +61,13 @@ const (
WarnStatus ControlStatus = "WARN" WarnStatus ControlStatus = "WARN"
) )
// SecurityChecks reads spec control and determines the scanners by check ID prefix // Scanners reads spec control and determines the scanners by check ID prefix
func (cs *ComplianceSpec) SecurityChecks() ([]types.SecurityCheck, error) { func (cs *ComplianceSpec) Scanners() ([]types.Scanner, error) {
scannerTypes := map[types.SecurityCheck]struct{}{} scannerTypes := map[types.Scanner]struct{}{}
for _, control := range cs.Spec.Controls { for _, control := range cs.Spec.Controls {
for _, check := range control.Checks { for _, check := range control.Checks {
scannerType := securityCheckByCheckID(check.ID) scannerType := scannerByCheckID(check.ID)
if scannerType == types.SecurityCheckUnknown { if scannerType == types.ScannerUnknown {
return nil, xerrors.Errorf("unsupported check ID: %s", check.ID) return nil, xerrors.Errorf("unsupported check ID: %s", check.ID)
} }
scannerTypes[scannerType] = struct{}{} scannerTypes[scannerType] = struct{}{}
@@ -77,26 +77,26 @@ func (cs *ComplianceSpec) SecurityChecks() ([]types.SecurityCheck, error) {
} }
// CheckIDs return list of compliance check IDs // CheckIDs return list of compliance check IDs
func (cs *ComplianceSpec) CheckIDs() map[types.SecurityCheck][]string { func (cs *ComplianceSpec) CheckIDs() map[types.Scanner][]string {
checkIDsMap := map[types.SecurityCheck][]string{} checkIDsMap := map[types.Scanner][]string{}
for _, control := range cs.Spec.Controls { for _, control := range cs.Spec.Controls {
for _, check := range control.Checks { for _, check := range control.Checks {
scannerType := securityCheckByCheckID(check.ID) scannerType := scannerByCheckID(check.ID)
checkIDsMap[scannerType] = append(checkIDsMap[scannerType], check.ID) checkIDsMap[scannerType] = append(checkIDsMap[scannerType], check.ID)
} }
} }
return checkIDsMap return checkIDsMap
} }
func securityCheckByCheckID(checkID string) types.SecurityCheck { func scannerByCheckID(checkID string) types.Scanner {
checkID = strings.ToLower(checkID) checkID = strings.ToLower(checkID)
switch { switch {
case strings.HasPrefix(checkID, "cve-") || strings.HasPrefix(checkID, "dla-"): case strings.HasPrefix(checkID, "cve-") || strings.HasPrefix(checkID, "dla-"):
return types.SecurityCheckVulnerability return types.VulnerabilityScanner
case strings.HasPrefix(checkID, "avd-"): case strings.HasPrefix(checkID, "avd-"):
return types.SecurityCheckConfig return types.MisconfigScanner
default: default:
return types.SecurityCheckUnknown return types.ScannerUnknown
} }
} }

View File

@@ -11,11 +11,11 @@ import (
"github.com/aquasecurity/trivy/pkg/types" "github.com/aquasecurity/trivy/pkg/types"
) )
func TestComplianceSpec_SecurityChecks(t *testing.T) { func TestComplianceSpec_Scanners(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
spec spec.Spec spec spec.Spec
want []types.SecurityCheck want []types.Scanner
wantErr assert.ErrorAssertionFunc wantErr assert.ErrorAssertionFunc
}{ }{
{ {
@@ -48,7 +48,7 @@ func TestComplianceSpec_SecurityChecks(t *testing.T) {
}, },
}, },
}, },
want: []types.SecurityCheck{types.SecurityCheckConfig}, want: []types.Scanner{types.MisconfigScanner},
wantErr: assert.NoError, wantErr: assert.NoError,
}, },
{ {
@@ -89,7 +89,10 @@ func TestComplianceSpec_SecurityChecks(t *testing.T) {
}, },
}, },
}, },
want: []types.SecurityCheck{types.SecurityCheckConfig, types.SecurityCheckVulnerability}, want: []types.Scanner{
types.MisconfigScanner,
types.VulnerabilityScanner,
},
wantErr: assert.NoError, wantErr: assert.NoError,
}, },
{ {
@@ -120,12 +123,12 @@ func TestComplianceSpec_SecurityChecks(t *testing.T) {
cs := &spec.ComplianceSpec{ cs := &spec.ComplianceSpec{
Spec: tt.spec, Spec: tt.spec,
} }
got, err := cs.SecurityChecks() got, err := cs.Scanners()
if !tt.wantErr(t, err, fmt.Sprintf("SecurityChecks()")) { if !tt.wantErr(t, err, fmt.Sprintf("Scanners()")) {
return return
} }
sort.Strings(got) // for consistency sort.Strings(got) // for consistency
assert.Equalf(t, tt.want, got, "SecurityChecks()") assert.Equalf(t, tt.want, got, "Scanners()")
}) })
} }
} }
@@ -134,7 +137,7 @@ func TestComplianceSpec_CheckIDs(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
spec spec.Spec spec spec.Spec
want map[types.SecurityCheck][]string want map[types.Scanner][]string
}{ }{
{ {
name: "get config scanner type by check id prefix", name: "get config scanner type by check id prefix",
@@ -166,8 +169,8 @@ func TestComplianceSpec_CheckIDs(t *testing.T) {
}, },
}, },
}, },
want: map[types.SecurityCheck][]string{ want: map[types.Scanner][]string{
types.SecurityCheckConfig: { types.MisconfigScanner: {
"AVD-KSV012", "AVD-KSV012",
"AVD-1.2.31", "AVD-1.2.31",
"AVD-1.2.32", "AVD-1.2.32",
@@ -212,13 +215,13 @@ func TestComplianceSpec_CheckIDs(t *testing.T) {
}, },
}, },
}, },
want: map[types.SecurityCheck][]string{ want: map[types.Scanner][]string{
types.SecurityCheckConfig: { types.MisconfigScanner: {
"AVD-KSV012", "AVD-KSV012",
"AVD-1.2.31", "AVD-1.2.31",
"AVD-1.2.32", "AVD-1.2.32",
}, },
types.SecurityCheckVulnerability: { types.VulnerabilityScanner: {
"CVE-9999-9999", "CVE-9999-9999",
}, },
}, },

View File

@@ -7,11 +7,11 @@ import (
) )
// MapSpecCheckIDToFilteredResults map spec check id to filtered scan results // MapSpecCheckIDToFilteredResults map spec check id to filtered scan results
func MapSpecCheckIDToFilteredResults(result types.Result, checkIDs map[types.SecurityCheck][]string) map[string]types.Results { func MapSpecCheckIDToFilteredResults(result types.Result, checkIDs map[types.Scanner][]string) map[string]types.Results {
mapCheckByID := make(map[string]types.Results) mapCheckByID := make(map[string]types.Results)
for _, vuln := range result.Vulnerabilities { for _, vuln := range result.Vulnerabilities {
// Skip irrelevant check IDs // Skip irrelevant check IDs
if !slices.Contains(checkIDs[types.SecurityCheckVulnerability], vuln.GetID()) { if !slices.Contains(checkIDs[types.VulnerabilityScanner], vuln.GetID()) {
continue continue
} }
mapCheckByID[vuln.GetID()] = append(mapCheckByID[vuln.GetID()], types.Result{ mapCheckByID[vuln.GetID()] = append(mapCheckByID[vuln.GetID()], types.Result{
@@ -23,7 +23,7 @@ func MapSpecCheckIDToFilteredResults(result types.Result, checkIDs map[types.Sec
} }
for _, m := range result.Misconfigurations { for _, m := range result.Misconfigurations {
// Skip irrelevant check IDs // Skip irrelevant check IDs
if !slices.Contains(checkIDs[types.SecurityCheckConfig], m.GetID()) { if !slices.Contains(checkIDs[types.MisconfigScanner], m.GetID()) {
continue continue
} }

View File

@@ -11,19 +11,19 @@ import (
) )
func TestMapSpecCheckIDToFilteredResults(t *testing.T) { func TestMapSpecCheckIDToFilteredResults(t *testing.T) {
checkIDs := map[types.SecurityCheck][]string{ checkIDs := map[types.Scanner][]string{
types.SecurityCheckConfig: { types.MisconfigScanner: {
"AVD-KSV012", "AVD-KSV012",
"AVD-1.2.31", "AVD-1.2.31",
"AVD-1.2.32", "AVD-1.2.32",
}, },
types.SecurityCheckVulnerability: { types.VulnerabilityScanner: {
"CVE-9999-9999", "CVE-9999-9999",
}, },
} }
tests := []struct { tests := []struct {
name string name string
checkIDs map[types.SecurityCheck][]string checkIDs map[types.Scanner][]string
result types.Result result types.Result
want map[string]types.Results want map[string]types.Results
}{ }{
@@ -35,31 +35,54 @@ func TestMapSpecCheckIDToFilteredResults(t *testing.T) {
Class: types.ClassConfig, Class: types.ClassConfig,
Type: ftypes.Kubernetes, Type: ftypes.Kubernetes,
Misconfigurations: []types.DetectedMisconfiguration{ Misconfigurations: []types.DetectedMisconfiguration{
{AVDID: "AVD-KSV012", Status: types.StatusFailure}, {
{AVDID: "AVD-KSV013", Status: types.StatusFailure}, AVDID: "AVD-KSV012",
{AVDID: "AVD-1.2.31", Status: types.StatusFailure}, Status: types.StatusFailure,
},
{
AVDID: "AVD-KSV013",
Status: types.StatusFailure,
},
{
AVDID: "AVD-1.2.31",
Status: types.StatusFailure,
},
}, },
}, },
want: map[string]types.Results{ want: map[string]types.Results{
"AVD-KSV012": { "AVD-KSV012": {
{ {
Target: "target", Target: "target",
Class: types.ClassConfig, Class: types.ClassConfig,
Type: ftypes.Kubernetes, Type: ftypes.Kubernetes,
MisconfSummary: &types.MisconfSummary{Successes: 0, Failures: 1, Exceptions: 0}, MisconfSummary: &types.MisconfSummary{
Successes: 0,
Failures: 1,
Exceptions: 0,
},
Misconfigurations: []types.DetectedMisconfiguration{ Misconfigurations: []types.DetectedMisconfiguration{
{AVDID: "AVD-KSV012", Status: types.StatusFailure}, {
AVDID: "AVD-KSV012",
Status: types.StatusFailure,
},
}, },
}, },
}, },
"AVD-1.2.31": { "AVD-1.2.31": {
{ {
Target: "target", Target: "target",
Class: types.ClassConfig, Class: types.ClassConfig,
Type: ftypes.Kubernetes, Type: ftypes.Kubernetes,
MisconfSummary: &types.MisconfSummary{Successes: 0, Failures: 1, Exceptions: 0}, MisconfSummary: &types.MisconfSummary{
Successes: 0,
Failures: 1,
Exceptions: 0,
},
Misconfigurations: []types.DetectedMisconfiguration{ Misconfigurations: []types.DetectedMisconfiguration{
{AVDID: "AVD-1.2.31", Status: types.StatusFailure}, {
AVDID: "AVD-1.2.31",
Status: types.StatusFailure,
},
}, },
}, },
}, },

View File

@@ -11,7 +11,7 @@ var (
Name: "include-non-failures", Name: "include-non-failures",
ConfigName: "misconfiguration.include-non-failures", ConfigName: "misconfiguration.include-non-failures",
Value: false, Value: false,
Usage: "include successes and exceptions, available with '--security-checks config'", Usage: "include successes and exceptions, available with '--scanners config'",
} }
HelmValuesFileFlag = Flag{ HelmValuesFileFlag = Flag{
Name: "helm-values", Name: "helm-values",

View File

@@ -94,14 +94,14 @@ type Options struct {
// Align takes consistency of options // Align takes consistency of options
func (o *Options) Align() { func (o *Options) Align() {
if o.Format == report.FormatSPDX || o.Format == report.FormatSPDXJSON { if o.Format == report.FormatSPDX || o.Format == report.FormatSPDXJSON {
log.Logger.Info(`"--format spdx" and "--format spdx-json" disable security checks`) log.Logger.Info(`"--format spdx" and "--format spdx-json" disable security scanning`)
o.SecurityChecks = nil o.Scanners = nil
} }
// Vulnerability scanning is disabled by default for CycloneDX. // Vulnerability scanning is disabled by default for CycloneDX.
if o.Format == report.FormatCycloneDX && !viper.IsSet(SecurityChecksFlag.ConfigName) { if o.Format == report.FormatCycloneDX && !viper.IsSet(ScannersFlag.ConfigName) {
log.Logger.Info(`"--format cyclonedx" disables security checks. Specify "--security-checks vuln" explicitly if you want to include vulnerabilities in the CycloneDX report.`) log.Logger.Info(`"--format cyclonedx" disables security scanning. Specify "--scanners vuln" explicitly if you want to include vulnerabilities in the CycloneDX report.`)
o.SecurityChecks = nil o.Scanners = nil
} }
} }
@@ -415,6 +415,8 @@ func flagNameNormalize(f *pflag.FlagSet, name string) pflag.NormalizedName {
name = PolicyNamespaceFlag.Name name = PolicyNamespaceFlag.Name
case "ctx": case "ctx":
name = ClusterContextFlag.Name name = ClusterContextFlag.Name
case "security-checks":
name = ScannersFlag.Name
} }
return pflag.NormalizedName(name) return pflag.NormalizedName(name)
} }

View File

@@ -24,30 +24,42 @@ func Test_getStringSlice(t *testing.T) {
}{ }{
{ {
name: "happy path. Empty value", name: "happy path. Empty value",
flag: &SecurityChecksFlag, flag: &ScannersFlag,
flagValue: "", flagValue: "",
want: nil, want: nil,
}, },
{ {
name: "happy path. String value", name: "happy path. String value",
flag: &SecurityChecksFlag, flag: &ScannersFlag,
flagValue: "license,vuln", flagValue: "license,vuln",
want: []string{types.SecurityCheckLicense, types.SecurityCheckVulnerability}, want: []string{
types.LicenseScanner,
types.VulnerabilityScanner,
},
}, },
{ {
name: "happy path. Slice value", name: "happy path. Slice value",
flag: &SecurityChecksFlag, flag: &ScannersFlag,
flagValue: []string{"license", "secret"}, flagValue: []string{
want: []string{types.SecurityCheckLicense, types.SecurityCheckSecret}, "license",
"secret",
},
want: []string{
types.LicenseScanner,
types.SecretScanner,
},
}, },
{ {
name: "happy path. Env value", name: "happy path. Env value",
flag: &SecurityChecksFlag, flag: &ScannersFlag,
env: env{ env: env{
key: "TRIVY_SECURITY_CHECKS", key: "TRIVY_SECURITY_CHECKS",
value: "rbac,config", value: "rbac,config",
}, },
want: []string{types.SecurityCheckRbac, types.SecurityCheckConfig}, want: []string{
types.RBACScanner,
types.MisconfigScanner,
},
}, },
} }

View File

@@ -26,11 +26,14 @@ var (
Value: false, Value: false,
Usage: "do not issue API requests to identify dependencies", Usage: "do not issue API requests to identify dependencies",
} }
SecurityChecksFlag = Flag{ ScannersFlag = Flag{
Name: "security-checks", Name: "scanners",
ConfigName: "scan.security-checks", ConfigName: "scan.scanners",
Value: []string{types.SecurityCheckVulnerability, types.SecurityCheckSecret}, Value: []string{
Usage: "comma-separated list of what security issues to detect (vuln,config,secret,license)", types.VulnerabilityScanner,
types.SecretScanner,
},
Usage: "comma-separated list of what security issues to detect (vuln,config,secret,license)",
} }
FilePatternsFlag = Flag{ FilePatternsFlag = Flag{
Name: "file-patterns", Name: "file-patterns",
@@ -59,38 +62,38 @@ var (
) )
type ScanFlagGroup struct { type ScanFlagGroup struct {
SkipDirs *Flag SkipDirs *Flag
SkipFiles *Flag SkipFiles *Flag
OfflineScan *Flag OfflineScan *Flag
SecurityChecks *Flag Scanners *Flag
FilePatterns *Flag FilePatterns *Flag
Slow *Flag Slow *Flag
SBOMSources *Flag SBOMSources *Flag
RekorURL *Flag RekorURL *Flag
} }
type ScanOptions struct { type ScanOptions struct {
Target string Target string
SkipDirs []string SkipDirs []string
SkipFiles []string SkipFiles []string
OfflineScan bool OfflineScan bool
SecurityChecks []string Scanners []string
FilePatterns []string FilePatterns []string
Slow bool Slow bool
SBOMSources []string SBOMSources []string
RekorURL string RekorURL string
} }
func NewScanFlagGroup() *ScanFlagGroup { func NewScanFlagGroup() *ScanFlagGroup {
return &ScanFlagGroup{ return &ScanFlagGroup{
SkipDirs: &SkipDirsFlag, SkipDirs: &SkipDirsFlag,
SkipFiles: &SkipFilesFlag, SkipFiles: &SkipFilesFlag,
OfflineScan: &OfflineScanFlag, OfflineScan: &OfflineScanFlag,
SecurityChecks: &SecurityChecksFlag, Scanners: &ScannersFlag,
FilePatterns: &FilePatternsFlag, FilePatterns: &FilePatternsFlag,
Slow: &SlowFlag, Slow: &SlowFlag,
SBOMSources: &SBOMSourcesFlag, SBOMSources: &SBOMSourcesFlag,
RekorURL: &RekorURLFlag, RekorURL: &RekorURLFlag,
} }
} }
@@ -99,8 +102,16 @@ func (f *ScanFlagGroup) Name() string {
} }
func (f *ScanFlagGroup) Flags() []*Flag { func (f *ScanFlagGroup) Flags() []*Flag {
return []*Flag{f.SkipDirs, f.SkipFiles, f.OfflineScan, f.SecurityChecks, f.FilePatterns, return []*Flag{
f.Slow, f.SBOMSources, f.RekorURL} f.SkipDirs,
f.SkipFiles,
f.OfflineScan,
f.Scanners,
f.FilePatterns,
f.Slow,
f.SBOMSources,
f.RekorURL,
}
} }
func (f *ScanFlagGroup) ToOptions(args []string) (ScanOptions, error) { func (f *ScanFlagGroup) ToOptions(args []string) (ScanOptions, error) {
@@ -108,9 +119,9 @@ func (f *ScanFlagGroup) ToOptions(args []string) (ScanOptions, error) {
if len(args) == 1 { if len(args) == 1 {
target = args[0] target = args[0]
} }
securityChecks, err := parseSecurityCheck(getStringSlice(f.SecurityChecks)) scanners, err := parseScanners(getStringSlice(f.Scanners))
if err != nil { if err != nil {
return ScanOptions{}, xerrors.Errorf("unable to parse security checks: %w", err) return ScanOptions{}, xerrors.Errorf("unable to parse scanners: %w", err)
} }
sbomSources := getStringSlice(f.SBOMSources) sbomSources := getStringSlice(f.SBOMSources)
@@ -119,27 +130,27 @@ func (f *ScanFlagGroup) ToOptions(args []string) (ScanOptions, error) {
} }
return ScanOptions{ return ScanOptions{
Target: target, Target: target,
SkipDirs: getStringSlice(f.SkipDirs), SkipDirs: getStringSlice(f.SkipDirs),
SkipFiles: getStringSlice(f.SkipFiles), SkipFiles: getStringSlice(f.SkipFiles),
OfflineScan: getBool(f.OfflineScan), OfflineScan: getBool(f.OfflineScan),
SecurityChecks: securityChecks, Scanners: scanners,
FilePatterns: getStringSlice(f.FilePatterns), FilePatterns: getStringSlice(f.FilePatterns),
Slow: getBool(f.Slow), Slow: getBool(f.Slow),
SBOMSources: sbomSources, SBOMSources: sbomSources,
RekorURL: getString(f.RekorURL), RekorURL: getString(f.RekorURL),
}, nil }, nil
} }
func parseSecurityCheck(securityCheck []string) ([]string, error) { func parseScanners(scanner []string) ([]string, error) {
var securityChecks []string var scanners []string
for _, v := range securityCheck { for _, v := range scanner {
if !slices.Contains(types.SecurityChecks, v) { if !slices.Contains(types.Scanners, v) {
return nil, xerrors.Errorf("unknown security check: %s", v) return nil, xerrors.Errorf("unknown scanner: %s", v)
} }
securityChecks = append(securityChecks, v) scanners = append(scanners, v)
} }
return securityChecks, nil return scanners, nil
} }
func validateSBOMSources(sbomSources []string) error { func validateSBOMSources(sbomSources []string) error {

View File

@@ -13,10 +13,10 @@ import (
func TestScanFlagGroup_ToOptions(t *testing.T) { func TestScanFlagGroup_ToOptions(t *testing.T) {
type fields struct { type fields struct {
skipDirs []string skipDirs []string
skipFiles []string skipFiles []string
offlineScan bool offlineScan bool
securityChecks string scanners string
} }
tests := []struct { tests := []struct {
name string name string
@@ -38,22 +38,22 @@ func TestScanFlagGroup_ToOptions(t *testing.T) {
name: "happy path for configs", name: "happy path for configs",
args: []string{"alpine:latest"}, args: []string{"alpine:latest"},
fields: fields{ fields: fields{
securityChecks: "config", scanners: "config",
}, },
want: flag.ScanOptions{ want: flag.ScanOptions{
Target: "alpine:latest", Target: "alpine:latest",
SecurityChecks: []string{types.SecurityCheckConfig}, Scanners: []string{types.MisconfigScanner},
}, },
assertion: require.NoError, assertion: require.NoError,
}, },
{ {
name: "with wrong security check", name: "with wrong scanner",
fields: fields{ fields: fields{
securityChecks: "vuln,WRONG-CHECK", scanners: "vuln,WRONG-CHECK",
}, },
want: flag.ScanOptions{}, want: flag.ScanOptions{},
assertion: func(t require.TestingT, err error, msgs ...interface{}) { assertion: func(t require.TestingT, err error, msgs ...interface{}) {
require.ErrorContains(t, err, "unknown security check: WRONG-CHECK") require.ErrorContains(t, err, "unknown scanner: WRONG-CHECK")
}, },
}, },
{ {
@@ -64,8 +64,11 @@ func TestScanFlagGroup_ToOptions(t *testing.T) {
assertion: require.NoError, assertion: require.NoError,
}, },
{ {
name: "with two or more targets (args)", name: "with two or more targets (args)",
args: []string{"alpine:latest", "nginx:latest"}, args: []string{
"alpine:latest",
"nginx:latest",
},
fields: fields{}, fields: fields{},
want: flag.ScanOptions{}, want: flag.ScanOptions{},
assertion: require.NoError, assertion: require.NoError,
@@ -73,20 +76,32 @@ func TestScanFlagGroup_ToOptions(t *testing.T) {
{ {
name: "skip two files", name: "skip two files",
fields: fields{ fields: fields{
skipFiles: []string{"file1", "file2"}, skipFiles: []string{
"file1",
"file2",
},
}, },
want: flag.ScanOptions{ want: flag.ScanOptions{
SkipFiles: []string{"file1", "file2"}, SkipFiles: []string{
"file1",
"file2",
},
}, },
assertion: require.NoError, assertion: require.NoError,
}, },
{ {
name: "skip two folders", name: "skip two folders",
fields: fields{ fields: fields{
skipDirs: []string{"dir1", "dir2"}, skipDirs: []string{
"dir1",
"dir2",
},
}, },
want: flag.ScanOptions{ want: flag.ScanOptions{
SkipDirs: []string{"dir1", "dir2"}, SkipDirs: []string{
"dir1",
"dir2",
},
}, },
assertion: require.NoError, assertion: require.NoError,
}, },
@@ -107,14 +122,14 @@ func TestScanFlagGroup_ToOptions(t *testing.T) {
viper.Set(flag.SkipDirsFlag.ConfigName, tt.fields.skipDirs) viper.Set(flag.SkipDirsFlag.ConfigName, tt.fields.skipDirs)
viper.Set(flag.SkipFilesFlag.ConfigName, tt.fields.skipFiles) viper.Set(flag.SkipFilesFlag.ConfigName, tt.fields.skipFiles)
viper.Set(flag.OfflineScanFlag.ConfigName, tt.fields.offlineScan) viper.Set(flag.OfflineScanFlag.ConfigName, tt.fields.offlineScan)
viper.Set(flag.SecurityChecksFlag.ConfigName, tt.fields.securityChecks) viper.Set(flag.ScannersFlag.ConfigName, tt.fields.scanners)
// Assert options // Assert options
f := &flag.ScanFlagGroup{ f := &flag.ScanFlagGroup{
SkipDirs: &flag.SkipDirsFlag, SkipDirs: &flag.SkipDirsFlag,
SkipFiles: &flag.SkipFilesFlag, SkipFiles: &flag.SkipFilesFlag,
OfflineScan: &flag.OfflineScanFlag, OfflineScan: &flag.OfflineScanFlag,
SecurityChecks: &flag.SecurityChecksFlag, Scanners: &flag.ScannersFlag,
} }
got, err := f.ToOptions(tt.args) got, err := f.ToOptions(tt.args)

View File

@@ -51,7 +51,10 @@ type runner struct {
} }
func newRunner(flagOpts flag.Options, cluster string) *runner { func newRunner(flagOpts flag.Options, cluster string) *runner {
return &runner{flagOpts, cluster} return &runner{
flagOpts,
cluster,
}
} }
func (r *runner) run(ctx context.Context, artifacts []*artifacts.Artifact) error { func (r *runner) run(ctx context.Context, artifacts []*artifacts.Artifact) error {
@@ -90,11 +93,11 @@ func (r *runner) run(ctx context.Context, artifacts []*artifacts.Artifact) error
if err = yaml.Unmarshal(cs, &complianceSpec); err != nil { if err = yaml.Unmarshal(cs, &complianceSpec); err != nil {
return xerrors.Errorf("yaml unmarshal error: %w", err) return xerrors.Errorf("yaml unmarshal error: %w", err)
} }
securityChecks, err := complianceSpec.SecurityChecks() scanners, err := complianceSpec.Scanners()
if err != nil { if err != nil {
return xerrors.Errorf("security check error: %w", err) return xerrors.Errorf("scanner error: %w", err)
} }
r.flagOpts.ScanOptions.SecurityChecks = securityChecks r.flagOpts.ScanOptions.Scanners = scanners
} }
rpt, err := s.Scan(ctx, artifacts) rpt, err := s.Scan(ctx, artifacts)
@@ -117,16 +120,17 @@ func (r *runner) run(ctx context.Context, artifacts []*artifacts.Artifact) error
return cr.Write(complianceReport, cr.Option{ return cr.Write(complianceReport, cr.Option{
Format: r.flagOpts.Format, Format: r.flagOpts.Format,
Report: r.flagOpts.ReportFormat, Report: r.flagOpts.ReportFormat,
Output: r.flagOpts.Output}) Output: r.flagOpts.Output,
})
} }
if err := report.Write(rpt, report.Option{ if err := report.Write(rpt, report.Option{
Format: r.flagOpts.Format, Format: r.flagOpts.Format,
Report: r.flagOpts.ReportFormat, Report: r.flagOpts.ReportFormat,
Output: r.flagOpts.Output, Output: r.flagOpts.Output,
Severities: r.flagOpts.Severities, Severities: r.flagOpts.Severities,
Components: r.flagOpts.Components, Components: r.flagOpts.Components,
SecurityChecks: r.flagOpts.ScanOptions.SecurityChecks, Scanners: r.flagOpts.ScanOptions.Scanners,
}); err != nil { }); err != nil {
return xerrors.Errorf("unable to write results: %w", err) return xerrors.Errorf("unable to write results: %w", err)
} }

View File

@@ -29,13 +29,13 @@ const (
) )
type Option struct { type Option struct {
Format string Format string
Report string Report string
Output io.Writer Output io.Writer
Severities []dbTypes.Severity Severities []dbTypes.Severity
ColumnHeading []string ColumnHeading []string
SecurityChecks []string Scanners []string
Components []string Components []string
} }
// Report represents a kubernetes scan report // Report represents a kubernetes scan report
@@ -135,10 +135,13 @@ func Write(report Report, option Option) error {
switch option.Format { switch option.Format {
case jsonFormat: case jsonFormat:
jwriter := JSONWriter{Output: option.Output, Report: option.Report} jwriter := JSONWriter{
Output: option.Output,
Report: option.Report,
}
return jwriter.Write(report) return jwriter.Write(report)
case tableFormat: case tableFormat:
separatedReports := separateMisconfigReports(report, option.SecurityChecks, option.Components) separatedReports := separateMisconfigReports(report, option.Scanners, option.Components)
if option.Report == summaryReport { if option.Report == summaryReport {
target := fmt.Sprintf("Summary Report for %s", report.ClusterName) target := fmt.Sprintf("Summary Report for %s", report.ClusterName)
@@ -150,7 +153,7 @@ func Write(report Report, option Option) error {
Output: option.Output, Output: option.Output,
Report: option.Report, Report: option.Report,
Severities: option.Severities, Severities: option.Severities,
ColumnHeading: ColumnHeading(option.SecurityChecks, option.Components, r.columns), ColumnHeading: ColumnHeading(option.Scanners, option.Components, r.columns),
} }
if err := writer.Write(r.report); err != nil { if err := writer.Write(r.report); err != nil {
@@ -169,11 +172,11 @@ type reports struct {
columns []string columns []string
} }
// separateMisconfigReports returns 3 reports based on securityChecks and components flags, // separateMisconfigReports returns 3 reports based on scanners and components flags,
// - misconfiguration report // - misconfiguration report
// - rbac report // - rbac report
// - infra checks report // - infra checks report
func separateMisconfigReports(k8sReport Report, securityChecks, components []string) []reports { func separateMisconfigReports(k8sReport Report, scanners, components []string) []reports {
workloadMisconfig := make([]Resource, 0) workloadMisconfig := make([]Resource, 0)
infraMisconfig := make([]Resource, 0) infraMisconfig := make([]Resource, 0)
@@ -181,7 +184,7 @@ func separateMisconfigReports(k8sReport Report, securityChecks, components []str
for _, misConfig := range k8sReport.Misconfigurations { for _, misConfig := range k8sReport.Misconfigurations {
switch { switch {
case slices.Contains(securityChecks, types.SecurityCheckRbac) && rbacResource(misConfig): case slices.Contains(scanners, types.RBACScanner) && rbacResource(misConfig):
rbacAssessment = append(rbacAssessment, misConfig) rbacAssessment = append(rbacAssessment, misConfig)
case infraResource(misConfig): case infraResource(misConfig):
workload, infra := splitInfraAndWorkloadResources(misConfig) workload, infra := splitInfraAndWorkloadResources(misConfig)
@@ -194,7 +197,7 @@ func separateMisconfigReports(k8sReport Report, securityChecks, components []str
workloadMisconfig = append(workloadMisconfig, workload) workloadMisconfig = append(workloadMisconfig, workload)
} }
case slices.Contains(securityChecks, types.SecurityCheckConfig) && !rbacResource(misConfig): case slices.Contains(scanners, types.MisconfigScanner) && !rbacResource(misConfig):
if slices.Contains(components, workloadComponent) { if slices.Contains(components, workloadComponent) {
workloadMisconfig = append(workloadMisconfig, misConfig) workloadMisconfig = append(workloadMisconfig, misConfig)
} }
@@ -203,7 +206,7 @@ func separateMisconfigReports(k8sReport Report, securityChecks, components []str
r := make([]reports, 0) r := make([]reports, 0)
if shouldAddWorkloadReport(securityChecks) { if shouldAddWorkloadReport(scanners) {
workloadReport := Report{ workloadReport := Report{
SchemaVersion: 0, SchemaVersion: 0,
ClusterName: k8sReport.ClusterName, ClusterName: k8sReport.ClusterName,
@@ -215,11 +218,14 @@ func separateMisconfigReports(k8sReport Report, securityChecks, components []str
if (slices.Contains(components, workloadComponent) && if (slices.Contains(components, workloadComponent) &&
len(workloadMisconfig) > 0) || len(workloadMisconfig) > 0) ||
len(k8sReport.Vulnerabilities) > 0 { len(k8sReport.Vulnerabilities) > 0 {
r = append(r, reports{report: workloadReport, columns: WorkloadColumns()}) r = append(r, reports{
report: workloadReport,
columns: WorkloadColumns(),
})
} }
} }
if slices.Contains(securityChecks, types.SecurityCheckRbac) && len(rbacAssessment) > 0 { if slices.Contains(scanners, types.RBACScanner) && len(rbacAssessment) > 0 {
r = append(r, reports{ r = append(r, reports{
report: Report{ report: Report{
SchemaVersion: 0, SchemaVersion: 0,
@@ -231,7 +237,7 @@ func separateMisconfigReports(k8sReport Report, securityChecks, components []str
}) })
} }
if slices.Contains(securityChecks, types.SecurityCheckConfig) && if slices.Contains(scanners, types.MisconfigScanner) &&
slices.Contains(components, infraComponent) && slices.Contains(components, infraComponent) &&
len(infraMisconfig) > 0 { len(infraMisconfig) > 0 {
@@ -357,8 +363,8 @@ func copyResult(r types.Result, misconfigs []types.DetectedMisconfiguration) typ
} }
} }
func shouldAddWorkloadReport(securityChecks []string) bool { func shouldAddWorkloadReport(scanners []string) bool {
return slices.Contains(securityChecks, types.SecurityCheckConfig) || return slices.Contains(scanners, types.MisconfigScanner) ||
slices.Contains(securityChecks, types.SecurityCheckVulnerability) || slices.Contains(scanners, types.VulnerabilityScanner) ||
slices.Contains(securityChecks, types.SecurityCheckSecret) slices.Contains(scanners, types.SecretScanner)
} }

View File

@@ -19,15 +19,45 @@ var (
Kind: "Deploy", Kind: "Deploy",
Name: "orion", Name: "orion",
Results: types.Results{ Results: types.Results{
{Misconfigurations: []types.DetectedMisconfiguration{ {
{ID: "ID100", Status: types.StatusFailure, Severity: "LOW"}, Misconfigurations: []types.DetectedMisconfiguration{
{ID: "ID101", Status: types.StatusFailure, Severity: "MEDIUM"}, {
{ID: "ID102", Status: types.StatusFailure, Severity: "HIGH"}, ID: "ID100",
{ID: "ID103", Status: types.StatusFailure, Severity: "CRITICAL"}, Status: types.StatusFailure,
{ID: "ID104", Status: types.StatusFailure, Severity: "UNKNOWN"}, Severity: "LOW",
{ID: "ID105", Status: types.StatusFailure, Severity: "LOW"}, },
{ID: "ID106", Status: types.StatusFailure, Severity: "HIGH"}, {
}}, ID: "ID101",
Status: types.StatusFailure,
Severity: "MEDIUM",
},
{
ID: "ID102",
Status: types.StatusFailure,
Severity: "HIGH",
},
{
ID: "ID103",
Status: types.StatusFailure,
Severity: "CRITICAL",
},
{
ID: "ID104",
Status: types.StatusFailure,
Severity: "UNKNOWN",
},
{
ID: "ID105",
Status: types.StatusFailure,
Severity: "LOW",
},
{
ID: "ID106",
Status: types.StatusFailure,
Severity: "HIGH",
},
},
},
}, },
} }
@@ -36,15 +66,38 @@ var (
Kind: "Deploy", Kind: "Deploy",
Name: "orion", Name: "orion",
Results: types.Results{ Results: types.Results{
{Vulnerabilities: []types.DetectedVulnerability{ {
{VulnerabilityID: "CVE-2022-1111", Vulnerability: dbTypes.Vulnerability{Severity: "LOW"}}, Vulnerabilities: []types.DetectedVulnerability{
{VulnerabilityID: "CVE-2022-2222", Vulnerability: dbTypes.Vulnerability{Severity: "MEDIUM"}}, {
{VulnerabilityID: "CVE-2022-3333", Vulnerability: dbTypes.Vulnerability{Severity: "HIGH"}}, VulnerabilityID: "CVE-2022-1111",
{VulnerabilityID: "CVE-2022-4444", Vulnerability: dbTypes.Vulnerability{Severity: "CRITICAL"}}, Vulnerability: dbTypes.Vulnerability{Severity: "LOW"},
{VulnerabilityID: "CVE-2022-5555", Vulnerability: dbTypes.Vulnerability{Severity: "UNKNOWN"}}, },
{VulnerabilityID: "CVE-2022-6666", Vulnerability: dbTypes.Vulnerability{Severity: "CRITICAL"}}, {
{VulnerabilityID: "CVE-2022-7777", Vulnerability: dbTypes.Vulnerability{Severity: "MEDIUM"}}, VulnerabilityID: "CVE-2022-2222",
}}, Vulnerability: dbTypes.Vulnerability{Severity: "MEDIUM"},
},
{
VulnerabilityID: "CVE-2022-3333",
Vulnerability: dbTypes.Vulnerability{Severity: "HIGH"},
},
{
VulnerabilityID: "CVE-2022-4444",
Vulnerability: dbTypes.Vulnerability{Severity: "CRITICAL"},
},
{
VulnerabilityID: "CVE-2022-5555",
Vulnerability: dbTypes.Vulnerability{Severity: "UNKNOWN"},
},
{
VulnerabilityID: "CVE-2022-6666",
Vulnerability: dbTypes.Vulnerability{Severity: "CRITICAL"},
},
{
VulnerabilityID: "CVE-2022-7777",
Vulnerability: dbTypes.Vulnerability{Severity: "MEDIUM"},
},
},
},
}, },
} }
@@ -53,24 +106,77 @@ var (
Kind: "Deploy", Kind: "Deploy",
Name: "orion", Name: "orion",
Results: types.Results{ Results: types.Results{
{Misconfigurations: []types.DetectedMisconfiguration{ {
{ID: "ID100", Status: types.StatusFailure, Severity: "LOW"}, Misconfigurations: []types.DetectedMisconfiguration{
{ID: "ID101", Status: types.StatusFailure, Severity: "MEDIUM"}, {
{ID: "ID102", Status: types.StatusFailure, Severity: "HIGH"}, ID: "ID100",
{ID: "ID103", Status: types.StatusFailure, Severity: "CRITICAL"}, Status: types.StatusFailure,
{ID: "ID104", Status: types.StatusFailure, Severity: "UNKNOWN"}, Severity: "LOW",
{ID: "ID105", Status: types.StatusFailure, Severity: "LOW"}, },
{ID: "ID106", Status: types.StatusFailure, Severity: "HIGH"}, {
}}, ID: "ID101",
{Vulnerabilities: []types.DetectedVulnerability{ Status: types.StatusFailure,
{VulnerabilityID: "CVE-2022-1111", Vulnerability: dbTypes.Vulnerability{Severity: "LOW"}}, Severity: "MEDIUM",
{VulnerabilityID: "CVE-2022-2222", Vulnerability: dbTypes.Vulnerability{Severity: "MEDIUM"}}, },
{VulnerabilityID: "CVE-2022-3333", Vulnerability: dbTypes.Vulnerability{Severity: "HIGH"}}, {
{VulnerabilityID: "CVE-2022-4444", Vulnerability: dbTypes.Vulnerability{Severity: "CRITICAL"}}, ID: "ID102",
{VulnerabilityID: "CVE-2022-5555", Vulnerability: dbTypes.Vulnerability{Severity: "UNKNOWN"}}, Status: types.StatusFailure,
{VulnerabilityID: "CVE-2022-6666", Vulnerability: dbTypes.Vulnerability{Severity: "CRITICAL"}}, Severity: "HIGH",
{VulnerabilityID: "CVE-2022-7777", Vulnerability: dbTypes.Vulnerability{Severity: "MEDIUM"}}, },
}}, {
ID: "ID103",
Status: types.StatusFailure,
Severity: "CRITICAL",
},
{
ID: "ID104",
Status: types.StatusFailure,
Severity: "UNKNOWN",
},
{
ID: "ID105",
Status: types.StatusFailure,
Severity: "LOW",
},
{
ID: "ID106",
Status: types.StatusFailure,
Severity: "HIGH",
},
},
},
{
Vulnerabilities: []types.DetectedVulnerability{
{
VulnerabilityID: "CVE-2022-1111",
Vulnerability: dbTypes.Vulnerability{Severity: "LOW"},
},
{
VulnerabilityID: "CVE-2022-2222",
Vulnerability: dbTypes.Vulnerability{Severity: "MEDIUM"},
},
{
VulnerabilityID: "CVE-2022-3333",
Vulnerability: dbTypes.Vulnerability{Severity: "HIGH"},
},
{
VulnerabilityID: "CVE-2022-4444",
Vulnerability: dbTypes.Vulnerability{Severity: "CRITICAL"},
},
{
VulnerabilityID: "CVE-2022-5555",
Vulnerability: dbTypes.Vulnerability{Severity: "UNKNOWN"},
},
{
VulnerabilityID: "CVE-2022-6666",
Vulnerability: dbTypes.Vulnerability{Severity: "CRITICAL"},
},
{
VulnerabilityID: "CVE-2022-7777",
Vulnerability: dbTypes.Vulnerability{Severity: "MEDIUM"},
},
},
},
}, },
} }
@@ -97,9 +203,15 @@ var (
Kind: "Role", Kind: "Role",
Name: "system::leader-locking-kube-controller-manager", Name: "system::leader-locking-kube-controller-manager",
Results: types.Results{ Results: types.Results{
{Misconfigurations: []types.DetectedMisconfiguration{ {
{ID: "ID100", Status: types.StatusFailure, Severity: "MEDIUM"}, Misconfigurations: []types.DetectedMisconfiguration{
}}, {
ID: "ID100",
Status: types.StatusFailure,
Severity: "MEDIUM",
},
},
},
}, },
} }
@@ -108,10 +220,18 @@ var (
Kind: "Deploy", Kind: "Deploy",
Name: "lua", Name: "lua",
Results: types.Results{ Results: types.Results{
{Secrets: []ftypes.SecretFinding{ {
{RuleID: "secret1", Severity: "CRITICAL"}, Secrets: []ftypes.SecretFinding{
{RuleID: "secret2", Severity: "MEDIUM"}, {
}}, RuleID: "secret1",
Severity: "CRITICAL",
},
{
RuleID: "secret2",
Severity: "MEDIUM",
},
},
},
}, },
} }
@@ -120,14 +240,36 @@ var (
Kind: "Pod", Kind: "Pod",
Name: "kube-apiserver", Name: "kube-apiserver",
Results: types.Results{ Results: types.Results{
{Misconfigurations: []types.DetectedMisconfiguration{ {
{ID: "KSV-ID100", Status: types.StatusFailure, Severity: "LOW"}, Misconfigurations: []types.DetectedMisconfiguration{
{ID: "KSV-ID101", Status: types.StatusFailure, Severity: "MEDIUM"}, {
{ID: "KSV-ID102", Status: types.StatusFailure, Severity: "HIGH"}, ID: "KSV-ID100",
Status: types.StatusFailure,
Severity: "LOW",
},
{
ID: "KSV-ID101",
Status: types.StatusFailure,
Severity: "MEDIUM",
},
{
ID: "KSV-ID102",
Status: types.StatusFailure,
Severity: "HIGH",
},
{ID: "KCV-ID100", Status: types.StatusFailure, Severity: "LOW"}, {
{ID: "KCV-ID101", Status: types.StatusFailure, Severity: "MEDIUM"}, ID: "KCV-ID100",
}}, Status: types.StatusFailure,
Severity: "LOW",
},
{
ID: "KCV-ID101",
Status: types.StatusFailure,
Severity: "MEDIUM",
},
},
},
}, },
} }
) )
@@ -141,8 +283,14 @@ func TestReport_consolidate(t *testing.T) {
{ {
name: "report with both misconfigs and vulnerabilities", name: "report with both misconfigs and vulnerabilities",
report: Report{ report: Report{
Vulnerabilities: []Resource{deployOrionWithVulns, cronjobHelloWithVulns}, Vulnerabilities: []Resource{
Misconfigurations: []Resource{deployOrionWithMisconfigs, podPrometheusWithMisconfigs}, deployOrionWithVulns,
cronjobHelloWithVulns,
},
Misconfigurations: []Resource{
deployOrionWithMisconfigs,
podPrometheusWithMisconfigs,
},
}, },
expectedFindings: map[string]Resource{ expectedFindings: map[string]Resource{
"default/deploy/orion": deployOrionWithBothVulnsAndMisconfigs, "default/deploy/orion": deployOrionWithBothVulnsAndMisconfigs,
@@ -153,7 +301,10 @@ func TestReport_consolidate(t *testing.T) {
{ {
name: "report with only misconfigurations", name: "report with only misconfigurations",
report: Report{ report: Report{
Misconfigurations: []Resource{deployOrionWithMisconfigs, podPrometheusWithMisconfigs}, Misconfigurations: []Resource{
deployOrionWithMisconfigs,
podPrometheusWithMisconfigs,
},
}, },
expectedFindings: map[string]Resource{ expectedFindings: map[string]Resource{
"default/deploy/orion": deployOrionWithMisconfigs, "default/deploy/orion": deployOrionWithMisconfigs,
@@ -163,7 +314,10 @@ func TestReport_consolidate(t *testing.T) {
{ {
name: "report with only vulnerabilities", name: "report with only vulnerabilities",
report: Report{ report: Report{
Vulnerabilities: []Resource{deployOrionWithVulns, cronjobHelloWithVulns}, Vulnerabilities: []Resource{
deployOrionWithVulns,
cronjobHelloWithVulns,
},
}, },
expectedFindings: map[string]Resource{ expectedFindings: map[string]Resource{
"default/deploy/orion": deployOrionWithVulns, "default/deploy/orion": deployOrionWithVulns,
@@ -194,10 +348,22 @@ func TestResource_fullname(t *testing.T) {
expected string expected string
resource Resource resource Resource
}{ }{
{"default/deploy/orion", deployOrionWithBothVulnsAndMisconfigs}, {
{"default/deploy/orion", deployOrionWithMisconfigs}, "default/deploy/orion",
{"default/cronjob/hello", cronjobHelloWithVulns}, deployOrionWithBothVulnsAndMisconfigs,
{"default/pod/prometheus", podPrometheusWithMisconfigs}, },
{
"default/deploy/orion",
deployOrionWithMisconfigs,
},
{
"default/cronjob/hello",
cronjobHelloWithVulns,
},
{
"default/pod/prometheus",
podPrometheusWithMisconfigs,
},
} }
for _, tt := range tests { for _, tt := range tests {
@@ -216,22 +382,34 @@ func TestResourceFailed(t *testing.T) {
{ {
name: "report with both misconfigs and vulnerabilities", name: "report with both misconfigs and vulnerabilities",
report: Report{ report: Report{
Vulnerabilities: []Resource{deployOrionWithVulns, cronjobHelloWithVulns}, Vulnerabilities: []Resource{
Misconfigurations: []Resource{deployOrionWithMisconfigs, podPrometheusWithMisconfigs}, deployOrionWithVulns,
cronjobHelloWithVulns,
},
Misconfigurations: []Resource{
deployOrionWithMisconfigs,
podPrometheusWithMisconfigs,
},
}, },
expected: true, expected: true,
}, },
{ {
name: "report with only misconfigurations", name: "report with only misconfigurations",
report: Report{ report: Report{
Misconfigurations: []Resource{deployOrionWithMisconfigs, podPrometheusWithMisconfigs}, Misconfigurations: []Resource{
deployOrionWithMisconfigs,
podPrometheusWithMisconfigs,
},
}, },
expected: true, expected: true,
}, },
{ {
name: "report with only vulnerabilities", name: "report with only vulnerabilities",
report: Report{ report: Report{
Vulnerabilities: []Resource{deployOrionWithVulns, cronjobHelloWithVulns}, Vulnerabilities: []Resource{
deployOrionWithVulns,
cronjobHelloWithVulns,
},
}, },
expected: true, expected: true,
}, },
@@ -285,66 +463,101 @@ func Test_rbacResource(t *testing.T) {
} }
func Test_separateMisconfigReports(t *testing.T) { func Test_separateMisconfigReports(t *testing.T) {
k8sReport := Report{Misconfigurations: []Resource{ k8sReport := Report{
{Kind: "Role"}, Misconfigurations: []Resource{
{Kind: "Deployment"}, {Kind: "Role"},
{Kind: "StatefulSet"}, {Kind: "Deployment"},
{Kind: "Pod", Namespace: "kube-system", Results: []types.Result{ {Kind: "StatefulSet"},
{Misconfigurations: []types.DetectedMisconfiguration{{ID: "KCV-0001"}}}, {
{Misconfigurations: []types.DetectedMisconfiguration{{ID: "KSV-0001"}}}, Kind: "Pod",
}}, Namespace: "kube-system",
}} Results: []types.Result{
{Misconfigurations: []types.DetectedMisconfiguration{{ID: "KCV-0001"}}},
{Misconfigurations: []types.DetectedMisconfiguration{{ID: "KSV-0001"}}},
},
},
},
}
tests := []struct { tests := []struct {
name string name string
k8sReport Report k8sReport Report
securityChecks []string scanners []string
components []string components []string
expectedReports []Report expectedReports []Report
}{ }{
{ {
name: "Config, Rbac, and Infra Reports", name: "Config, Rbac, and Infra Reports",
k8sReport: k8sReport, k8sReport: k8sReport,
securityChecks: []string{types.SecurityCheckConfig, types.SecurityCheckRbac}, scanners: []string{
components: []string{workloadComponent, infraComponent}, types.MisconfigScanner,
expectedReports: []Report{ // the order matter for the test types.RBACScanner,
{Misconfigurations: []Resource{{Kind: "Deployment"}, {Kind: "StatefulSet"}, {Kind: "Pod"}}}, },
components: []string{
workloadComponent,
infraComponent,
},
expectedReports: []Report{
// the order matter for the test
{
Misconfigurations: []Resource{
{Kind: "Deployment"},
{Kind: "StatefulSet"},
{Kind: "Pod"},
},
},
{Misconfigurations: []Resource{{Kind: "Role"}}}, {Misconfigurations: []Resource{{Kind: "Role"}}},
{Misconfigurations: []Resource{{Kind: "Pod"}}}, {Misconfigurations: []Resource{{Kind: "Pod"}}},
}, },
}, },
{ {
name: "Config and Infra for the same resource", name: "Config and Infra for the same resource",
k8sReport: k8sReport, k8sReport: k8sReport,
securityChecks: []string{types.SecurityCheckConfig}, scanners: []string{types.MisconfigScanner},
components: []string{workloadComponent, infraComponent}, components: []string{
expectedReports: []Report{ // the order matter for the test workloadComponent,
{Misconfigurations: []Resource{{Kind: "Deployment"}, {Kind: "StatefulSet"}, {Kind: "Pod"}}}, infraComponent,
},
expectedReports: []Report{
// the order matter for the test
{
Misconfigurations: []Resource{
{Kind: "Deployment"},
{Kind: "StatefulSet"},
{Kind: "Pod"},
},
},
{Misconfigurations: []Resource{{Kind: "Pod"}}}, {Misconfigurations: []Resource{{Kind: "Pod"}}},
}, },
}, },
{ {
name: "Role Report Only", name: "Role Report Only",
k8sReport: k8sReport, k8sReport: k8sReport,
securityChecks: []string{types.SecurityCheckRbac}, scanners: []string{types.RBACScanner},
expectedReports: []Report{ expectedReports: []Report{
{Misconfigurations: []Resource{{Kind: "Role"}}}, {Misconfigurations: []Resource{{Kind: "Role"}}},
}, },
}, },
{ {
name: "Config Report Only", name: "Config Report Only",
k8sReport: k8sReport, k8sReport: k8sReport,
securityChecks: []string{types.SecurityCheckConfig}, scanners: []string{types.MisconfigScanner},
components: []string{workloadComponent}, components: []string{workloadComponent},
expectedReports: []Report{ expectedReports: []Report{
{Misconfigurations: []Resource{{Kind: "Deployment"}, {Kind: "StatefulSet"}, {Kind: "Pod"}}}, {
Misconfigurations: []Resource{
{Kind: "Deployment"},
{Kind: "StatefulSet"},
{Kind: "Pod"},
},
},
}, },
}, },
{ {
name: "Infra Report Only", name: "Infra Report Only",
k8sReport: k8sReport, k8sReport: k8sReport,
securityChecks: []string{types.SecurityCheckConfig}, scanners: []string{types.MisconfigScanner},
components: []string{infraComponent}, components: []string{infraComponent},
expectedReports: []Report{ expectedReports: []Report{
{Misconfigurations: []Resource{{Kind: "Pod"}}}, {Misconfigurations: []Resource{{Kind: "Pod"}}},
}, },
@@ -355,7 +568,7 @@ func Test_separateMisconfigReports(t *testing.T) {
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
reports := separateMisconfigReports(tt.k8sReport, tt.securityChecks, tt.components) reports := separateMisconfigReports(tt.k8sReport, tt.scanners, tt.components)
assert.Equal(t, len(tt.expectedReports), len(reports)) assert.Equal(t, len(tt.expectedReports), len(reports))
for i := range reports { for i := range reports {
@@ -381,7 +594,7 @@ func TestReportWrite_Summary(t *testing.T) {
name string name string
report Report report Report
opt Option opt Option
securityChecks []string scanners []string
components []string components []string
severities []dbTypes.Severity severities []dbTypes.Severity
expectedOutput string expectedOutput string
@@ -392,9 +605,9 @@ func TestReportWrite_Summary(t *testing.T) {
ClusterName: "test", ClusterName: "test",
Misconfigurations: []Resource{deployOrionWithMisconfigs}, Misconfigurations: []Resource{deployOrionWithMisconfigs},
}, },
securityChecks: []string{types.SecurityCheckConfig}, scanners: []string{types.MisconfigScanner},
components: []string{workloadComponent}, components: []string{workloadComponent},
severities: allSeverities, severities: allSeverities,
expectedOutput: `Summary Report for test expectedOutput: `Summary Report for test
======================= =======================
@@ -414,8 +627,8 @@ Severities: C=CRITICAL H=HIGH M=MEDIUM L=LOW U=UNKNOWN`,
ClusterName: "test", ClusterName: "test",
Vulnerabilities: []Resource{deployOrionWithVulns}, Vulnerabilities: []Resource{deployOrionWithVulns},
}, },
securityChecks: []string{types.SecurityCheckVulnerability}, scanners: []string{types.VulnerabilityScanner},
severities: allSeverities, severities: allSeverities,
expectedOutput: `Summary Report for test expectedOutput: `Summary Report for test
======================= =======================
@@ -435,8 +648,8 @@ Severities: C=CRITICAL H=HIGH M=MEDIUM L=LOW U=UNKNOWN`,
ClusterName: "test", ClusterName: "test",
Misconfigurations: []Resource{roleWithMisconfig}, Misconfigurations: []Resource{roleWithMisconfig},
}, },
securityChecks: []string{types.SecurityCheckRbac}, scanners: []string{types.RBACScanner},
severities: allSeverities, severities: allSeverities,
expectedOutput: `Summary Report for test expectedOutput: `Summary Report for test
======================= =======================
@@ -456,8 +669,8 @@ Severities: C=CRITICAL H=HIGH M=MEDIUM L=LOW U=UNKNOWN`,
ClusterName: "test", ClusterName: "test",
Vulnerabilities: []Resource{deployLuaWithSecrets}, Vulnerabilities: []Resource{deployLuaWithSecrets},
}, },
securityChecks: []string{types.SecurityCheckSecret}, scanners: []string{types.SecretScanner},
severities: allSeverities, severities: allSeverities,
expectedOutput: `Summary Report for test expectedOutput: `Summary Report for test
======================= =======================
@@ -477,9 +690,9 @@ Severities: C=CRITICAL H=HIGH M=MEDIUM L=LOW U=UNKNOWN`,
ClusterName: "test", ClusterName: "test",
Misconfigurations: []Resource{apiseverPodWithMisconfigAndInfra}, Misconfigurations: []Resource{apiseverPodWithMisconfigAndInfra},
}, },
securityChecks: []string{types.SecurityCheckConfig}, scanners: []string{types.MisconfigScanner},
components: []string{infraComponent}, components: []string{infraComponent},
severities: allSeverities, severities: allSeverities,
expectedOutput: `Summary Report for test expectedOutput: `Summary Report for test
======================= =======================
@@ -499,9 +712,13 @@ Severities: C=CRITICAL H=HIGH M=MEDIUM L=LOW U=UNKNOWN`,
ClusterName: "test", ClusterName: "test",
Misconfigurations: []Resource{apiseverPodWithMisconfigAndInfra}, Misconfigurations: []Resource{apiseverPodWithMisconfigAndInfra},
}, },
securityChecks: []string{types.SecurityCheckVulnerability, types.SecurityCheckConfig, types.SecurityCheckSecret}, scanners: []string{
components: []string{workloadComponent}, types.VulnerabilityScanner,
severities: allSeverities, types.MisconfigScanner,
types.SecretScanner,
},
components: []string{workloadComponent},
severities: allSeverities,
expectedOutput: `Summary Report for test expectedOutput: `Summary Report for test
======================= =======================
@@ -516,14 +733,21 @@ Workload Assessment
Severities: C=CRITICAL H=HIGH M=MEDIUM L=LOW U=UNKNOWN`, Severities: C=CRITICAL H=HIGH M=MEDIUM L=LOW U=UNKNOWN`,
}, },
{ {
name: "apiserver, all security-checks and serverities", name: "apiserver, all scanners and serverities",
report: Report{ report: Report{
ClusterName: "test", ClusterName: "test",
Misconfigurations: []Resource{apiseverPodWithMisconfigAndInfra}, Misconfigurations: []Resource{apiseverPodWithMisconfigAndInfra},
}, },
securityChecks: []string{types.SecurityCheckConfig, types.SecurityCheckVulnerability, scanners: []string{
types.SecurityCheckRbac, types.SecurityCheckSecret}, types.MisconfigScanner,
components: []string{workloadComponent, infraComponent}, types.VulnerabilityScanner,
types.RBACScanner,
types.SecretScanner,
},
components: []string{
workloadComponent,
infraComponent,
},
severities: allSeverities, severities: allSeverities,
expectedOutput: `Summary Report for test expectedOutput: `Summary Report for test
======================= =======================
@@ -556,12 +780,12 @@ Severities: C=CRITICAL H=HIGH M=MEDIUM L=LOW U=UNKNOWN`,
output := bytes.Buffer{} output := bytes.Buffer{}
opt := Option{ opt := Option{
Format: "table", Format: "table",
Report: "summary", Report: "summary",
Output: &output, Output: &output,
SecurityChecks: tc.securityChecks, Scanners: tc.scanners,
Severities: tc.severities, Severities: tc.severities,
Components: tc.components, Components: tc.components,
} }
Write(tc.report, opt) Write(tc.report, opt)

View File

@@ -35,24 +35,27 @@ func NewSummaryWriter(output io.Writer, requiredSevs []dbTypes.Severity, columnH
} }
} }
func ColumnHeading(securityChecks, components, availableColumns []string) []string { func ColumnHeading(scanners, components, availableColumns []string) []string {
columns := []string{NamespaceColumn, ResourceColumn} columns := []string{
NamespaceColumn,
ResourceColumn,
}
securityOptions := make(map[string]interface{}, 0) securityOptions := make(map[string]interface{}, 0)
//maintain column order (vuln,config,secret) //maintain column order (vuln,config,secret)
for _, check := range securityChecks { for _, check := range scanners {
switch check { switch check {
case types.SecurityCheckVulnerability: case types.VulnerabilityScanner:
securityOptions[VulnerabilitiesColumn] = nil securityOptions[VulnerabilitiesColumn] = nil
case types.SecurityCheckConfig: case types.MisconfigScanner:
if slices.Contains(components, workloadComponent) { if slices.Contains(components, workloadComponent) {
securityOptions[MisconfigurationsColumn] = nil securityOptions[MisconfigurationsColumn] = nil
} }
if slices.Contains(components, infraComponent) { if slices.Contains(components, infraComponent) {
securityOptions[InfraAssessmentColumn] = nil securityOptions[InfraAssessmentColumn] = nil
} }
case types.SecurityCheckSecret: case types.SecretScanner:
securityOptions[SecretsColumn] = nil securityOptions[SecretsColumn] = nil
case types.SecurityCheckRbac: case types.RBACScanner:
securityOptions[RbacAssessmentColumn] = nil securityOptions[RbacAssessmentColumn] = nil
} }
} }
@@ -94,7 +97,10 @@ func (s SummaryWriter) Write(report Report) error {
} }
vCount, mCount, sCount := accumulateSeverityCounts(finding) vCount, mCount, sCount := accumulateSeverityCounts(finding)
name := fmt.Sprintf("%s/%s", finding.Kind, finding.Name) name := fmt.Sprintf("%s/%s", finding.Kind, finding.Name)
rowParts := []string{finding.Namespace, name} rowParts := []string{
finding.Namespace,
name,
}
if slices.Contains(s.ColumnsHeading, VulnerabilitiesColumn) { if slices.Contains(s.ColumnsHeading, VulnerabilitiesColumn) {
rowParts = append(rowParts, s.generateSummary(vCount)...) rowParts = append(rowParts, s.generateSummary(vCount)...)
@@ -140,9 +146,13 @@ func (s SummaryWriter) generateSummary(sevCount map[string]int) []string {
} }
func getRequiredSeverities(requiredSevs []dbTypes.Severity) ([]string, []string) { func getRequiredSeverities(requiredSevs []dbTypes.Severity) ([]string, []string) {
requiredSevOrder := []dbTypes.Severity{dbTypes.SeverityCritical, requiredSevOrder := []dbTypes.Severity{
dbTypes.SeverityHigh, dbTypes.SeverityMedium, dbTypes.SeverityCritical,
dbTypes.SeverityLow, dbTypes.SeverityUnknown} dbTypes.SeverityHigh,
dbTypes.SeverityMedium,
dbTypes.SeverityLow,
dbTypes.SeverityUnknown,
}
var severities []string var severities []string
var severityHeadings []string var severityHeadings []string
for _, sev := range requiredSevOrder { for _, sev := range requiredSevOrder {
@@ -178,11 +188,20 @@ func accumulateSeverityCounts(finding Resource) (map[string]int, map[string]int,
func configureHeader(s SummaryWriter, t *table.Table, columnHeading []string) { func configureHeader(s SummaryWriter, t *table.Table, columnHeading []string) {
sevCount := len(s.Severities) sevCount := len(s.Severities)
if len(columnHeading) > 2 { if len(columnHeading) > 2 {
headerRow := []string{columnHeading[0], columnHeading[1]} headerRow := []string{
columnHeading[0],
columnHeading[1],
}
// vulnerabilities headings // vulnerabilities headings
count := len(columnHeading) - len(headerRow) count := len(columnHeading) - len(headerRow)
colSpan := []int{1, 1} colSpan := []int{
headerAlignment := []table.Alignment{table.AlignLeft, table.AlignLeft} 1,
1,
}
headerAlignment := []table.Alignment{
table.AlignLeft,
table.AlignLeft,
}
for i := 0; i < count; i++ { for i := 0; i < count; i++ {
headerRow = append(headerRow, s.SeverityHeadings...) headerRow = append(headerRow, s.SeverityHeadings...)
colSpan = append(colSpan, sevCount) colSpan = append(colSpan, sevCount)

View File

@@ -10,67 +10,102 @@ import (
) )
func TestReport_ColumnHeading(t *testing.T) { func TestReport_ColumnHeading(t *testing.T) {
allSecurityChecks := []string{ allScanners := []string{
types.SecurityCheckVulnerability, types.VulnerabilityScanner,
types.SecurityCheckConfig, types.MisconfigScanner,
types.SecurityCheckSecret, types.SecretScanner,
types.SecurityCheckRbac, types.RBACScanner,
} }
tests := []struct { tests := []struct {
name string name string
securityChecks []string scanners []string
components []string components []string
availableColumns []string availableColumns []string
want []string want []string
}{ }{
{ {
name: "filter workload columns", name: "filter workload columns",
securityChecks: allSecurityChecks, scanners: allScanners,
availableColumns: WorkloadColumns(), availableColumns: WorkloadColumns(),
components: []string{workloadComponent, infraComponent}, components: []string{
want: []string{NamespaceColumn, ResourceColumn, VulnerabilitiesColumn, MisconfigurationsColumn, SecretsColumn}, workloadComponent,
infraComponent,
},
want: []string{
NamespaceColumn,
ResourceColumn,
VulnerabilitiesColumn,
MisconfigurationsColumn,
SecretsColumn,
},
}, },
{ {
name: "filter rbac columns", name: "filter rbac columns",
securityChecks: allSecurityChecks, scanners: allScanners,
components: []string{}, components: []string{},
availableColumns: RoleColumns(), availableColumns: RoleColumns(),
want: []string{NamespaceColumn, ResourceColumn, RbacAssessmentColumn}, want: []string{
NamespaceColumn,
ResourceColumn,
RbacAssessmentColumn,
},
}, },
{ {
name: "filter infra columns", name: "filter infra columns",
securityChecks: allSecurityChecks, scanners: allScanners,
components: []string{workloadComponent, infraComponent}, components: []string{
workloadComponent,
infraComponent,
},
availableColumns: InfraColumns(), availableColumns: InfraColumns(),
want: []string{NamespaceColumn, ResourceColumn, InfraAssessmentColumn}, want: []string{
NamespaceColumn,
ResourceColumn,
InfraAssessmentColumn,
},
}, },
{ {
name: "config column only", name: "config column only",
securityChecks: []string{types.SecurityCheckConfig}, scanners: []string{types.MisconfigScanner},
components: []string{workloadComponent, infraComponent}, components: []string{
workloadComponent,
infraComponent,
},
availableColumns: WorkloadColumns(), availableColumns: WorkloadColumns(),
want: []string{NamespaceColumn, ResourceColumn, MisconfigurationsColumn}, want: []string{
NamespaceColumn,
ResourceColumn,
MisconfigurationsColumn,
},
}, },
{ {
name: "secret column only", name: "secret column only",
securityChecks: []string{types.SecurityCheckSecret}, scanners: []string{types.SecretScanner},
components: []string{}, components: []string{},
availableColumns: WorkloadColumns(), availableColumns: WorkloadColumns(),
want: []string{NamespaceColumn, ResourceColumn, SecretsColumn}, want: []string{
NamespaceColumn,
ResourceColumn,
SecretsColumn,
},
}, },
{ {
name: "vuln column only", name: "vuln column only",
securityChecks: []string{types.SecurityCheckVulnerability}, scanners: []string{types.VulnerabilityScanner},
components: []string{}, components: []string{},
availableColumns: WorkloadColumns(), availableColumns: WorkloadColumns(),
want: []string{NamespaceColumn, ResourceColumn, VulnerabilitiesColumn}, want: []string{
NamespaceColumn,
ResourceColumn,
VulnerabilitiesColumn,
},
}, },
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
column := ColumnHeading(tt.securityChecks, tt.components, tt.availableColumns) column := ColumnHeading(tt.scanners, tt.components, tt.availableColumns)
if !assert.Equal(t, column, tt.want) { if !assert.Equal(t, column, tt.want) {
t.Error(fmt.Errorf("TestReport_ColumnHeading want %v got %v", tt.want, column)) t.Error(fmt.Errorf("TestReport_ColumnHeading want %v got %v", tt.want, column))
} }

View File

@@ -24,7 +24,11 @@ type Scanner struct {
} }
func NewScanner(cluster string, runner cmd.Runner, opts flag.Options) *Scanner { func NewScanner(cluster string, runner cmd.Runner, opts flag.Options) *Scanner {
return &Scanner{cluster, runner, opts} return &Scanner{
cluster,
runner,
opts,
}
} }
func (s *Scanner) Scan(ctx context.Context, artifacts []*artifacts.Artifact) (report.Report, error) { func (s *Scanner) Scan(ctx context.Context, artifacts []*artifacts.Artifact) (report.Report, error) {
@@ -59,7 +63,7 @@ func (s *Scanner) Scan(ctx context.Context, artifacts []*artifacts.Artifact) (re
for _, artifact := range artifacts { for _, artifact := range artifacts {
bar.Increment() bar.Increment()
if shouldScanVulnsOrSecrets(s.opts.SecurityChecks) { if shouldScanVulnsOrSecrets(s.opts.Scanners) {
resources, err := s.scanVulns(ctx, artifact) resources, err := s.scanVulns(ctx, artifact)
if err != nil { if err != nil {
return report.Report{}, xerrors.Errorf("scanning vulnerabilities error: %w", err) return report.Report{}, xerrors.Errorf("scanning vulnerabilities error: %w", err)
@@ -67,7 +71,7 @@ func (s *Scanner) Scan(ctx context.Context, artifacts []*artifacts.Artifact) (re
vulns = append(vulns, resources...) vulns = append(vulns, resources...)
} }
if local.ShouldScanMisconfigOrRbac(s.opts.SecurityChecks) { if local.ShouldScanMisconfigOrRbac(s.opts.Scanners) {
resource, err := s.scanMisconfigs(ctx, artifact) resource, err := s.scanMisconfigs(ctx, artifact)
if err != nil { if err != nil {
return report.Report{}, xerrors.Errorf("scanning misconfigurations error: %w", err) return report.Report{}, xerrors.Errorf("scanning misconfigurations error: %w", err)
@@ -137,7 +141,7 @@ func (s *Scanner) filter(ctx context.Context, r types.Report, artifact *artifact
return report.CreateResource(artifact, r, nil), nil return report.CreateResource(artifact, r, nil), nil
} }
func shouldScanVulnsOrSecrets(securityChecks []string) bool { func shouldScanVulnsOrSecrets(scanners []string) bool {
return slices.Contains(securityChecks, types.SecurityCheckVulnerability) || return slices.Contains(scanners, types.VulnerabilityScanner) ||
slices.Contains(securityChecks, types.SecurityCheckSecret) slices.Contains(scanners, types.SecretScanner)
} }

View File

@@ -57,7 +57,10 @@ func NewScanner(scannerOptions ScannerOption, opts ...Option) Scanner {
opt(o) opt(o)
} }
return Scanner{customHeaders: scannerOptions.CustomHeaders, client: o.rpcClient} return Scanner{
customHeaders: scannerOptions.CustomHeaders,
client: o.rpcClient,
}
} }
// Scan scans the image // Scan scans the image
@@ -79,7 +82,7 @@ func (s Scanner) Scan(ctx context.Context, target, artifactKey string, blobKeys
BlobIds: blobKeys, BlobIds: blobKeys,
Options: &rpc.ScanOptions{ Options: &rpc.ScanOptions{
VulnType: opts.VulnType, VulnType: opts.VulnType,
SecurityChecks: opts.SecurityChecks, Scanners: opts.Scanners,
ListAllPackages: opts.ListAllPackages, ListAllPackages: opts.ListAllPackages,
LicenseCategories: licenseCategories, LicenseCategories: licenseCategories,
}, },

View File

@@ -44,7 +44,7 @@ func teeError(err error) error {
func (s *ScanServer) Scan(ctx context.Context, in *rpcScanner.ScanRequest) (*rpcScanner.ScanResponse, error) { func (s *ScanServer) Scan(ctx context.Context, in *rpcScanner.ScanRequest) (*rpcScanner.ScanResponse, error) {
options := types.ScanOptions{ options := types.ScanOptions{
VulnType: in.Options.VulnType, VulnType: in.Options.VulnType,
SecurityChecks: in.Options.SecurityChecks, Scanners: in.Options.Scanners,
ListAllPackages: in.Options.ListAllPackages, ListAllPackages: in.Options.ListAllPackages,
} }
results, os, err := s.localScanner.Scan(ctx, in.Target, in.ArtifactId, in.BlobIds, options) results, os, err := s.localScanner.Scan(ctx, in.Target, in.ArtifactId, in.BlobIds, options)
@@ -95,7 +95,10 @@ func (s *CacheServer) MissingBlobs(_ context.Context, in *rpcCache.MissingBlobsR
if err != nil { if err != nil {
return nil, teeError(xerrors.Errorf("failed to get missing blobs: %w", err)) return nil, teeError(xerrors.Errorf("failed to get missing blobs: %w", err))
} }
return &rpcCache.MissingBlobsResponse{MissingArtifact: missingArtifact, MissingBlobIds: blobIDs}, nil return &rpcCache.MissingBlobsResponse{
MissingArtifact: missingArtifact,
MissingBlobIds: blobIDs,
}, nil
} }
// DeleteBlobs removes blobs by IDs // DeleteBlobs removes blobs by IDs

View File

@@ -114,7 +114,7 @@ func (s Scanner) Scan(ctx context.Context, target, artifactKey string, blobKeys
} }
// Scan packages for vulnerabilities // Scan packages for vulnerabilities
if slices.Contains(options.SecurityChecks, types.SecurityCheckVulnerability) { if slices.Contains(options.Scanners, types.VulnerabilityScanner) {
var vulnResults types.Results var vulnResults types.Results
vulnResults, eosl, err = s.scanVulnerabilities(target, artifactDetail, options) vulnResults, eosl, err = s.scanVulnerabilities(target, artifactDetail, options)
if err != nil { if err != nil {
@@ -132,19 +132,19 @@ func (s Scanner) Scan(ctx context.Context, target, artifactKey string, blobKeys
} }
// Scan IaC config files // Scan IaC config files
if ShouldScanMisconfigOrRbac(options.SecurityChecks) { if ShouldScanMisconfigOrRbac(options.Scanners) {
configResults := s.MisconfsToResults(artifactDetail.Misconfigurations) configResults := s.MisconfsToResults(artifactDetail.Misconfigurations)
results = append(results, configResults...) results = append(results, configResults...)
} }
// Scan secrets // Scan secrets
if slices.Contains(options.SecurityChecks, types.SecurityCheckSecret) { if slices.Contains(options.Scanners, types.SecretScanner) {
secretResults := s.secretsToResults(artifactDetail.Secrets) secretResults := s.secretsToResults(artifactDetail.Secrets)
results = append(results, secretResults...) results = append(results, secretResults...)
} }
// Scan licenses // Scan licenses
if slices.Contains(options.SecurityChecks, types.SecurityCheckLicense) { if slices.Contains(options.Scanners, types.LicenseScanner) {
licenseResults := s.scanLicenses(artifactDetail, options.LicenseCategories) licenseResults := s.scanLicenses(artifactDetail, options.LicenseCategories)
results = append(results, licenseResults...) results = append(results, licenseResults...)
} }
@@ -538,7 +538,7 @@ func mergePkgs(pkgs, pkgsFromCommands []ftypes.Package) []ftypes.Package {
return pkgs return pkgs
} }
func ShouldScanMisconfigOrRbac(securityChecks []string) bool { func ShouldScanMisconfigOrRbac(scanners []string) bool {
return slices.Contains(securityChecks, types.SecurityCheckConfig) || return slices.Contains(scanners, types.MisconfigScanner) ||
slices.Contains(securityChecks, types.SecurityCheckRbac) slices.Contains(scanners, types.RBACScanner)
} }

View File

@@ -42,8 +42,11 @@ func TestScanner_Scan(t *testing.T) {
target: "alpine:latest", target: "alpine:latest",
layerIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"}, layerIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"},
options: types.ScanOptions{ options: types.ScanOptions{
VulnType: []string{types.VulnTypeOS, types.VulnTypeLibrary}, VulnType: []string{
SecurityChecks: []string{types.SecurityCheckVulnerability}, types.VulnTypeOS,
types.VulnTypeLibrary,
},
Scanners: []string{types.VulnerabilityScanner},
}, },
}, },
fixtures: []string{"testdata/fixtures/happy.yaml"}, fixtures: []string{"testdata/fixtures/happy.yaml"},
@@ -149,8 +152,11 @@ func TestScanner_Scan(t *testing.T) {
target: "alpine:latest", target: "alpine:latest",
layerIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"}, layerIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"},
options: types.ScanOptions{ options: types.ScanOptions{
VulnType: []string{types.VulnTypeOS, types.VulnTypeLibrary}, VulnType: []string{
SecurityChecks: []string{types.SecurityCheckVulnerability}, types.VulnTypeOS,
types.VulnTypeLibrary,
},
Scanners: []string{types.VulnerabilityScanner},
ListAllPackages: true, ListAllPackages: true,
}, },
}, },
@@ -297,8 +303,11 @@ func TestScanner_Scan(t *testing.T) {
target: "alpine:latest", target: "alpine:latest",
layerIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"}, layerIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"},
options: types.ScanOptions{ options: types.ScanOptions{
VulnType: []string{types.VulnTypeOS, types.VulnTypeLibrary}, VulnType: []string{
SecurityChecks: []string{types.SecurityCheckVulnerability}, types.VulnTypeOS,
types.VulnTypeLibrary,
},
Scanners: []string{types.VulnerabilityScanner},
ListAllPackages: true, ListAllPackages: true,
}, },
}, },
@@ -403,8 +412,11 @@ func TestScanner_Scan(t *testing.T) {
target: "alpine:latest", target: "alpine:latest",
layerIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"}, layerIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"},
options: types.ScanOptions{ options: types.ScanOptions{
VulnType: []string{types.VulnTypeOS, types.VulnTypeLibrary}, VulnType: []string{
SecurityChecks: []string{types.SecurityCheckVulnerability}, types.VulnTypeOS,
types.VulnTypeLibrary,
},
Scanners: []string{types.VulnerabilityScanner},
}, },
}, },
fixtures: []string{"testdata/fixtures/happy.yaml"}, fixtures: []string{"testdata/fixtures/happy.yaml"},
@@ -483,8 +495,11 @@ func TestScanner_Scan(t *testing.T) {
target: "alpine:latest", target: "alpine:latest",
layerIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"}, layerIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"},
options: types.ScanOptions{ options: types.ScanOptions{
VulnType: []string{types.VulnTypeOS, types.VulnTypeLibrary}, VulnType: []string{
SecurityChecks: []string{types.SecurityCheckVulnerability}, types.VulnTypeOS,
types.VulnTypeLibrary,
},
Scanners: []string{types.VulnerabilityScanner},
}, },
}, },
fixtures: []string{"testdata/fixtures/happy.yaml"}, fixtures: []string{"testdata/fixtures/happy.yaml"},
@@ -563,8 +578,11 @@ func TestScanner_Scan(t *testing.T) {
target: "fedora:27", target: "fedora:27",
layerIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"}, layerIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"},
options: types.ScanOptions{ options: types.ScanOptions{
VulnType: []string{types.VulnTypeOS, types.VulnTypeLibrary}, VulnType: []string{
SecurityChecks: []string{types.SecurityCheckVulnerability}, types.VulnTypeOS,
types.VulnTypeLibrary,
},
Scanners: []string{types.VulnerabilityScanner},
}, },
}, },
fixtures: []string{"testdata/fixtures/happy.yaml"}, fixtures: []string{"testdata/fixtures/happy.yaml"},
@@ -636,8 +654,11 @@ func TestScanner_Scan(t *testing.T) {
target: "busybox:latest", target: "busybox:latest",
layerIDs: []string{"sha256:a6d503001157aedc826853f9b67f26d35966221b158bff03849868ae4a821116"}, layerIDs: []string{"sha256:a6d503001157aedc826853f9b67f26d35966221b158bff03849868ae4a821116"},
options: types.ScanOptions{ options: types.ScanOptions{
VulnType: []string{types.VulnTypeOS, types.VulnTypeLibrary}, VulnType: []string{
SecurityChecks: []string{types.SecurityCheckVulnerability}, types.VulnTypeOS,
types.VulnTypeLibrary,
},
Scanners: []string{types.VulnerabilityScanner},
}, },
}, },
fixtures: []string{"testdata/fixtures/happy.yaml"}, fixtures: []string{"testdata/fixtures/happy.yaml"},
@@ -657,8 +678,8 @@ func TestScanner_Scan(t *testing.T) {
target: "alpine:latest", target: "alpine:latest",
layerIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"}, layerIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"},
options: types.ScanOptions{ options: types.ScanOptions{
VulnType: []string{types.VulnTypeLibrary}, VulnType: []string{types.VulnTypeLibrary},
SecurityChecks: []string{types.SecurityCheckVulnerability}, Scanners: []string{types.VulnerabilityScanner},
}, },
}, },
fixtures: []string{"testdata/fixtures/happy.yaml"}, fixtures: []string{"testdata/fixtures/happy.yaml"},
@@ -767,7 +788,7 @@ func TestScanner_Scan(t *testing.T) {
target: "/app/configs", target: "/app/configs",
layerIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"}, layerIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"},
options: types.ScanOptions{ options: types.ScanOptions{
SecurityChecks: []string{types.SecurityCheckConfig}, Scanners: []string{types.MisconfigScanner},
}, },
}, },
fixtures: []string{"testdata/fixtures/happy.yaml"}, fixtures: []string{"testdata/fixtures/happy.yaml"},
@@ -916,8 +937,11 @@ func TestScanner_Scan(t *testing.T) {
target: "alpine:latest", target: "alpine:latest",
layerIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"}, layerIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"},
options: types.ScanOptions{ options: types.ScanOptions{
VulnType: []string{types.VulnTypeOS, types.VulnTypeLibrary}, VulnType: []string{
SecurityChecks: []string{types.SecurityCheckVulnerability}, types.VulnTypeOS,
types.VulnTypeLibrary,
},
Scanners: []string{types.VulnerabilityScanner},
}, },
}, },
fixtures: []string{"testdata/fixtures/happy.yaml"}, fixtures: []string{"testdata/fixtures/happy.yaml"},
@@ -937,8 +961,8 @@ func TestScanner_Scan(t *testing.T) {
target: "alpine:latest", target: "alpine:latest",
layerIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"}, layerIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"},
options: types.ScanOptions{ options: types.ScanOptions{
VulnType: []string{types.VulnTypeLibrary}, VulnType: []string{types.VulnTypeLibrary},
SecurityChecks: []string{types.SecurityCheckVulnerability}, Scanners: []string{types.VulnerabilityScanner},
}, },
}, },
fixtures: []string{"testdata/fixtures/sad.yaml"}, fixtures: []string{"testdata/fixtures/sad.yaml"},

View File

@@ -7,7 +7,7 @@ import (
// ScanOptions holds the attributes for scanning vulnerabilities // ScanOptions holds the attributes for scanning vulnerabilities
type ScanOptions struct { type ScanOptions struct {
VulnType []string VulnType []string
SecurityChecks []string Scanners []string
ScanRemovedPackages bool ScanRemovedPackages bool
Platform string Platform string
ListAllPackages bool ListAllPackages bool

View File

@@ -3,8 +3,8 @@ package types
// VulnType represents vulnerability type // VulnType represents vulnerability type
type VulnType = string type VulnType = string
// SecurityCheck represents the type of security check // Scanner represents the type of security scanning
type SecurityCheck = string type Scanner = string
const ( const (
// VulnTypeUnknown is a vulnerability type of unknown // VulnTypeUnknown is a vulnerability type of unknown
@@ -16,29 +16,35 @@ const (
// VulnTypeLibrary is a vulnerability type of programming language dependencies // VulnTypeLibrary is a vulnerability type of programming language dependencies
VulnTypeLibrary = VulnType("library") VulnTypeLibrary = VulnType("library")
// SecurityCheckUnknown is a security check of unknown // ScannerUnknown is the scanner of unknown
SecurityCheckUnknown = SecurityCheck("unknown") ScannerUnknown = Scanner("unknown")
// SecurityCheckVulnerability is a security check of vulnerabilities // VulnerabilityScanner is the scanner of vulnerabilities
SecurityCheckVulnerability = SecurityCheck("vuln") VulnerabilityScanner = Scanner("vuln")
// SecurityCheckConfig is a security check of misconfigurations // MisconfigScanner is the scanner of misconfigurations
SecurityCheckConfig = SecurityCheck("config") MisconfigScanner = Scanner("config")
// SecurityCheckSecret is a security check of secrets // SecretScanner is the scanner of secrets
SecurityCheckSecret = SecurityCheck("secret") SecretScanner = Scanner("secret")
// SecurityCheckRbac is a security check of rbac assessment // RBACScanner is the scanner of rbac assessment
SecurityCheckRbac = SecurityCheck("rbac") RBACScanner = Scanner("rbac")
// SecurityCheckLicense is the security check of licenses // LicenseScanner is the scanner of licenses
SecurityCheckLicense = SecurityCheck("license") LicenseScanner = Scanner("license")
) )
var ( var (
VulnTypes = []string{VulnTypeOS, VulnTypeLibrary} VulnTypes = []string{
SecurityChecks = []string{ VulnTypeOS,
SecurityCheckVulnerability, SecurityCheckConfig, SecurityCheckRbac, VulnTypeLibrary,
SecurityCheckSecret, SecurityCheckLicense, }
Scanners = []string{
VulnerabilityScanner,
MisconfigScanner,
RBACScanner,
SecretScanner,
LicenseScanner,
} }
) )

View File

@@ -7,15 +7,13 @@
package cache package cache
import ( import (
reflect "reflect" common "github.com/aquasecurity/trivy/rpc/common"
sync "sync"
protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl" protoimpl "google.golang.org/protobuf/runtime/protoimpl"
emptypb "google.golang.org/protobuf/types/known/emptypb" emptypb "google.golang.org/protobuf/types/known/emptypb"
timestamppb "google.golang.org/protobuf/types/known/timestamppb" timestamppb "google.golang.org/protobuf/types/known/timestamppb"
reflect "reflect"
common "github.com/aquasecurity/trivy/rpc/common" sync "sync"
) )
const ( const (

View File

@@ -3,40 +3,26 @@
package cache package cache
import ( import context "context"
context "context" import fmt "fmt"
fmt "fmt" import http "net/http"
import ioutil "io/ioutil"
import json "encoding/json"
import strconv "strconv"
import strings "strings"
http "net/http" import protojson "google.golang.org/protobuf/encoding/protojson"
import proto "google.golang.org/protobuf/proto"
import twirp "github.com/twitchtv/twirp"
import ctxsetters "github.com/twitchtv/twirp/ctxsetters"
ioutil "io/ioutil" import google_protobuf2 "google.golang.org/protobuf/types/known/emptypb"
json "encoding/json" import bytes "bytes"
import errors "errors"
strconv "strconv" import io "io"
import path "path"
strings "strings" import url "net/url"
protojson "google.golang.org/protobuf/encoding/protojson"
proto "google.golang.org/protobuf/proto"
twirp "github.com/twitchtv/twirp"
ctxsetters "github.com/twitchtv/twirp/ctxsetters"
google_protobuf2 "google.golang.org/protobuf/types/known/emptypb"
bytes "bytes"
errors "errors"
io "io"
path "path"
url "net/url"
)
// Version compatibility assertion. // Version compatibility assertion.
// If the constant is not defined in the package, that likely means // If the constant is not defined in the package, that likely means

View File

@@ -7,13 +7,11 @@
package scanner package scanner
import ( import (
reflect "reflect" common "github.com/aquasecurity/trivy/rpc/common"
sync "sync"
protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl" protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
common "github.com/aquasecurity/trivy/rpc/common" sync "sync"
) )
const ( const (
@@ -94,7 +92,8 @@ func (x *ScanRequest) GetOptions() *ScanOptions {
return nil return nil
} }
// cf. https://stackoverflow.com/questions/38886789/protobuf3-how-to-describe-map-of-repeated-string // cf.
// https://stackoverflow.com/questions/38886789/protobuf3-how-to-describe-map-of-repeated-string
type Licenses struct { type Licenses struct {
state protoimpl.MessageState state protoimpl.MessageState
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
@@ -148,7 +147,7 @@ type ScanOptions struct {
unknownFields protoimpl.UnknownFields unknownFields protoimpl.UnknownFields
VulnType []string `protobuf:"bytes,1,rep,name=vuln_type,json=vulnType,proto3" json:"vuln_type,omitempty"` VulnType []string `protobuf:"bytes,1,rep,name=vuln_type,json=vulnType,proto3" json:"vuln_type,omitempty"`
SecurityChecks []string `protobuf:"bytes,2,rep,name=security_checks,json=securityChecks,proto3" json:"security_checks,omitempty"` Scanners []string `protobuf:"bytes,2,rep,name=scanners,proto3" json:"scanners,omitempty"`
ListAllPackages bool `protobuf:"varint,3,opt,name=list_all_packages,json=listAllPackages,proto3" json:"list_all_packages,omitempty"` ListAllPackages bool `protobuf:"varint,3,opt,name=list_all_packages,json=listAllPackages,proto3" json:"list_all_packages,omitempty"`
LicenseCategories map[string]*Licenses `protobuf:"bytes,4,rep,name=license_categories,json=licenseCategories,proto3" json:"license_categories,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` LicenseCategories map[string]*Licenses `protobuf:"bytes,4,rep,name=license_categories,json=licenseCategories,proto3" json:"license_categories,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
} }
@@ -192,9 +191,9 @@ func (x *ScanOptions) GetVulnType() []string {
return nil return nil
} }
func (x *ScanOptions) GetSecurityChecks() []string { func (x *ScanOptions) GetScanners() []string {
if x != nil { if x != nil {
return x.SecurityChecks return x.Scanners
} }
return nil return nil
} }
@@ -391,69 +390,68 @@ var file_rpc_scanner_service_proto_rawDesc = []byte{
0x53, 0x63, 0x61, 0x6e, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x07, 0x6f, 0x70, 0x74, 0x53, 0x63, 0x61, 0x6e, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x07, 0x6f, 0x70, 0x74,
0x69, 0x6f, 0x6e, 0x73, 0x22, 0x20, 0x0a, 0x08, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x20, 0x0a, 0x08, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x73,
0x12, 0x14, 0x0a, 0x05, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52,
0x05, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x22, 0xc6, 0x02, 0x0a, 0x0b, 0x53, 0x63, 0x61, 0x6e, 0x4f, 0x05, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x22, 0xb9, 0x02, 0x0a, 0x0b, 0x53, 0x63, 0x61, 0x6e, 0x4f,
0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x76, 0x75, 0x6c, 0x6e, 0x5f, 0x74, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x76, 0x75, 0x6c, 0x6e, 0x5f, 0x74,
0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x76, 0x75, 0x6c, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x76, 0x75, 0x6c, 0x6e, 0x54,
0x79, 0x70, 0x65, 0x12, 0x27, 0x0a, 0x0f, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x5f, 0x79, 0x70, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x63, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x73, 0x18,
0x63, 0x68, 0x65, 0x63, 0x6b, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0e, 0x73, 0x65, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x73, 0x63, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x73, 0x12,
0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x73, 0x12, 0x2a, 0x0a, 0x11, 0x2a, 0x0a, 0x11, 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x61, 0x6c, 0x6c, 0x5f, 0x70, 0x61, 0x63, 0x6b,
0x6c, 0x69, 0x73, 0x74, 0x5f, 0x61, 0x6c, 0x6c, 0x5f, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x61, 0x67, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x6c, 0x69, 0x73, 0x74,
0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x6c, 0x69, 0x73, 0x74, 0x41, 0x6c, 0x6c, 0x41, 0x6c, 0x6c, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x73, 0x12, 0x63, 0x0a, 0x12, 0x6c,
0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x73, 0x12, 0x63, 0x0a, 0x12, 0x6c, 0x69, 0x63, 0x65, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x5f, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x69, 0x65,
0x6e, 0x73, 0x65, 0x5f, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x69, 0x65, 0x73, 0x18, 0x04, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x34, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e,
0x20, 0x03, 0x28, 0x0b, 0x32, 0x34, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x73, 0x63, 0x61, 0x73, 0x63, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x63, 0x61, 0x6e, 0x4f,
0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x63, 0x61, 0x6e, 0x4f, 0x70, 0x74, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x43, 0x61,
0x6f, 0x6e, 0x73, 0x2e, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x43, 0x61, 0x74, 0x65, 0x67, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x69, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x11, 0x6c,
0x6f, 0x72, 0x69, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x11, 0x6c, 0x69, 0x63, 0x65, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x69, 0x65, 0x73,
0x6e, 0x73, 0x65, 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x69, 0x65, 0x73, 0x1a, 0x60, 0x0a, 0x1a, 0x60, 0x0a, 0x16, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x43, 0x61, 0x74, 0x65, 0x67,
0x16, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65,
0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x30, 0x0a, 0x05,
0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x30, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x74, 0x72,
0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x69, 0x76, 0x79, 0x2e, 0x73, 0x63, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4c,
0x2e, 0x73, 0x63, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x63, 0x65, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x73, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02,
0x6e, 0x73, 0x65, 0x73, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x38, 0x01, 0x22, 0x64, 0x0a, 0x0c, 0x53, 0x63, 0x61, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
0x64, 0x0a, 0x0c, 0x53, 0x63, 0x61, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x73, 0x65, 0x12, 0x20, 0x0a, 0x02, 0x6f, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10,
0x20, 0x0a, 0x02, 0x6f, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x74, 0x72, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4f, 0x53,
0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4f, 0x53, 0x52, 0x02, 0x6f, 0x52, 0x02, 0x6f, 0x73, 0x12, 0x32, 0x0a, 0x07, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x18,
0x73, 0x12, 0x32, 0x0a, 0x07, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x73, 0x63,
0x28, 0x0b, 0x32, 0x18, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x73, 0x63, 0x61, 0x6e, 0x6e, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52,
0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x07, 0x72, 0x65, 0x07, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x22, 0x9a, 0x03, 0x0a, 0x06, 0x52, 0x65, 0x73,
0x73, 0x75, 0x6c, 0x74, 0x73, 0x22, 0x9a, 0x03, 0x0a, 0x06, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x75, 0x6c, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x18, 0x01, 0x20,
0x12, 0x16, 0x0a, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x01, 0x28, 0x09, 0x52, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x12, 0x45, 0x0a, 0x0f, 0x76,
0x52, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x12, 0x45, 0x0a, 0x0f, 0x76, 0x75, 0x6c, 0x6e, 0x75, 0x6c, 0x6e, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x69, 0x65, 0x73, 0x18, 0x02,
0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x69, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d,
0x0b, 0x32, 0x1b, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x6d, 0x6f, 0x6e, 0x2e, 0x56, 0x75, 0x6c, 0x6e, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74,
0x2e, 0x56, 0x75, 0x6c, 0x6e, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x52, 0x0f, 0x79, 0x52, 0x0f, 0x76, 0x75, 0x6c, 0x6e, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x69,
0x76, 0x75, 0x6c, 0x6e, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x69, 0x65, 0x73, 0x12, 0x65, 0x73, 0x12, 0x54, 0x0a, 0x11, 0x6d, 0x69, 0x73, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75,
0x54, 0x0a, 0x11, 0x6d, 0x69, 0x73, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e,
0x69, 0x6f, 0x6e, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x74, 0x72, 0x69, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x44, 0x65, 0x74,
0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x44, 0x65, 0x74, 0x65, 0x63, 0x74, 0x65, 0x63, 0x74, 0x65, 0x64, 0x4d, 0x69, 0x73, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72,
0x65, 0x64, 0x4d, 0x69, 0x73, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x11, 0x6d, 0x69, 0x73, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67,
0x6f, 0x6e, 0x52, 0x11, 0x6d, 0x69, 0x73, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6c, 0x61, 0x73,
0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x18, 0x06, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x12, 0x12,
0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79,
0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x70, 0x65, 0x12, 0x31, 0x0a, 0x08, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x73, 0x18, 0x05,
0x31, 0x0a, 0x08, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d,
0x0b, 0x32, 0x15, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x6d, 0x6f, 0x6e, 0x2e, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x52, 0x08, 0x70, 0x61, 0x63,
0x2e, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x52, 0x08, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x6b, 0x61, 0x67, 0x65, 0x73, 0x12, 0x47, 0x0a, 0x10, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x5f,
0x65, 0x73, 0x12, 0x47, 0x0a, 0x10, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x5f, 0x72, 0x65, 0x73, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32,
0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x74, 0x1c, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x43,
0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x43, 0x75, 0x73, 0x74, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x0f, 0x63,
0x6f, 0x6d, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x0f, 0x63, 0x75, 0x73, 0x74, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x35,
0x6f, 0x6d, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x35, 0x0a, 0x07, 0x73, 0x0a, 0x07, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32,
0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x74, 0x1b, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x53,
0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x53, 0x65, 0x63, 0x72, 0x65, 0x63, 0x72, 0x65, 0x74, 0x46, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x52, 0x07, 0x73, 0x65,
0x65, 0x74, 0x46, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x52, 0x07, 0x73, 0x65, 0x63, 0x72, 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x32, 0x50, 0x0a, 0x07, 0x53, 0x63, 0x61, 0x6e, 0x6e, 0x65, 0x72,
0x74, 0x73, 0x32, 0x50, 0x0a, 0x07, 0x53, 0x63, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x12, 0x45, 0x0a, 0x12, 0x45, 0x0a, 0x04, 0x53, 0x63, 0x61, 0x6e, 0x12, 0x1d, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79,
0x04, 0x53, 0x63, 0x61, 0x6e, 0x12, 0x1d, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x73, 0x63, 0x2e, 0x73, 0x63, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x63, 0x61, 0x6e,
0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x63, 0x61, 0x6e, 0x52, 0x65, 0x71, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e,
0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x73, 0x63, 0x61, 0x73, 0x63, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x63, 0x61, 0x6e, 0x52,
0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x63, 0x61, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x33, 0x5a, 0x31, 0x67, 0x69, 0x74, 0x68, 0x75,
0x6f, 0x6e, 0x73, 0x65, 0x42, 0x33, 0x5a, 0x31, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x71, 0x75, 0x61, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69,
0x6f, 0x6d, 0x2f, 0x61, 0x71, 0x75, 0x61, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x2f, 0x74, 0x79, 0x2f, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2f, 0x72, 0x70, 0x63, 0x2f, 0x73, 0x63, 0x61,
0x74, 0x72, 0x69, 0x76, 0x79, 0x2f, 0x72, 0x70, 0x63, 0x2f, 0x73, 0x63, 0x61, 0x6e, 0x6e, 0x65, 0x6e, 0x6e, 0x65, 0x72, 0x3b, 0x73, 0x63, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x62, 0x06, 0x70, 0x72,
0x72, 0x3b, 0x73, 0x63, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x6f, 0x74, 0x6f, 0x33,
0x33,
} }
var ( var (

View File

@@ -24,7 +24,7 @@ message Licenses {
message ScanOptions { message ScanOptions {
repeated string vuln_type = 1; repeated string vuln_type = 1;
repeated string security_checks = 2; repeated string scanners = 2;
bool list_all_packages = 3; bool list_all_packages = 3;
map<string, Licenses> license_categories = 4; map<string, Licenses> license_categories = 4;
} }

View File

@@ -3,38 +3,24 @@
package scanner package scanner
import ( import context "context"
context "context" import fmt "fmt"
fmt "fmt" import http "net/http"
import ioutil "io/ioutil"
import json "encoding/json"
import strconv "strconv"
import strings "strings"
http "net/http" import protojson "google.golang.org/protobuf/encoding/protojson"
import proto "google.golang.org/protobuf/proto"
import twirp "github.com/twitchtv/twirp"
import ctxsetters "github.com/twitchtv/twirp/ctxsetters"
ioutil "io/ioutil" import bytes "bytes"
import errors "errors"
json "encoding/json" import io "io"
import path "path"
strconv "strconv" import url "net/url"
strings "strings"
protojson "google.golang.org/protobuf/encoding/protojson"
proto "google.golang.org/protobuf/proto"
twirp "github.com/twitchtv/twirp"
ctxsetters "github.com/twitchtv/twirp/ctxsetters"
bytes "bytes"
errors "errors"
io "io"
path "path"
url "net/url"
)
// Version compatibility assertion. // Version compatibility assertion.
// If the constant is not defined in the package, that likely means // If the constant is not defined in the package, that likely means
@@ -1108,45 +1094,44 @@ func callClientError(ctx context.Context, h *twirp.ClientHooks, err twirp.Error)
} }
var twirpFileDescriptor0 = []byte{ var twirpFileDescriptor0 = []byte{
// 630 bytes of a gzipped FileDescriptorProto // 617 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x94, 0x6f, 0x6f, 0xd3, 0x3e, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x94, 0x5f, 0x6f, 0xd3, 0x30,
0x10, 0xc7, 0xd5, 0x76, 0x6b, 0xbb, 0xcb, 0x4f, 0xbf, 0x76, 0x16, 0x4c, 0x59, 0xc7, 0x9f, 0xaa, 0x10, 0xc0, 0xd5, 0x76, 0x6b, 0xb3, 0x0b, 0xd2, 0x3a, 0x0b, 0xa6, 0xac, 0xe3, 0x4f, 0xd5, 0x07,
0x0f, 0xa0, 0xe2, 0x41, 0xca, 0x32, 0x10, 0x08, 0x1e, 0xc1, 0x18, 0x68, 0x12, 0x68, 0x93, 0x3b, 0x54, 0xf1, 0x90, 0xb2, 0x0c, 0x04, 0x82, 0x27, 0x18, 0x03, 0x4d, 0x02, 0x6d, 0x72, 0x27, 0x1e,
0xf1, 0x80, 0x27, 0xc1, 0x75, 0x6e, 0x9d, 0xb5, 0x34, 0xce, 0x6c, 0xa7, 0x52, 0xde, 0xca, 0x5e, 0x78, 0x09, 0xae, 0x73, 0x2b, 0xd6, 0xd2, 0x38, 0xb3, 0x9d, 0x4a, 0xf9, 0x2a, 0xfb, 0x26, 0x7c,
0x10, 0xaf, 0x0b, 0xd9, 0x49, 0xa6, 0xb5, 0xdb, 0x78, 0x14, 0xdf, 0xdd, 0xe7, 0xce, 0x67, 0xdf, 0x3b, 0x64, 0x27, 0x99, 0xd6, 0x6e, 0xe3, 0x29, 0xbe, 0xbb, 0xdf, 0xfd, 0xf3, 0x5d, 0x0c, 0x7b,
0x37, 0x86, 0x5d, 0x95, 0xf1, 0x89, 0xe6, 0x2c, 0x4d, 0x51, 0x4d, 0x34, 0xaa, 0xa5, 0xe0, 0x18, 0x2a, 0xe7, 0x13, 0xcd, 0x59, 0x96, 0xa1, 0x9a, 0x68, 0x54, 0x4b, 0xc1, 0x31, 0xcc, 0x95, 0x34,
0x64, 0x4a, 0x1a, 0x49, 0xfa, 0x46, 0x89, 0x65, 0x11, 0x54, 0xc1, 0x60, 0xb9, 0x3f, 0xf0, 0x2d, 0x92, 0xf4, 0x8d, 0x12, 0xcb, 0x32, 0xac, 0x8d, 0xe1, 0xf2, 0x60, 0x10, 0x58, 0x98, 0xcb, 0xc5,
0xcc, 0xe5, 0x62, 0x21, 0xd3, 0x55, 0x76, 0x74, 0xdd, 0x00, 0x6f, 0xca, 0x59, 0x4a, 0xf1, 0x2a, 0x42, 0x66, 0xab, 0xec, 0xe8, 0xba, 0x05, 0xfe, 0x94, 0xb3, 0x8c, 0xe2, 0x55, 0x81, 0xda, 0x90,
0x47, 0x6d, 0xc8, 0x0e, 0xb4, 0x0d, 0x53, 0x73, 0x34, 0x7e, 0x63, 0xd8, 0x18, 0x6f, 0xd1, 0xca, 0x5d, 0xe8, 0x1a, 0xa6, 0xe6, 0x68, 0x82, 0xd6, 0xb0, 0x35, 0xde, 0xa2, 0xb5, 0x44, 0x5e, 0x80,
0x22, 0xcf, 0xc1, 0x63, 0xca, 0x88, 0x73, 0xc6, 0x4d, 0x24, 0x62, 0xbf, 0xe9, 0x82, 0x50, 0xbb, 0xcf, 0x94, 0x11, 0x17, 0x8c, 0x9b, 0x58, 0x24, 0x41, 0xdb, 0x19, 0xa1, 0x51, 0x9d, 0x24, 0x64,
0x8e, 0x63, 0xb2, 0x0b, 0xdd, 0x59, 0x22, 0x67, 0x91, 0x88, 0xb5, 0xdf, 0x1a, 0xb6, 0xc6, 0x5b, 0x0f, 0xbc, 0x59, 0x2a, 0x67, 0xb1, 0x48, 0x74, 0xd0, 0x19, 0x76, 0xc6, 0x5b, 0xb4, 0x67, 0xe5,
0xb4, 0x63, 0xed, 0xe3, 0x58, 0x93, 0x77, 0xd0, 0x91, 0x99, 0x11, 0x32, 0xd5, 0xfe, 0xc6, 0xb0, 0x93, 0x44, 0x93, 0x77, 0xd0, 0x93, 0xb9, 0x11, 0x32, 0xd3, 0xc1, 0xc6, 0xb0, 0x35, 0xf6, 0xa3,
0x31, 0xf6, 0xc2, 0xa7, 0xc1, 0x7a, 0x87, 0x81, 0xed, 0xe1, 0xa4, 0x84, 0x68, 0x4d, 0x8f, 0x86, 0x67, 0xe1, 0x7a, 0x85, 0xa1, 0xad, 0xe1, 0xb4, 0x82, 0x68, 0x43, 0x8f, 0x86, 0xe0, 0x7d, 0x17,
0xd0, 0xfd, 0x2e, 0x38, 0xa6, 0x1a, 0x35, 0x79, 0x04, 0x9b, 0x29, 0x5b, 0xa0, 0xf6, 0x1b, 0xae, 0x1c, 0x33, 0x8d, 0x9a, 0x3c, 0x86, 0xcd, 0x8c, 0x2d, 0x50, 0x07, 0x2d, 0x17, 0xbc, 0x12, 0x46,
0x78, 0x69, 0x8c, 0xfe, 0x34, 0xcb, 0xf6, 0xab, 0x54, 0xb2, 0x07, 0x5b, 0xcb, 0x3c, 0x49, 0x23, 0x7f, 0xdb, 0x55, 0xf9, 0xb5, 0x2b, 0xd9, 0x87, 0xad, 0x65, 0x91, 0x66, 0xb1, 0x29, 0x73, 0xac,
0x53, 0x64, 0x58, 0x91, 0x5d, 0xeb, 0x38, 0x2b, 0x32, 0x24, 0x2f, 0xa1, 0xa7, 0x91, 0xe7, 0x4a, 0x49, 0xcf, 0x2a, 0xce, 0xcb, 0x1c, 0xc9, 0x00, 0xbc, 0x3a, 0xa3, 0x0e, 0xda, 0x95, 0xad, 0x91,
0x98, 0x22, 0xe2, 0x17, 0xc8, 0x2f, 0xb5, 0xdf, 0x74, 0xc8, 0xff, 0xb5, 0xfb, 0xd0, 0x79, 0xc9, 0xc9, 0x2b, 0xd8, 0x49, 0x85, 0x36, 0x31, 0x4b, 0xd3, 0x38, 0x67, 0xfc, 0x92, 0xcd, 0xd1, 0xf6,
0x2b, 0xd8, 0x4e, 0x84, 0x36, 0x11, 0x4b, 0x92, 0x28, 0x63, 0xfc, 0x92, 0xcd, 0xd1, 0x1e, 0xaa, 0xd1, 0x1a, 0x7b, 0x74, 0xdb, 0x1a, 0x3e, 0xa5, 0xe9, 0x59, 0xad, 0x26, 0x1c, 0x48, 0x5a, 0x95,
0x31, 0xee, 0xd2, 0x9e, 0x0d, 0x7c, 0x4a, 0x92, 0xd3, 0xca, 0x4d, 0x38, 0x90, 0xa4, 0xec, 0x31, 0x15, 0x73, 0x66, 0x70, 0x2e, 0x95, 0x40, 0xdb, 0x5a, 0x67, 0xec, 0x47, 0x6f, 0xfe, 0xdb, 0x5a,
0xe2, 0xcc, 0xe0, 0x5c, 0x2a, 0x81, 0xf6, 0x9c, 0xad, 0xb1, 0x17, 0xbe, 0xf9, 0xe7, 0x39, 0x83, 0x58, 0xb7, 0x73, 0x74, 0xe3, 0x76, 0x9c, 0x19, 0x55, 0xd2, 0x9d, 0x74, 0x5d, 0x3f, 0xf8, 0x0d,
0xea, 0x6c, 0x87, 0x37, 0x69, 0x47, 0xa9, 0x51, 0x05, 0xdd, 0x4e, 0xd6, 0xfd, 0x83, 0xdf, 0xb0, 0xbb, 0xf7, 0xc3, 0xa4, 0x0f, 0x9d, 0x4b, 0x2c, 0xeb, 0xf9, 0xd8, 0x23, 0x79, 0x0d, 0x9b, 0x4b,
0x73, 0x3f, 0x4c, 0xfa, 0xd0, 0xba, 0xc4, 0xa2, 0x1a, 0x96, 0x5d, 0x92, 0xd7, 0xb0, 0xb9, 0x64, 0x96, 0x16, 0xe8, 0xc6, 0xe2, 0x47, 0x83, 0xbb, 0x35, 0x34, 0xd7, 0x48, 0x2b, 0xf0, 0x43, 0xfb,
0x49, 0x8e, 0x6e, 0x46, 0x5e, 0x38, 0xb8, 0xdb, 0x43, 0x7d, 0xa7, 0xb4, 0x04, 0x3f, 0x34, 0xdf, 0x7d, 0x6b, 0x94, 0xc0, 0xa3, 0x6a, 0xf2, 0x3a, 0x97, 0x99, 0x46, 0x32, 0x84, 0xb6, 0xd4, 0x2e,
0x37, 0x46, 0x31, 0xfc, 0x57, 0xca, 0x40, 0x67, 0x32, 0xd5, 0x48, 0x86, 0xd0, 0x94, 0xda, 0x95, 0xac, 0x1f, 0xf5, 0xeb, 0x10, 0xd5, 0xce, 0x84, 0xa7, 0x53, 0xda, 0x96, 0x9a, 0x44, 0xd0, 0x53,
0xf5, 0xc2, 0x7e, 0x55, 0xa2, 0x14, 0x50, 0x70, 0x32, 0xa5, 0x4d, 0xa9, 0x49, 0x08, 0x1d, 0x85, 0xa8, 0x8b, 0xd4, 0x54, 0x23, 0xf6, 0xa3, 0xe0, 0x6e, 0x26, 0xea, 0x00, 0xda, 0x80, 0xa3, 0xeb,
0x3a, 0x4f, 0x4c, 0x39, 0x6f, 0x2f, 0xf4, 0xef, 0xee, 0x44, 0x1d, 0x40, 0x6b, 0x70, 0x74, 0xdd, 0x0e, 0x74, 0x2b, 0xdd, 0x83, 0xbb, 0x75, 0x0c, 0xdb, 0x76, 0x46, 0xa8, 0xd8, 0x4c, 0xa4, 0xc2,
0x82, 0x76, 0xe9, 0x7b, 0x50, 0x68, 0x47, 0xd0, 0xb3, 0x03, 0x43, 0xc5, 0x66, 0x22, 0x11, 0xc6, 0xd8, 0xcb, 0x6c, 0xbb, 0xf0, 0xfb, 0xab, 0x55, 0xfc, 0xbc, 0x05, 0x95, 0x74, 0xdd, 0x87, 0x9c,
0x5e, 0x66, 0xd3, 0x95, 0xdf, 0x5b, 0xed, 0xe2, 0xe7, 0x2d, 0xa8, 0xa0, 0xeb, 0x39, 0xe4, 0x0c, 0xc3, 0xce, 0x42, 0x68, 0x2e, 0xb3, 0x0b, 0x31, 0x2f, 0x14, 0x6b, 0x16, 0xce, 0x06, 0x7a, 0xb9,
0xb6, 0x17, 0x42, 0x73, 0x99, 0x9e, 0x8b, 0x79, 0xae, 0x58, 0xad, 0x3e, 0x5b, 0xe8, 0xc5, 0x6a, 0x1a, 0xe8, 0x0b, 0x1a, 0xe4, 0x06, 0x93, 0x1f, 0x6b, 0x38, 0xbd, 0x1b, 0xc0, 0xee, 0x1d, 0x4f,
0xa1, 0x2f, 0x68, 0x90, 0x1b, 0x8c, 0x7f, 0xac, 0xe1, 0xf4, 0x6e, 0x01, 0x2b, 0x42, 0x9e, 0x30, 0x99, 0xd6, 0x41, 0xd7, 0xd5, 0x5c, 0x09, 0x84, 0xc0, 0x86, 0x5b, 0xb1, 0x8e, 0x53, 0xba, 0x33,
0xad, 0xfd, 0xb6, 0xeb, 0xb9, 0x34, 0x08, 0x81, 0x0d, 0xa7, 0xb7, 0x96, 0x73, 0xba, 0x35, 0xd9, 0x39, 0x00, 0xef, 0x66, 0x73, 0x36, 0x5d, 0xda, 0x27, 0xab, 0x69, 0xeb, 0x05, 0xa2, 0x37, 0x18,
0x87, 0xee, 0x8d, 0x72, 0x36, 0xdd, 0xb6, 0x8f, 0x57, 0xb7, 0xad, 0x04, 0x44, 0x6f, 0x30, 0xf2, 0xf9, 0x06, 0x7d, 0x5e, 0x68, 0x23, 0x17, 0xb1, 0x42, 0x2d, 0x0b, 0xc5, 0x51, 0x07, 0x3d, 0xe7,
0x0d, 0xfa, 0x3c, 0xd7, 0x46, 0x2e, 0x22, 0x85, 0x5a, 0xe6, 0x8a, 0xa3, 0xf6, 0x3b, 0x2e, 0xf5, 0xfa, 0x74, 0xd5, 0xf5, 0xc8, 0x51, 0xb4, 0x86, 0xe8, 0x36, 0x5f, 0x91, 0x35, 0x79, 0x0b, 0x3d,
0xc9, 0x6a, 0xea, 0xa1, 0xa3, 0x68, 0x05, 0xd1, 0x1e, 0x5f, 0xb1, 0x35, 0x79, 0x0b, 0x1d, 0x8d, 0x8d, 0x5c, 0xa1, 0xd1, 0x81, 0x77, 0xdf, 0xd5, 0x4d, 0x9d, 0xf1, 0xab, 0xc8, 0x12, 0x91, 0xcd,
0x5c, 0xa1, 0xd1, 0x7e, 0xf7, 0xbe, 0xab, 0x9b, 0xba, 0xe0, 0x57, 0x91, 0xc6, 0x22, 0x9d, 0xd3, 0x69, 0xc3, 0x46, 0x67, 0xd0, 0x9b, 0x56, 0xa3, 0x23, 0xc7, 0xb0, 0x61, 0x8f, 0xe4, 0x81, 0x7f,
0x9a, 0x0d, 0x4f, 0xa1, 0x33, 0x2d, 0x47, 0x47, 0x8e, 0x60, 0xc3, 0x2e, 0xc9, 0x03, 0x3f, 0x6a, 0xb3, 0x7e, 0x1f, 0x06, 0xcf, 0x1f, 0x32, 0x57, 0x4b, 0xf4, 0xf9, 0xf0, 0xd7, 0xc1, 0x5c, 0x98,
0xf5, 0x58, 0x0c, 0x9e, 0x3d, 0x14, 0x2e, 0x45, 0xf4, 0xf9, 0xe0, 0xd7, 0xfe, 0x5c, 0x98, 0x8b, 0x3f, 0xc5, 0xcc, 0x66, 0x9e, 0xb0, 0xab, 0x82, 0x69, 0xe4, 0x85, 0x12, 0xa6, 0x9c, 0x38, 0xc7,
0x7c, 0x66, 0x77, 0x9e, 0xb0, 0xab, 0x9c, 0xd5, 0x3f, 0xda, 0xc4, 0x25, 0x4e, 0x6e, 0xbd, 0x61, 0xc9, 0xad, 0x67, 0xeb, 0x63, 0xfd, 0x9d, 0x75, 0xdd, 0x5b, 0x74, 0xf8, 0x2f, 0x00, 0x00, 0xff,
0x1f, 0xab, 0xef, 0xac, 0xed, 0x1e, 0xa6, 0x83, 0xbf, 0x01, 0x00, 0x00, 0xff, 0xff, 0xa6, 0xdf, 0xff, 0x18, 0xc4, 0x97, 0x86, 0xd4, 0x04, 0x00, 0x00,
0x7a, 0xaf, 0xe1, 0x04, 0x00, 0x00,
} }