mirror of
https://github.com/aquasecurity/trivy.git
synced 2025-12-23 15:37:50 -08:00
feat(vuln): show suppressed vulnerabilities in table (#6084)
Signed-off-by: knqyf263 <knqyf263@gmail.com> Co-authored-by: DmitriyLewen <91113035+DmitriyLewen@users.noreply.github.com>
This commit is contained in:
@@ -1,81 +1,34 @@
|
|||||||
# Filtering
|
# Filtering
|
||||||
Trivy provides various methods for filtering the results.
|
Trivy provides various methods for filtering the results.
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart LR
|
||||||
|
Issues("Detected\nIssues") --> Severity
|
||||||
|
|
||||||
## By Status
|
subgraph Filtering
|
||||||
|
subgraph Prioritization
|
||||||
| Scanner | Supported |
|
direction TB
|
||||||
|:----------------:|:---------:|
|
Severity("By Severity") --> Status("By Status")
|
||||||
| Vulnerability | ✓ |
|
end
|
||||||
| Misconfiguration | |
|
subgraph Suppression
|
||||||
| Secret | |
|
Status --> Ignore("By Finding IDs")
|
||||||
| License | |
|
Ignore --> Rego("By Rego")
|
||||||
|
Rego --> VEX("By VEX")
|
||||||
Trivy supports the following vulnerability statuses:
|
end
|
||||||
|
end
|
||||||
- `unknown`
|
VEX --> Results
|
||||||
- `not_affected`: this package is not affected by this vulnerability on this platform
|
|
||||||
- `affected`: this package is affected by this vulnerability on this platform, but there is no patch released yet
|
|
||||||
- `fixed`: this vulnerability is fixed on this platform
|
|
||||||
- `under_investigation`: it is currently unknown whether or not this vulnerability affects this package on this platform, and it is under investigation
|
|
||||||
- `will_not_fix`: this package is affected by this vulnerability on this platform, but there is currently no intention to fix it (this would primarily be for flaws that are of Low or Moderate impact that pose no significant risk to customers)
|
|
||||||
- `fix_deferred`: this package is affected by this vulnerability on this platform, and may be fixed in the future
|
|
||||||
- `end_of_life`: this package has been identified to contain the impacted component, but analysis to determine whether it is affected or not by this vulnerability was not performed
|
|
||||||
|
|
||||||
Note that vulnerabilities with the `unknown`, `not_affected` or `under_investigation` status are not detected.
|
|
||||||
These are only defined for comprehensiveness, and you will not have the opportunity to specify these statuses.
|
|
||||||
|
|
||||||
Some statuses are supported in limited distributions.
|
|
||||||
|
|
||||||
| OS | Fixed | Affected | Under Investigation | Will Not Fix | Fix Deferred | End of Life |
|
|
||||||
|:----------:|:-----:|:--------:|:-------------------:|:------------:|:------------:|:-----------:|
|
|
||||||
| Debian | ✓ | ✓ | | | ✓ | ✓ |
|
|
||||||
| RHEL | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
|
||||||
| Other OSes | ✓ | ✓ | | | | |
|
|
||||||
|
|
||||||
|
|
||||||
To ignore vulnerabilities with specific statuses, use the `--ignore-status <list_of_statuses>` option.
|
|
||||||
|
|
||||||
|
|
||||||
```bash
|
|
||||||
$ trivy image --ignore-status affected,fixed ruby:2.4.0
|
|
||||||
```
|
```
|
||||||
|
|
||||||
<details>
|
Similar to the functionality of filtering results, you can also limit the sub-targets for each scanner.
|
||||||
<summary>Result</summary>
|
For information on these settings, please refer to the scanner-specific documentation ([vulnerability](../scanner/vulnerability.md) , [misconfiguration](../scanner/misconfiguration/index.md), etc.).
|
||||||
|
|
||||||
```
|
## Prioritization
|
||||||
2019-05-16T12:50:14.786+0900 INFO Detecting Debian vulnerabilities...
|
You can filter the results by
|
||||||
|
|
||||||
ruby:2.4.0 (debian 8.7)
|
- [Severity](#by-severity)
|
||||||
=======================
|
- [Status](#by-status)
|
||||||
Total: 527 (UNKNOWN: 0, LOW: 276, MEDIUM: 83, HIGH: 158, CRITICAL: 10)
|
|
||||||
|
|
||||||
┌─────────────────────────────┬──────────────────┬──────────┬──────────────┬────────────────────────────┬───────────────┬──────────────────────────────────────────────────────────────┐
|
### By Severity
|
||||||
│ Library │ Vulnerability │ Severity │ Status │ Installed Version │ Fixed Version │ Title │
|
|
||||||
├─────────────────────────────┼──────────────────┼──────────┼──────────────┼────────────────────────────┼───────────────┼──────────────────────────────────────────────────────────────┤
|
|
||||||
│ binutils │ CVE-2014-9939 │ CRITICAL │ will_not_fix │ 2.25-5 │ │ binutils: buffer overflow in ihex.c │
|
|
||||||
│ │ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2014-9939 │
|
|
||||||
│ ├──────────────────┤ │ │ ├───────────────┼──────────────────────────────────────────────────────────────┤
|
|
||||||
│ │ CVE-2017-6969 │ │ │ │ │ binutils: Heap-based buffer over-read in readelf when │
|
|
||||||
│ │ │ │ │ │ │ processing corrupt RL78 binaries │
|
|
||||||
│ │ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2017-6969 │
|
|
||||||
│ ├──────────────────┤ │ │ ├───────────────┼──────────────────────────────────────────────────────────────┤
|
|
||||||
...
|
|
||||||
```
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
!!! tip
|
|
||||||
To skip all unfixed vulnerabilities, you can use the `--ignore-unfixed` flag .
|
|
||||||
It is a shorthand of `--ignore-status affected,will_not_fix,fix_deferred,end_of_life`.
|
|
||||||
It displays "fixed" vulnerabilities only.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
$ trivy image --ignore-unfixed ruby:2.4.0
|
|
||||||
```
|
|
||||||
|
|
||||||
## By Severity
|
|
||||||
|
|
||||||
| Scanner | Supported |
|
| Scanner | Supported |
|
||||||
|:----------------:|:---------:|
|
|:----------------:|:---------:|
|
||||||
@@ -202,11 +155,122 @@ See https://avd.aquasec.com/misconfig/avd-aws-0081
|
|||||||
```
|
```
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
## By Finding IDs
|
### By Status
|
||||||
|
|
||||||
|
| Scanner | Supported |
|
||||||
|
|:----------------:|:---------:|
|
||||||
|
| Vulnerability | ✓ |
|
||||||
|
| Misconfiguration | |
|
||||||
|
| Secret | |
|
||||||
|
| License | |
|
||||||
|
|
||||||
|
Trivy supports the following vulnerability statuses:
|
||||||
|
|
||||||
|
- `unknown`
|
||||||
|
- `not_affected`: this package is not affected by this vulnerability on this platform
|
||||||
|
- `affected`: this package is affected by this vulnerability on this platform, but there is no patch released yet
|
||||||
|
- `fixed`: this vulnerability is fixed on this platform
|
||||||
|
- `under_investigation`: it is currently unknown whether or not this vulnerability affects this package on this platform, and it is under investigation
|
||||||
|
- `will_not_fix`: this package is affected by this vulnerability on this platform, but there is currently no intention to fix it (this would primarily be for flaws that are of Low or Moderate impact that pose no significant risk to customers)
|
||||||
|
- `fix_deferred`: this package is affected by this vulnerability on this platform, and may be fixed in the future
|
||||||
|
- `end_of_life`: this package has been identified to contain the impacted component, but analysis to determine whether it is affected or not by this vulnerability was not performed
|
||||||
|
|
||||||
|
Note that vulnerabilities with the `unknown`, `not_affected` or `under_investigation` status are not detected.
|
||||||
|
These are only defined for comprehensiveness, and you will not have the opportunity to specify these statuses.
|
||||||
|
|
||||||
|
Some statuses are supported in limited distributions.
|
||||||
|
|
||||||
|
| OS | Fixed | Affected | Under Investigation | Will Not Fix | Fix Deferred | End of Life |
|
||||||
|
|:----------:|:-----:|:--------:|:-------------------:|:------------:|:------------:|:-----------:|
|
||||||
|
| Debian | ✓ | ✓ | | | ✓ | ✓ |
|
||||||
|
| RHEL | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
||||||
|
| Other OSes | ✓ | ✓ | | | | |
|
||||||
|
|
||||||
|
|
||||||
|
To ignore vulnerabilities with specific statuses, use the `--ignore-status <list_of_statuses>` option.
|
||||||
|
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ trivy image --ignore-status affected,fixed ruby:2.4.0
|
||||||
|
```
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>Result</summary>
|
||||||
|
|
||||||
|
```
|
||||||
|
2019-05-16T12:50:14.786+0900 INFO Detecting Debian vulnerabilities...
|
||||||
|
|
||||||
|
ruby:2.4.0 (debian 8.7)
|
||||||
|
=======================
|
||||||
|
Total: 527 (UNKNOWN: 0, LOW: 276, MEDIUM: 83, HIGH: 158, CRITICAL: 10)
|
||||||
|
|
||||||
|
┌─────────────────────────────┬──────────────────┬──────────┬──────────────┬────────────────────────────┬───────────────┬──────────────────────────────────────────────────────────────┐
|
||||||
|
│ Library │ Vulnerability │ Severity │ Status │ Installed Version │ Fixed Version │ Title │
|
||||||
|
├─────────────────────────────┼──────────────────┼──────────┼──────────────┼────────────────────────────┼───────────────┼──────────────────────────────────────────────────────────────┤
|
||||||
|
│ binutils │ CVE-2014-9939 │ CRITICAL │ will_not_fix │ 2.25-5 │ │ binutils: buffer overflow in ihex.c │
|
||||||
|
│ │ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2014-9939 │
|
||||||
|
│ ├──────────────────┤ │ │ ├───────────────┼──────────────────────────────────────────────────────────────┤
|
||||||
|
│ │ CVE-2017-6969 │ │ │ │ │ binutils: Heap-based buffer over-read in readelf when │
|
||||||
|
│ │ │ │ │ │ │ processing corrupt RL78 binaries │
|
||||||
|
│ │ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2017-6969 │
|
||||||
|
│ ├──────────────────┤ │ │ ├───────────────┼──────────────────────────────────────────────────────────────┤
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
!!! tip
|
||||||
|
To skip all unfixed vulnerabilities, you can use the `--ignore-unfixed` flag .
|
||||||
|
It is a shorthand of `--ignore-status affected,will_not_fix,fix_deferred,end_of_life`.
|
||||||
|
It displays "fixed" vulnerabilities only.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ trivy image --ignore-unfixed ruby:2.4.0
|
||||||
|
```
|
||||||
|
|
||||||
|
## Suppression
|
||||||
|
You can filter the results by
|
||||||
|
|
||||||
|
- [Finding IDs](#by-finding-ids)
|
||||||
|
- [Rego](#by-rego)
|
||||||
|
- [Vulnerability Exploitability Exchange (VEX)](#by-vulnerability-exploitability-exchange-vex)
|
||||||
|
|
||||||
|
To show the suppressed results, use the `--show-suppressed` flag.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ trivy image --vex debian11.csaf.vex --ignorefile .trivyignore.yaml --show-suppressed debian:11
|
||||||
|
...
|
||||||
|
|
||||||
|
Suppressed Vulnerabilities (Total: 9)
|
||||||
|
|
||||||
|
┌───────────────┬───────────────┬──────────┬──────────────┬─────────────────────────────────────────────┬───────────────────┐
|
||||||
|
│ Library │ Vulnerability │ Severity │ Status │ Statement │ Source │
|
||||||
|
├───────────────┼───────────────┼──────────┼──────────────┼─────────────────────────────────────────────┼───────────────────┤
|
||||||
|
│ libdb5.3 │ CVE-2019-8457 │ CRITICAL │ not_affected │ vulnerable_code_not_in_execute_path │ CSAF VEX │
|
||||||
|
├───────────────┼───────────────┼──────────┼──────────────┼─────────────────────────────────────────────┼───────────────────┤
|
||||||
|
│ bsdutils │ CVE-2022-0563 │ LOW │ ignored │ Accept the risk │ .trivyignore.yaml │
|
||||||
|
├───────────────┤ │ │ │ │ │
|
||||||
|
│ libblkid1 │ │ │ │ │ │
|
||||||
|
├───────────────┤ │ │ │ │ │
|
||||||
|
│ libmount1 │ │ │ │ │ │
|
||||||
|
├───────────────┤ │ │ │ │ │
|
||||||
|
│ libsmartcols1 │ │ │ │ │ │
|
||||||
|
├───────────────┤ │ │ │ │ │
|
||||||
|
│ libuuid1 │ │ │ │ │ │
|
||||||
|
├───────────────┤ │ │ │ │ │
|
||||||
|
│ mount │ │ │ │ │ │
|
||||||
|
├───────────────┼───────────────┤ │ ├─────────────────────────────────────────────┤ │
|
||||||
|
│ tar │ CVE-2005-2541 │ │ │ The vulnerable configuration is not enabled │ │
|
||||||
|
├───────────────┼───────────────┤ │ ├─────────────────────────────────────────────┤ │
|
||||||
|
│ util-linux │ CVE-2022-0563 │ │ │ Accept the risk │ │
|
||||||
|
└───────────────┴───────────────┴──────────┴──────────────┴─────────────────────────────────────────────┴───────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
### By Finding IDs
|
||||||
|
|
||||||
Trivy supports the [.trivyignore](#trivyignore) and [.trivyignore.yaml](#trivyignoreyaml) ignore files.
|
Trivy supports the [.trivyignore](#trivyignore) and [.trivyignore.yaml](#trivyignoreyaml) ignore files.
|
||||||
|
|
||||||
### .trivyignore
|
#### .trivyignore
|
||||||
|
|
||||||
| Scanner | Supported |
|
| Scanner | Supported |
|
||||||
|:----------------:|:---------:|
|
|:----------------:|:---------:|
|
||||||
@@ -254,7 +318,7 @@ Total: 0 (UNKNOWN: 0, LOW: 0, MEDIUM: 0, HIGH: 0, CRITICAL: 0)
|
|||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
### .trivyignore.yaml
|
#### .trivyignore.yaml
|
||||||
|
|
||||||
| Scanner | Supported |
|
| Scanner | Supported |
|
||||||
|:----------------:|:---------:|
|
|:----------------:|:---------:|
|
||||||
@@ -339,76 +403,7 @@ Total: 0 (UNKNOWN: 0, LOW: 0, MEDIUM: 0, HIGH: 0, CRITICAL: 0)
|
|||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
|
### By Rego
|
||||||
## By Vulnerability Target
|
|
||||||
| Scanner | Supported |
|
|
||||||
|:----------------:|:---------:|
|
|
||||||
| Vulnerability | ✓ |
|
|
||||||
| Misconfiguration | |
|
|
||||||
| Secret | |
|
|
||||||
| License | |
|
|
||||||
|
|
||||||
Use `--vuln-type` option.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
$ trivy image --vuln-type os ruby:2.4.0
|
|
||||||
```
|
|
||||||
|
|
||||||
Available values:
|
|
||||||
|
|
||||||
- library
|
|
||||||
- os
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary>Result</summary>
|
|
||||||
|
|
||||||
```bash
|
|
||||||
2019-05-22T19:36:50.530+0200 [34mINFO[0m Updating vulnerability database...
|
|
||||||
2019-05-22T19:36:51.681+0200 [34mINFO[0m Detecting Alpine vulnerabilities...
|
|
||||||
2019-05-22T19:36:51.685+0200 [34mINFO[0m Updating npm Security DB...
|
|
||||||
2019-05-22T19:36:52.389+0200 [34mINFO[0m Detecting npm vulnerabilities...
|
|
||||||
2019-05-22T19:36:52.390+0200 [34mINFO[0m Updating pipenv Security DB...
|
|
||||||
2019-05-22T19:36:53.406+0200 [34mINFO[0m Detecting pipenv vulnerabilities...
|
|
||||||
|
|
||||||
ruby:2.4.0 (debian 8.7)
|
|
||||||
=======================
|
|
||||||
Total: 7 (UNKNOWN: 0, LOW: 1, MEDIUM: 1, HIGH: 3, CRITICAL: 2)
|
|
||||||
|
|
||||||
+---------+------------------+----------+-------------------+---------------+----------------------------------+
|
|
||||||
| LIBRARY | VULNERABILITY ID | SEVERITY | INSTALLED VERSION | FIXED VERSION | TITLE |
|
|
||||||
+---------+------------------+----------+-------------------+---------------+----------------------------------+
|
|
||||||
| curl | CVE-2018-14618 | CRITICAL | 7.61.0-r0 | 7.61.1-r0 | curl: NTLM password overflow |
|
|
||||||
| | | | | | via integer overflow |
|
|
||||||
+ +------------------+----------+ +---------------+----------------------------------+
|
|
||||||
| | CVE-2018-16839 | HIGH | | 7.61.1-r1 | curl: Integer overflow leading |
|
|
||||||
| | | | | | to heap-based buffer overflow in |
|
|
||||||
| | | | | | Curl_sasl_create_plain_message() |
|
|
||||||
+---------+------------------+----------+-------------------+---------------+----------------------------------+
|
|
||||||
| git | CVE-2018-17456 | HIGH | 2.15.2-r0 | 2.15.3-r0 | git: arbitrary code execution |
|
|
||||||
| | | | | | via .gitmodules |
|
|
||||||
+ +------------------+ + + +----------------------------------+
|
|
||||||
| | CVE-2018-19486 | | | | git: Improper handling of |
|
|
||||||
| | | | | | PATH allows for commands to be |
|
|
||||||
| | | | | | executed from... |
|
|
||||||
+---------+------------------+----------+-------------------+---------------+----------------------------------+
|
|
||||||
| libssh2 | CVE-2019-3855 | CRITICAL | 1.8.0-r2 | 1.8.1-r0 | libssh2: Integer overflow in |
|
|
||||||
| | | | | | transport read resulting in |
|
|
||||||
| | | | | | out of bounds write... |
|
|
||||||
+---------+------------------+----------+-------------------+---------------+----------------------------------+
|
|
||||||
| sqlite | CVE-2018-20346 | MEDIUM | 3.21.0-r1 | 3.25.3-r0 | CVE-2018-20505 CVE-2018-20506 |
|
|
||||||
| | | | | | sqlite: Multiple flaws in |
|
|
||||||
| | | | | | sqlite which can be triggered |
|
|
||||||
| | | | | | via... |
|
|
||||||
+---------+------------------+----------+-------------------+---------------+----------------------------------+
|
|
||||||
| tar | CVE-2018-20482 | LOW | 1.29-r1 | 1.31-r0 | tar: Infinite read loop in |
|
|
||||||
| | | | | | sparse_dump_region function in |
|
|
||||||
| | | | | | sparse.c |
|
|
||||||
+---------+------------------+----------+-------------------+---------------+----------------------------------+
|
|
||||||
```
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
## By Rego
|
|
||||||
|
|
||||||
| Scanner | Supported |
|
| Scanner | Supported |
|
||||||
|:----------------:|:---------:|
|
|:----------------:|:---------:|
|
||||||
@@ -483,39 +478,15 @@ More info about the helper functions are in the library [here](https://github.co
|
|||||||
|
|
||||||
You can find more example policies [here](https://github.com/aquasecurity/trivy/tree/{{ git.tag }}/pkg/result/module.go)
|
You can find more example policies [here](https://github.com/aquasecurity/trivy/tree/{{ git.tag }}/pkg/result/module.go)
|
||||||
|
|
||||||
## By Inline Comments
|
### By Vulnerability Exploitability Exchange (VEX)
|
||||||
|
|
||||||
| Scanner | Supported |
|
| Scanner | Supported |
|
||||||
|:----------------:|:---------:|
|
|:----------------:|:---------:|
|
||||||
| Vulnerability | |
|
| Vulnerability | ✓ |
|
||||||
| Misconfiguration | ✓ |
|
| Misconfiguration | |
|
||||||
| Secret | |
|
| Secret | |
|
||||||
| License | |
|
| License | |
|
||||||
|
|
||||||
Some configuration file formats (e.g. Terraform) support inline comments.
|
Please refer to the [VEX documentation](../supply-chain/vex.md) for the details.
|
||||||
|
|
||||||
In cases where trivy can detect comments of a specific format immediately adjacent to resource definitions, it is possible to filter/ignore findings from a single point of resource definition (in contrast to `.trivyignore`, which has a directory-wide scope on all of the files scanned).
|
|
||||||
|
|
||||||
The format for these comments is `trivy:ignore:<Vulnerability ID>` immediately following the format-specific line-comment token. You can add multiple ignores on the same comment line.
|
|
||||||
|
|
||||||
For example, to filter a Vulnerability ID "AVD-GCP-0051" in a Terraform HCL file:
|
|
||||||
|
|
||||||
```terraform
|
|
||||||
#trivy:ignore:AVD-GCP-0051
|
|
||||||
resource "google_container_cluster" "one_off_test" {
|
|
||||||
name = var.cluster_name
|
|
||||||
location = var.region
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
For example, to filter vulnerabilities "AVD-GCP-0051" and "AVD-GCP-0053" in a Terraform HCL file:
|
|
||||||
|
|
||||||
```terraform
|
|
||||||
#trivy:ignore:AVD-GCP-0051 trivy:ignore:AVD-GCP-0053
|
|
||||||
resource "google_container_cluster" "one_off_test" {
|
|
||||||
name = var.cluster_name
|
|
||||||
location = var.region
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
[^1]: license name is used as id for `.trivyignore.yaml` files
|
[^1]: license name is used as id for `.trivyignore.yaml` files
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ trivy convert [flags] RESULT_JSON
|
|||||||
--output-plugin-arg string [EXPERIMENTAL] output plugin arguments
|
--output-plugin-arg string [EXPERIMENTAL] output plugin arguments
|
||||||
--report string specify a report format for the output (all,summary) (default "all")
|
--report string specify a report format for the output (all,summary) (default "all")
|
||||||
-s, --severity strings severities of security issues to be displayed (UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL) (default [UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL])
|
-s, --severity strings severities of security issues to be displayed (UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL) (default [UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL])
|
||||||
|
--show-suppressed [EXPERIMENTAL] show suppressed vulnerabilities
|
||||||
-t, --template string output template
|
-t, --template string output template
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -75,6 +75,7 @@ trivy filesystem [flags] PATH
|
|||||||
--secret-config string specify a path to config file for secret scanning (default "trivy-secret.yaml")
|
--secret-config string specify a path to config file for secret scanning (default "trivy-secret.yaml")
|
||||||
--server string server address in client mode
|
--server string server address in client mode
|
||||||
-s, --severity strings severities of security issues to be displayed (UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL) (default [UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL])
|
-s, --severity strings severities of security issues to be displayed (UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL) (default [UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL])
|
||||||
|
--show-suppressed [EXPERIMENTAL] show suppressed vulnerabilities
|
||||||
--skip-db-update skip updating vulnerability database
|
--skip-db-update skip updating vulnerability database
|
||||||
--skip-dirs strings specify the directories or glob patterns to skip
|
--skip-dirs strings specify the directories or glob patterns to skip
|
||||||
--skip-files strings specify the files or glob patterns to skip
|
--skip-files strings specify the files or glob patterns to skip
|
||||||
|
|||||||
@@ -95,6 +95,7 @@ trivy image [flags] IMAGE_NAME
|
|||||||
--secret-config string specify a path to config file for secret scanning (default "trivy-secret.yaml")
|
--secret-config string specify a path to config file for secret scanning (default "trivy-secret.yaml")
|
||||||
--server string server address in client mode
|
--server string server address in client mode
|
||||||
-s, --severity strings severities of security issues to be displayed (UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL) (default [UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL])
|
-s, --severity strings severities of security issues to be displayed (UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL) (default [UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL])
|
||||||
|
--show-suppressed [EXPERIMENTAL] show suppressed vulnerabilities
|
||||||
--skip-db-update skip updating vulnerability database
|
--skip-db-update skip updating vulnerability database
|
||||||
--skip-dirs strings specify the directories or glob patterns to skip
|
--skip-dirs strings specify the directories or glob patterns to skip
|
||||||
--skip-files strings specify the files or glob patterns to skip
|
--skip-files strings specify the files or glob patterns to skip
|
||||||
|
|||||||
@@ -87,6 +87,7 @@ trivy kubernetes [flags] { cluster | all | specific resources like kubectl. eg:
|
|||||||
--scanners strings comma-separated list of what security issues to detect (vuln,misconfig,secret,rbac) (default [vuln,misconfig,secret,rbac])
|
--scanners strings comma-separated list of what security issues to detect (vuln,misconfig,secret,rbac) (default [vuln,misconfig,secret,rbac])
|
||||||
--secret-config string specify a path to config file for secret scanning (default "trivy-secret.yaml")
|
--secret-config string specify a path to config file for secret scanning (default "trivy-secret.yaml")
|
||||||
-s, --severity strings severities of security issues to be displayed (UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL) (default [UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL])
|
-s, --severity strings severities of security issues to be displayed (UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL) (default [UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL])
|
||||||
|
--show-suppressed [EXPERIMENTAL] show suppressed vulnerabilities
|
||||||
--skip-db-update skip updating vulnerability database
|
--skip-db-update skip updating vulnerability database
|
||||||
--skip-dirs strings specify the directories or glob patterns to skip
|
--skip-dirs strings specify the directories or glob patterns to skip
|
||||||
--skip-files strings specify the files or glob patterns to skip
|
--skip-files strings specify the files or glob patterns to skip
|
||||||
|
|||||||
@@ -74,6 +74,7 @@ trivy repository [flags] (REPO_PATH | REPO_URL)
|
|||||||
--secret-config string specify a path to config file for secret scanning (default "trivy-secret.yaml")
|
--secret-config string specify a path to config file for secret scanning (default "trivy-secret.yaml")
|
||||||
--server string server address in client mode
|
--server string server address in client mode
|
||||||
-s, --severity strings severities of security issues to be displayed (UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL) (default [UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL])
|
-s, --severity strings severities of security issues to be displayed (UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL) (default [UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL])
|
||||||
|
--show-suppressed [EXPERIMENTAL] show suppressed vulnerabilities
|
||||||
--skip-db-update skip updating vulnerability database
|
--skip-db-update skip updating vulnerability database
|
||||||
--skip-dirs strings specify the directories or glob patterns to skip
|
--skip-dirs strings specify the directories or glob patterns to skip
|
||||||
--skip-files strings specify the files or glob patterns to skip
|
--skip-files strings specify the files or glob patterns to skip
|
||||||
|
|||||||
@@ -76,6 +76,7 @@ trivy rootfs [flags] ROOTDIR
|
|||||||
--secret-config string specify a path to config file for secret scanning (default "trivy-secret.yaml")
|
--secret-config string specify a path to config file for secret scanning (default "trivy-secret.yaml")
|
||||||
--server string server address in client mode
|
--server string server address in client mode
|
||||||
-s, --severity strings severities of security issues to be displayed (UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL) (default [UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL])
|
-s, --severity strings severities of security issues to be displayed (UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL) (default [UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL])
|
||||||
|
--show-suppressed [EXPERIMENTAL] show suppressed vulnerabilities
|
||||||
--skip-db-update skip updating vulnerability database
|
--skip-db-update skip updating vulnerability database
|
||||||
--skip-dirs strings specify the directories or glob patterns to skip
|
--skip-dirs strings specify the directories or glob patterns to skip
|
||||||
--skip-files strings specify the files or glob patterns to skip
|
--skip-files strings specify the files or glob patterns to skip
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ trivy sbom [flags] SBOM_PATH
|
|||||||
--sbom-sources strings [EXPERIMENTAL] try to retrieve SBOM from the specified sources (oci,rekor)
|
--sbom-sources strings [EXPERIMENTAL] try to retrieve SBOM from the specified sources (oci,rekor)
|
||||||
--server string server address in client mode
|
--server string server address in client mode
|
||||||
-s, --severity strings severities of security issues to be displayed (UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL) (default [UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL])
|
-s, --severity strings severities of security issues to be displayed (UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL) (default [UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL])
|
||||||
|
--show-suppressed [EXPERIMENTAL] show suppressed vulnerabilities
|
||||||
--skip-db-update skip updating vulnerability database
|
--skip-db-update skip updating vulnerability database
|
||||||
--skip-dirs strings specify the directories or glob patterns to skip
|
--skip-dirs strings specify the directories or glob patterns to skip
|
||||||
--skip-files strings specify the files or glob patterns to skip
|
--skip-files strings specify the files or glob patterns to skip
|
||||||
|
|||||||
@@ -67,6 +67,7 @@ trivy vm [flags] VM_IMAGE
|
|||||||
--secret-config string specify a path to config file for secret scanning (default "trivy-secret.yaml")
|
--secret-config string specify a path to config file for secret scanning (default "trivy-secret.yaml")
|
||||||
--server string server address in client mode
|
--server string server address in client mode
|
||||||
-s, --severity strings severities of security issues to be displayed (UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL) (default [UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL])
|
-s, --severity strings severities of security issues to be displayed (UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL) (default [UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL])
|
||||||
|
--show-suppressed [EXPERIMENTAL] show suppressed vulnerabilities
|
||||||
--skip-db-update skip updating vulnerability database
|
--skip-db-update skip updating vulnerability database
|
||||||
--skip-dirs strings specify the directories or glob patterns to skip
|
--skip-dirs strings specify the directories or glob patterns to skip
|
||||||
--skip-files strings specify the files or glob patterns to skip
|
--skip-files strings specify the files or glob patterns to skip
|
||||||
|
|||||||
@@ -316,15 +316,17 @@ This section describes misconfiguration-specific configuration.
|
|||||||
Other common options are documented [here](../../configuration/index.md).
|
Other common options are documented [here](../../configuration/index.md).
|
||||||
|
|
||||||
### Enabling a subset of misconfiguration scanners
|
### Enabling a subset of misconfiguration scanners
|
||||||
It's possible to only enable certain misconfiguration scanners if you prefer. You can do so by passing the `--misconfig-scanners` option.
|
It's possible to only enable certain misconfiguration scanners if you prefer.
|
||||||
|
You can do so by passing the `--misconfig-scanners` option.
|
||||||
This flag takes a comma-separated list of configuration scanner types.
|
This flag takes a comma-separated list of configuration scanner types.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
trivy config --misconfig-scanners=terraform,dockerfile .
|
trivy config --misconfig-scanners=terraform,dockerfile .
|
||||||
```
|
```
|
||||||
|
|
||||||
Will only scan for misconfigurations that pertain to Terraform and Dockerfiles.
|
Will only scan for misconfigurations that pertain to Terraform and Dockerfiles.
|
||||||
|
|
||||||
### Pass custom policies
|
### Passing custom policies
|
||||||
You can pass policy files or directories including your custom policies through `--policy` option.
|
You can pass policy files or directories including your custom policies through `--policy` option.
|
||||||
This can be repeated for specifying multiple files or directories.
|
This can be repeated for specifying multiple files or directories.
|
||||||
|
|
||||||
@@ -338,7 +340,7 @@ For more details, see [Custom Policies](./custom/index.md).
|
|||||||
!!! tip
|
!!! tip
|
||||||
You also need to specify `--namespaces` option.
|
You also need to specify `--namespaces` option.
|
||||||
|
|
||||||
### Pass custom data
|
### Passing custom data
|
||||||
You can pass directories including your custom data through `--data` option.
|
You can pass directories including your custom data through `--data` option.
|
||||||
This can be repeated for specifying multiple directories.
|
This can be repeated for specifying multiple directories.
|
||||||
|
|
||||||
@@ -349,7 +351,7 @@ trivy conf --policy ./policy --data ./data --namespaces user ./configs
|
|||||||
|
|
||||||
For more details, see [Custom Data](./custom/data.md).
|
For more details, see [Custom Data](./custom/data.md).
|
||||||
|
|
||||||
### Pass namespaces
|
### Passing namespaces
|
||||||
By default, Trivy evaluates policies defined in `builtin.*`.
|
By default, Trivy evaluates policies defined in `builtin.*`.
|
||||||
If you want to evaluate custom policies in other packages, you have to specify package prefixes through `--namespaces` option.
|
If you want to evaluate custom policies in other packages, you have to specify package prefixes through `--namespaces` option.
|
||||||
This can be repeated for specifying multiple packages.
|
This can be repeated for specifying multiple packages.
|
||||||
@@ -358,4 +360,32 @@ This can be repeated for specifying multiple packages.
|
|||||||
trivy conf --policy ./policy --namespaces main --namespaces user ./configs
|
trivy conf --policy ./policy --namespaces main --namespaces user ./configs
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Skipping resources by inline comments
|
||||||
|
Some configuration file formats (e.g. Terraform) support inline comments.
|
||||||
|
|
||||||
|
In cases where trivy can detect comments of a specific format immediately adjacent to resource definitions, it is possible to filter/ignore findings from a single point of resource definition (in contrast to `.trivyignore`, which has a directory-wide scope on all of the files scanned).
|
||||||
|
|
||||||
|
The format for these comments is `trivy:ignore:<Vulnerability ID>` immediately following the format-specific line-comment token.
|
||||||
|
You can add multiple ignores on the same comment line.
|
||||||
|
|
||||||
|
For example, to filter a misconfiguration ID "AVD-GCP-0051" in a Terraform HCL file:
|
||||||
|
|
||||||
|
```terraform
|
||||||
|
#trivy:ignore:AVD-GCP-0051
|
||||||
|
resource "google_container_cluster" "one_off_test" {
|
||||||
|
name = var.cluster_name
|
||||||
|
location = var.region
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
For example, to filter misconfigurations "AVD-GCP-0051" and "AVD-GCP-0053" in a Terraform HCL file:
|
||||||
|
|
||||||
|
```terraform
|
||||||
|
#trivy:ignore:AVD-GCP-0051 trivy:ignore:AVD-GCP-0053
|
||||||
|
resource "google_container_cluster" "one_off_test" {
|
||||||
|
name = var.cluster_name
|
||||||
|
location = var.region
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
[custom]: custom/index.md
|
[custom]: custom/index.md
|
||||||
@@ -152,6 +152,76 @@ The default is `ghcr.io/aquasecurity/trivy-java-db`.
|
|||||||
If authentication is required, you need to run `docker login YOUR_REGISTRY`.
|
If authentication is required, you need to run `docker login YOUR_REGISTRY`.
|
||||||
Currently, specifying a username and password is not supported.
|
Currently, specifying a username and password is not supported.
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
This section describes vulnerability-specific configuration.
|
||||||
|
Other common options are documented [here](../configuration/index.md).
|
||||||
|
|
||||||
|
### Enabling a subset of package types
|
||||||
|
It's possible to only enable certain package types if you prefer.
|
||||||
|
You can do so by passing the `--vuln-type` option.
|
||||||
|
This flag takes a comma-separated list of package types.
|
||||||
|
|
||||||
|
Available values:
|
||||||
|
|
||||||
|
- os
|
||||||
|
- Scan OS packages managed by the OS package manager (e.g. `dpkg`, `yum`, `apk`).
|
||||||
|
- library
|
||||||
|
- Scan language-specific packages (e.g. packages installed by `pip`, `npm`, or `gem`).
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ trivy image --vuln-type os ruby:2.4.0
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>Result</summary>
|
||||||
|
|
||||||
|
```bash
|
||||||
|
2019-05-22T19:36:50.530+0200 [34mINFO[0m Updating vulnerability database...
|
||||||
|
2019-05-22T19:36:51.681+0200 [34mINFO[0m Detecting Alpine vulnerabilities...
|
||||||
|
2019-05-22T19:36:51.685+0200 [34mINFO[0m Updating npm Security DB...
|
||||||
|
2019-05-22T19:36:52.389+0200 [34mINFO[0m Detecting npm vulnerabilities...
|
||||||
|
2019-05-22T19:36:52.390+0200 [34mINFO[0m Updating pipenv Security DB...
|
||||||
|
2019-05-22T19:36:53.406+0200 [34mINFO[0m Detecting pipenv vulnerabilities...
|
||||||
|
|
||||||
|
ruby:2.4.0 (debian 8.7)
|
||||||
|
=======================
|
||||||
|
Total: 7 (UNKNOWN: 0, LOW: 1, MEDIUM: 1, HIGH: 3, CRITICAL: 2)
|
||||||
|
|
||||||
|
+---------+------------------+----------+-------------------+---------------+----------------------------------+
|
||||||
|
| LIBRARY | VULNERABILITY ID | SEVERITY | INSTALLED VERSION | FIXED VERSION | TITLE |
|
||||||
|
+---------+------------------+----------+-------------------+---------------+----------------------------------+
|
||||||
|
| curl | CVE-2018-14618 | CRITICAL | 7.61.0-r0 | 7.61.1-r0 | curl: NTLM password overflow |
|
||||||
|
| | | | | | via integer overflow |
|
||||||
|
+ +------------------+----------+ +---------------+----------------------------------+
|
||||||
|
| | CVE-2018-16839 | HIGH | | 7.61.1-r1 | curl: Integer overflow leading |
|
||||||
|
| | | | | | to heap-based buffer overflow in |
|
||||||
|
| | | | | | Curl_sasl_create_plain_message() |
|
||||||
|
+---------+------------------+----------+-------------------+---------------+----------------------------------+
|
||||||
|
| git | CVE-2018-17456 | HIGH | 2.15.2-r0 | 2.15.3-r0 | git: arbitrary code execution |
|
||||||
|
| | | | | | via .gitmodules |
|
||||||
|
+ +------------------+ + + +----------------------------------+
|
||||||
|
| | CVE-2018-19486 | | | | git: Improper handling of |
|
||||||
|
| | | | | | PATH allows for commands to be |
|
||||||
|
| | | | | | executed from... |
|
||||||
|
+---------+------------------+----------+-------------------+---------------+----------------------------------+
|
||||||
|
| libssh2 | CVE-2019-3855 | CRITICAL | 1.8.0-r2 | 1.8.1-r0 | libssh2: Integer overflow in |
|
||||||
|
| | | | | | transport read resulting in |
|
||||||
|
| | | | | | out of bounds write... |
|
||||||
|
+---------+------------------+----------+-------------------+---------------+----------------------------------+
|
||||||
|
| sqlite | CVE-2018-20346 | MEDIUM | 3.21.0-r1 | 3.25.3-r0 | CVE-2018-20505 CVE-2018-20506 |
|
||||||
|
| | | | | | sqlite: Multiple flaws in |
|
||||||
|
| | | | | | sqlite which can be triggered |
|
||||||
|
| | | | | | via... |
|
||||||
|
+---------+------------------+----------+-------------------+---------------+----------------------------------+
|
||||||
|
| tar | CVE-2018-20482 | LOW | 1.29-r1 | 1.31-r0 | tar: Infinite read loop in |
|
||||||
|
| | | | | | sparse_dump_region function in |
|
||||||
|
| | | | | | sparse.c |
|
||||||
|
+---------+------------------+----------+-------------------+---------------+----------------------------------+
|
||||||
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
[^1]: https://github.com/GoogleContainerTools/distroless
|
[^1]: https://github.com/GoogleContainerTools/distroless
|
||||||
|
|
||||||
[nvd-CVE-2023-0464]: https://nvd.nist.gov/vuln/detail/CVE-2023-0464
|
[nvd-CVE-2023-0464]: https://nvd.nist.gov/vuln/detail/CVE-2023-0464
|
||||||
|
|||||||
@@ -203,7 +203,11 @@ theme:
|
|||||||
|
|
||||||
markdown_extensions:
|
markdown_extensions:
|
||||||
- pymdownx.highlight
|
- pymdownx.highlight
|
||||||
- pymdownx.superfences
|
- pymdownx.superfences:
|
||||||
|
custom_fences:
|
||||||
|
- name: mermaid
|
||||||
|
class: mermaid
|
||||||
|
format: !!python/name:pymdownx.superfences.fence_code_format
|
||||||
- admonition
|
- admonition
|
||||||
- footnotes
|
- footnotes
|
||||||
- attr_list
|
- attr_list
|
||||||
|
|||||||
@@ -61,12 +61,12 @@ func ConvertResults(results scan.Results, provider string, scoped []string) map[
|
|||||||
primaryURL = fmt.Sprintf("https://avd.aquasec.com/misconfig/%s", strings.ToLower(result.Rule().AVDID))
|
primaryURL = fmt.Sprintf("https://avd.aquasec.com/misconfig/%s", strings.ToLower(result.Rule().AVDID))
|
||||||
}
|
}
|
||||||
|
|
||||||
status := types.StatusFailure
|
status := types.MisconfStatusFailure
|
||||||
switch result.Status() {
|
switch result.Status() {
|
||||||
case scan.StatusPassed:
|
case scan.StatusPassed:
|
||||||
status = types.StatusPassed
|
status = types.MisconfStatusPassed
|
||||||
case scan.StatusIgnored:
|
case scan.StatusIgnored:
|
||||||
status = types.StatusException
|
status = types.MisconfStatusException
|
||||||
}
|
}
|
||||||
|
|
||||||
flat := result.Flatten()
|
flat := result.Flatten()
|
||||||
|
|||||||
@@ -643,6 +643,7 @@ func NewConfigCommand(globalFlags *flag.GlobalFlagGroup) *cobra.Command {
|
|||||||
reportFlagGroup.DependencyTree = nil // disable '--dependency-tree'
|
reportFlagGroup.DependencyTree = nil // disable '--dependency-tree'
|
||||||
reportFlagGroup.ListAllPkgs = nil // disable '--list-all-pkgs'
|
reportFlagGroup.ListAllPkgs = nil // disable '--list-all-pkgs'
|
||||||
reportFlagGroup.ExitOnEOL = nil // disable '--exit-on-eol'
|
reportFlagGroup.ExitOnEOL = nil // disable '--exit-on-eol'
|
||||||
|
reportFlagGroup.ShowSuppressed = nil // disable '--show-suppressed'
|
||||||
reportFormat := flag.ReportFormatFlag.Clone()
|
reportFormat := flag.ReportFormatFlag.Clone()
|
||||||
reportFormat.Usage = "specify a compliance report format for the output" // @TODO: support --report summary for non compliance reports
|
reportFormat.Usage = "specify a compliance report format for the output" // @TODO: support --report summary for non compliance reports
|
||||||
reportFlagGroup.ReportFormat = reportFormat
|
reportFlagGroup.ReportFormat = reportFormat
|
||||||
@@ -988,6 +989,7 @@ func NewAWSCommand(globalFlags *flag.GlobalFlagGroup) *cobra.Command {
|
|||||||
}
|
}
|
||||||
reportFlagGroup.Compliance = &compliance // override usage as the accepted values differ for each subcommand.
|
reportFlagGroup.Compliance = &compliance // override usage as the accepted values differ for each subcommand.
|
||||||
reportFlagGroup.ExitOnEOL = nil // disable '--exit-on-eol'
|
reportFlagGroup.ExitOnEOL = nil // disable '--exit-on-eol'
|
||||||
|
reportFlagGroup.ShowSuppressed = nil // disable '--show-suppressed'
|
||||||
|
|
||||||
awsFlags := &flag.Flags{
|
awsFlags := &flag.Flags{
|
||||||
GlobalFlagGroup: globalFlags,
|
GlobalFlagGroup: globalFlags,
|
||||||
|
|||||||
@@ -26,7 +26,10 @@ func TestJSONWriter_Write(t *testing.T) {
|
|||||||
Results: types.Results{
|
Results: types.Results{
|
||||||
{
|
{
|
||||||
Misconfigurations: []types.DetectedMisconfiguration{
|
Misconfigurations: []types.DetectedMisconfiguration{
|
||||||
{AVDID: "AVD-KSV012", Status: types.StatusFailure},
|
{
|
||||||
|
AVDID: "AVD-KSV012",
|
||||||
|
Status: types.MisconfStatusFailure,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -38,7 +41,10 @@ func TestJSONWriter_Write(t *testing.T) {
|
|||||||
Results: types.Results{
|
Results: types.Results{
|
||||||
{
|
{
|
||||||
Misconfigurations: []types.DetectedMisconfiguration{
|
Misconfigurations: []types.DetectedMisconfiguration{
|
||||||
{AVDID: "AVD-KSV013", Status: types.StatusFailure},
|
{
|
||||||
|
AVDID: "AVD-KSV013",
|
||||||
|
Status: types.MisconfStatusFailure,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -69,7 +75,10 @@ func TestJSONWriter_Write(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) {
|
||||||
buf := new(bytes.Buffer)
|
buf := new(bytes.Buffer)
|
||||||
tr := report.JSONWriter{Report: tt.reportType, Output: buf}
|
tr := report.JSONWriter{
|
||||||
|
Report: tt.reportType,
|
||||||
|
Output: buf,
|
||||||
|
}
|
||||||
err := tr.Write(tt.input)
|
err := tr.Write(tt.input)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
|||||||
@@ -57,13 +57,13 @@ func TestBuildComplianceReport(t *testing.T) {
|
|||||||
"https://kubernetes.io/docs/concepts/security/pod-security-standards/#restricted",
|
"https://kubernetes.io/docs/concepts/security/pod-security-standards/#restricted",
|
||||||
"https://avd.aquasec.com/misconfig/ksv001",
|
"https://avd.aquasec.com/misconfig/ksv001",
|
||||||
},
|
},
|
||||||
Status: types.StatusPassed,
|
Status: types.MisconfStatusPassed,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Type: "Kubernetes Security Check",
|
Type: "Kubernetes Security Check",
|
||||||
ID: "KSV002",
|
ID: "KSV002",
|
||||||
AVDID: "AVD-KSV-9999",
|
AVDID: "AVD-KSV-9999",
|
||||||
Status: types.StatusFailure,
|
Status: types.MisconfStatusFailure,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -179,7 +179,7 @@ func TestBuildComplianceReport(t *testing.T) {
|
|||||||
"https://kubernetes.io/docs/concepts/security/pod-security-standards/#restricted",
|
"https://kubernetes.io/docs/concepts/security/pod-security-standards/#restricted",
|
||||||
"https://avd.aquasec.com/misconfig/ksv001",
|
"https://avd.aquasec.com/misconfig/ksv001",
|
||||||
},
|
},
|
||||||
Status: types.StatusPassed,
|
Status: types.MisconfStatusPassed,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -32,7 +32,10 @@ func TestBuildSummary(t *testing.T) {
|
|||||||
Results: types.Results{
|
Results: types.Results{
|
||||||
{
|
{
|
||||||
Misconfigurations: []types.DetectedMisconfiguration{
|
Misconfigurations: []types.DetectedMisconfiguration{
|
||||||
{AVDID: "AVD-KSV012", Status: types.StatusFailure},
|
{
|
||||||
|
AVDID: "AVD-KSV012",
|
||||||
|
Status: types.MisconfStatusFailure,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -44,7 +47,10 @@ func TestBuildSummary(t *testing.T) {
|
|||||||
Results: types.Results{
|
Results: types.Results{
|
||||||
{
|
{
|
||||||
Misconfigurations: []types.DetectedMisconfiguration{
|
Misconfigurations: []types.DetectedMisconfiguration{
|
||||||
{AVDID: "AVD-KSV013", Status: types.StatusFailure},
|
{
|
||||||
|
AVDID: "AVD-KSV013",
|
||||||
|
Status: types.MisconfStatusFailure,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -86,7 +92,10 @@ func TestBuildSummary(t *testing.T) {
|
|||||||
Results: types.Results{
|
Results: types.Results{
|
||||||
{
|
{
|
||||||
Misconfigurations: []types.DetectedMisconfiguration{
|
Misconfigurations: []types.DetectedMisconfiguration{
|
||||||
{AVDID: "AVD-KSV012", Status: types.StatusFailure},
|
{
|
||||||
|
AVDID: "AVD-KSV012",
|
||||||
|
Status: types.MisconfStatusFailure,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -98,7 +107,10 @@ func TestBuildSummary(t *testing.T) {
|
|||||||
Results: types.Results{
|
Results: types.Results{
|
||||||
{
|
{
|
||||||
Misconfigurations: []types.DetectedMisconfiguration{
|
Misconfigurations: []types.DetectedMisconfiguration{
|
||||||
{AVDID: "AVD-KSV013", Status: types.StatusFailure},
|
{
|
||||||
|
AVDID: "AVD-KSV013",
|
||||||
|
Status: types.MisconfStatusFailure,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package report
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"io"
|
"io"
|
||||||
"sync"
|
|
||||||
|
|
||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
@@ -33,7 +32,6 @@ func (tw TableWriter) Write(ctx context.Context, report *ComplianceReport) error
|
|||||||
t := pkgReport.Writer{
|
t := pkgReport.Writer{
|
||||||
Output: tw.Output,
|
Output: tw.Output,
|
||||||
Severities: tw.Severities,
|
Severities: tw.Severities,
|
||||||
ShowMessageOnce: &sync.Once{},
|
|
||||||
}
|
}
|
||||||
for _, cr := range report.Results {
|
for _, cr := range report.Results {
|
||||||
r := types.Report{Results: cr.Results}
|
r := types.Report{Results: cr.Results}
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ func TestTableWriter_Write(t *testing.T) {
|
|||||||
Misconfigurations: []types.DetectedMisconfiguration{
|
Misconfigurations: []types.DetectedMisconfiguration{
|
||||||
{
|
{
|
||||||
AVDID: "AVD-KSV012",
|
AVDID: "AVD-KSV012",
|
||||||
Status: types.StatusFailure,
|
Status: types.MisconfStatusFailure,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -54,7 +54,7 @@ func TestTableWriter_Write(t *testing.T) {
|
|||||||
Misconfigurations: []types.DetectedMisconfiguration{
|
Misconfigurations: []types.DetectedMisconfiguration{
|
||||||
{
|
{
|
||||||
AVDID: "AVD-KSV013",
|
AVDID: "AVD-KSV013",
|
||||||
Status: types.StatusFailure,
|
Status: types.MisconfStatusFailure,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import (
|
|||||||
"github.com/samber/lo"
|
"github.com/samber/lo"
|
||||||
|
|
||||||
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
|
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
|
||||||
ftypes "github.com/aquasecurity/trivy/pkg/fanal/types"
|
|
||||||
"github.com/aquasecurity/trivy/pkg/types"
|
"github.com/aquasecurity/trivy/pkg/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -63,8 +62,8 @@ func filterHighSecrets(result types.Result) types.Result {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func filterSecrets(result types.Result, severity dbTypes.Severity) types.Result {
|
func filterSecrets(result types.Result, severity dbTypes.Severity) types.Result {
|
||||||
filtered := lo.Filter(result.Secrets, func(vuln ftypes.SecretFinding, _ int) bool {
|
filtered := lo.Filter(result.Secrets, func(secret types.DetectedSecret, _ int) bool {
|
||||||
return vuln.Severity == severity.String()
|
return secret.Severity == severity.String()
|
||||||
})
|
})
|
||||||
return types.Result{
|
return types.Result{
|
||||||
Target: result.Target,
|
Target: result.Target,
|
||||||
|
|||||||
@@ -11,10 +11,10 @@ func MapSpecCheckIDToFilteredResults(result types.Result, checkIDs map[types.Sca
|
|||||||
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.VulnerabilityScanner], vuln.GetID()) {
|
if !slices.Contains(checkIDs[types.VulnerabilityScanner], vuln.VulnerabilityID) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
mapCheckByID[vuln.GetID()] = append(mapCheckByID[vuln.GetID()], types.Result{
|
mapCheckByID[vuln.VulnerabilityID] = append(mapCheckByID[vuln.VulnerabilityID], types.Result{
|
||||||
Target: result.Target,
|
Target: result.Target,
|
||||||
Class: result.Class,
|
Class: result.Class,
|
||||||
Type: result.Type,
|
Type: result.Type,
|
||||||
@@ -23,11 +23,11 @@ func MapSpecCheckIDToFilteredResults(result types.Result, checkIDs map[types.Sca
|
|||||||
}
|
}
|
||||||
for _, m := range result.Misconfigurations {
|
for _, m := range result.Misconfigurations {
|
||||||
// Skip irrelevant check IDs
|
// Skip irrelevant check IDs
|
||||||
if !slices.Contains(checkIDs[types.MisconfigScanner], m.GetID()) {
|
if !slices.Contains(checkIDs[types.MisconfigScanner], m.AVDID) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
mapCheckByID[m.GetID()] = append(mapCheckByID[m.GetID()], types.Result{
|
mapCheckByID[m.AVDID] = append(mapCheckByID[m.AVDID], types.Result{
|
||||||
Target: result.Target,
|
Target: result.Target,
|
||||||
Class: result.Class,
|
Class: result.Class,
|
||||||
Type: result.Type,
|
Type: result.Type,
|
||||||
@@ -45,11 +45,11 @@ func MapSpecCheckIDToFilteredResults(result types.Result, checkIDs map[types.Sca
|
|||||||
func misconfigSummary(misconfig types.DetectedMisconfiguration) *types.MisconfSummary {
|
func misconfigSummary(misconfig types.DetectedMisconfiguration) *types.MisconfSummary {
|
||||||
rms := types.MisconfSummary{}
|
rms := types.MisconfSummary{}
|
||||||
switch misconfig.Status {
|
switch misconfig.Status {
|
||||||
case types.StatusPassed:
|
case types.MisconfStatusPassed:
|
||||||
rms.Successes = 1
|
rms.Successes = 1
|
||||||
case types.StatusFailure:
|
case types.MisconfStatusFailure:
|
||||||
rms.Failures = 1
|
rms.Failures = 1
|
||||||
case types.StatusException:
|
case types.MisconfStatusException:
|
||||||
rms.Exceptions = 1
|
rms.Exceptions = 1
|
||||||
}
|
}
|
||||||
return &rms
|
return &rms
|
||||||
|
|||||||
@@ -42,15 +42,15 @@ func TestMapSpecCheckIDToFilteredResults(t *testing.T) {
|
|||||||
Misconfigurations: []types.DetectedMisconfiguration{
|
Misconfigurations: []types.DetectedMisconfiguration{
|
||||||
{
|
{
|
||||||
AVDID: "AVD-KSV012",
|
AVDID: "AVD-KSV012",
|
||||||
Status: types.StatusFailure,
|
Status: types.MisconfStatusFailure,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
AVDID: "AVD-KSV013",
|
AVDID: "AVD-KSV013",
|
||||||
Status: types.StatusFailure,
|
Status: types.MisconfStatusFailure,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
AVDID: "AVD-1.2.31",
|
AVDID: "AVD-1.2.31",
|
||||||
Status: types.StatusFailure,
|
Status: types.MisconfStatusFailure,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -68,7 +68,7 @@ func TestMapSpecCheckIDToFilteredResults(t *testing.T) {
|
|||||||
Misconfigurations: []types.DetectedMisconfiguration{
|
Misconfigurations: []types.DetectedMisconfiguration{
|
||||||
{
|
{
|
||||||
AVDID: "AVD-KSV012",
|
AVDID: "AVD-KSV012",
|
||||||
Status: types.StatusFailure,
|
Status: types.MisconfStatusFailure,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -86,7 +86,7 @@ func TestMapSpecCheckIDToFilteredResults(t *testing.T) {
|
|||||||
Misconfigurations: []types.DetectedMisconfiguration{
|
Misconfigurations: []types.DetectedMisconfiguration{
|
||||||
{
|
{
|
||||||
AVDID: "AVD-1.2.31",
|
AVDID: "AVD-1.2.31",
|
||||||
Status: types.StatusFailure,
|
Status: types.MisconfStatusFailure,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -99,7 +99,7 @@ func TestMapSpecCheckIDToFilteredResults(t *testing.T) {
|
|||||||
result: types.Result{
|
result: types.Result{
|
||||||
Target: "target",
|
Target: "target",
|
||||||
Class: types.ClassSecret,
|
Class: types.ClassSecret,
|
||||||
Secrets: []ftypes.SecretFinding{
|
Secrets: []types.DetectedSecret{
|
||||||
{
|
{
|
||||||
RuleID: "aws-access-key-id",
|
RuleID: "aws-access-key-id",
|
||||||
Category: secret.CategoryAWS,
|
Category: secret.CategoryAWS,
|
||||||
@@ -135,7 +135,7 @@ func TestMapSpecCheckIDToFilteredResults(t *testing.T) {
|
|||||||
{
|
{
|
||||||
Target: "target",
|
Target: "target",
|
||||||
Class: types.ClassSecret,
|
Class: types.ClassSecret,
|
||||||
Secrets: []ftypes.SecretFinding{
|
Secrets: []types.DetectedSecret{
|
||||||
{
|
{
|
||||||
RuleID: "aws-access-key-id",
|
RuleID: "aws-access-key-id",
|
||||||
Category: secret.CategoryAWS,
|
Category: secret.CategoryAWS,
|
||||||
|
|||||||
@@ -101,6 +101,11 @@ var (
|
|||||||
ConfigName: "scan.compliance",
|
ConfigName: "scan.compliance",
|
||||||
Usage: "compliance report to generate",
|
Usage: "compliance report to generate",
|
||||||
}
|
}
|
||||||
|
ShowSuppressedFlag = Flag[bool]{
|
||||||
|
Name: "show-suppressed",
|
||||||
|
ConfigName: "scan.show-suppressed",
|
||||||
|
Usage: "[EXPERIMENTAL] show suppressed vulnerabilities",
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
// ReportFlagGroup composes common printer flag structs
|
// ReportFlagGroup composes common printer flag structs
|
||||||
@@ -119,6 +124,7 @@ type ReportFlagGroup struct {
|
|||||||
OutputPluginArg *Flag[string]
|
OutputPluginArg *Flag[string]
|
||||||
Severity *Flag[[]string]
|
Severity *Flag[[]string]
|
||||||
Compliance *Flag[string]
|
Compliance *Flag[string]
|
||||||
|
ShowSuppressed *Flag[bool]
|
||||||
}
|
}
|
||||||
|
|
||||||
type ReportOptions struct {
|
type ReportOptions struct {
|
||||||
@@ -135,6 +141,7 @@ type ReportOptions struct {
|
|||||||
OutputPluginArgs []string
|
OutputPluginArgs []string
|
||||||
Severities []dbTypes.Severity
|
Severities []dbTypes.Severity
|
||||||
Compliance spec.ComplianceSpec
|
Compliance spec.ComplianceSpec
|
||||||
|
ShowSuppressed bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewReportFlagGroup() *ReportFlagGroup {
|
func NewReportFlagGroup() *ReportFlagGroup {
|
||||||
@@ -152,6 +159,7 @@ func NewReportFlagGroup() *ReportFlagGroup {
|
|||||||
OutputPluginArg: OutputPluginArgFlag.Clone(),
|
OutputPluginArg: OutputPluginArgFlag.Clone(),
|
||||||
Severity: SeverityFlag.Clone(),
|
Severity: SeverityFlag.Clone(),
|
||||||
Compliance: ComplianceFlag.Clone(),
|
Compliance: ComplianceFlag.Clone(),
|
||||||
|
ShowSuppressed: ShowSuppressedFlag.Clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -174,6 +182,7 @@ func (f *ReportFlagGroup) Flags() []Flagger {
|
|||||||
f.OutputPluginArg,
|
f.OutputPluginArg,
|
||||||
f.Severity,
|
f.Severity,
|
||||||
f.Compliance,
|
f.Compliance,
|
||||||
|
f.ShowSuppressed,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -247,6 +256,7 @@ func (f *ReportFlagGroup) ToOptions() (ReportOptions, error) {
|
|||||||
OutputPluginArgs: outputPluginArgs,
|
OutputPluginArgs: outputPluginArgs,
|
||||||
Severities: toSeverity(f.Severity.Value()),
|
Severities: toSeverity(f.Severity.Value()),
|
||||||
Compliance: cs,
|
Compliance: cs,
|
||||||
|
ShowSuppressed: f.ShowSuppressed.Value(),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import (
|
|||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
|
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
|
||||||
ftypes "github.com/aquasecurity/trivy/pkg/fanal/types"
|
|
||||||
"github.com/aquasecurity/trivy/pkg/types"
|
"github.com/aquasecurity/trivy/pkg/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -28,37 +27,37 @@ var (
|
|||||||
Misconfigurations: []types.DetectedMisconfiguration{
|
Misconfigurations: []types.DetectedMisconfiguration{
|
||||||
{
|
{
|
||||||
ID: "ID100",
|
ID: "ID100",
|
||||||
Status: types.StatusFailure,
|
Status: types.MisconfStatusFailure,
|
||||||
Severity: "LOW",
|
Severity: "LOW",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ID: "ID101",
|
ID: "ID101",
|
||||||
Status: types.StatusFailure,
|
Status: types.MisconfStatusFailure,
|
||||||
Severity: "MEDIUM",
|
Severity: "MEDIUM",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ID: "ID102",
|
ID: "ID102",
|
||||||
Status: types.StatusFailure,
|
Status: types.MisconfStatusFailure,
|
||||||
Severity: "HIGH",
|
Severity: "HIGH",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ID: "ID103",
|
ID: "ID103",
|
||||||
Status: types.StatusFailure,
|
Status: types.MisconfStatusFailure,
|
||||||
Severity: "CRITICAL",
|
Severity: "CRITICAL",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ID: "ID104",
|
ID: "ID104",
|
||||||
Status: types.StatusFailure,
|
Status: types.MisconfStatusFailure,
|
||||||
Severity: "UNKNOWN",
|
Severity: "UNKNOWN",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ID: "ID105",
|
ID: "ID105",
|
||||||
Status: types.StatusFailure,
|
Status: types.MisconfStatusFailure,
|
||||||
Severity: "LOW",
|
Severity: "LOW",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ID: "ID106",
|
ID: "ID106",
|
||||||
Status: types.StatusFailure,
|
Status: types.MisconfStatusFailure,
|
||||||
Severity: "HIGH",
|
Severity: "HIGH",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -131,37 +130,37 @@ var (
|
|||||||
Misconfigurations: []types.DetectedMisconfiguration{
|
Misconfigurations: []types.DetectedMisconfiguration{
|
||||||
{
|
{
|
||||||
ID: "ID100",
|
ID: "ID100",
|
||||||
Status: types.StatusFailure,
|
Status: types.MisconfStatusFailure,
|
||||||
Severity: "LOW",
|
Severity: "LOW",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ID: "ID101",
|
ID: "ID101",
|
||||||
Status: types.StatusFailure,
|
Status: types.MisconfStatusFailure,
|
||||||
Severity: "MEDIUM",
|
Severity: "MEDIUM",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ID: "ID102",
|
ID: "ID102",
|
||||||
Status: types.StatusFailure,
|
Status: types.MisconfStatusFailure,
|
||||||
Severity: "HIGH",
|
Severity: "HIGH",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ID: "ID103",
|
ID: "ID103",
|
||||||
Status: types.StatusFailure,
|
Status: types.MisconfStatusFailure,
|
||||||
Severity: "CRITICAL",
|
Severity: "CRITICAL",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ID: "ID104",
|
ID: "ID104",
|
||||||
Status: types.StatusFailure,
|
Status: types.MisconfStatusFailure,
|
||||||
Severity: "UNKNOWN",
|
Severity: "UNKNOWN",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ID: "ID105",
|
ID: "ID105",
|
||||||
Status: types.StatusFailure,
|
Status: types.MisconfStatusFailure,
|
||||||
Severity: "LOW",
|
Severity: "LOW",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ID: "ID106",
|
ID: "ID106",
|
||||||
Status: types.StatusFailure,
|
Status: types.MisconfStatusFailure,
|
||||||
Severity: "HIGH",
|
Severity: "HIGH",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -244,7 +243,7 @@ var (
|
|||||||
Misconfigurations: []types.DetectedMisconfiguration{
|
Misconfigurations: []types.DetectedMisconfiguration{
|
||||||
{
|
{
|
||||||
ID: "ID100",
|
ID: "ID100",
|
||||||
Status: types.StatusFailure,
|
Status: types.MisconfStatusFailure,
|
||||||
Severity: "MEDIUM",
|
Severity: "MEDIUM",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -258,7 +257,7 @@ var (
|
|||||||
Name: "lua",
|
Name: "lua",
|
||||||
Results: types.Results{
|
Results: types.Results{
|
||||||
{
|
{
|
||||||
Secrets: []ftypes.SecretFinding{
|
Secrets: []types.DetectedSecret{
|
||||||
{
|
{
|
||||||
RuleID: "secret1",
|
RuleID: "secret1",
|
||||||
Severity: "CRITICAL",
|
Severity: "CRITICAL",
|
||||||
@@ -281,28 +280,28 @@ var (
|
|||||||
Misconfigurations: []types.DetectedMisconfiguration{
|
Misconfigurations: []types.DetectedMisconfiguration{
|
||||||
{
|
{
|
||||||
ID: "KSV-ID100",
|
ID: "KSV-ID100",
|
||||||
Status: types.StatusFailure,
|
Status: types.MisconfStatusFailure,
|
||||||
Severity: "LOW",
|
Severity: "LOW",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ID: "KSV-ID101",
|
ID: "KSV-ID101",
|
||||||
Status: types.StatusFailure,
|
Status: types.MisconfStatusFailure,
|
||||||
Severity: "MEDIUM",
|
Severity: "MEDIUM",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ID: "KSV-ID102",
|
ID: "KSV-ID102",
|
||||||
Status: types.StatusFailure,
|
Status: types.MisconfStatusFailure,
|
||||||
Severity: "HIGH",
|
Severity: "HIGH",
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
ID: "KCV-ID100",
|
ID: "KCV-ID100",
|
||||||
Status: types.StatusFailure,
|
Status: types.MisconfStatusFailure,
|
||||||
Severity: "LOW",
|
Severity: "LOW",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ID: "KCV-ID101",
|
ID: "KCV-ID101",
|
||||||
Status: types.StatusFailure,
|
Status: types.MisconfStatusFailure,
|
||||||
Severity: "MEDIUM",
|
Severity: "MEDIUM",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package report
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"io"
|
"io"
|
||||||
"sync"
|
|
||||||
|
|
||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
@@ -50,7 +49,6 @@ func (tw TableWriter) Write(ctx context.Context, report Report) error {
|
|||||||
t := pkgReport.Writer{
|
t := pkgReport.Writer{
|
||||||
Output: tw.Output,
|
Output: tw.Output,
|
||||||
Severities: tw.Severities,
|
Severities: tw.Severities,
|
||||||
ShowMessageOnce: &sync.Once{},
|
|
||||||
}
|
}
|
||||||
for _, r := range report.Resources {
|
for _, r := range report.Resources {
|
||||||
if r.Report.Results.Failed() {
|
if r.Report.Results.Failed() {
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import (
|
|||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
|
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
|
||||||
ftypes "github.com/aquasecurity/trivy/pkg/fanal/types"
|
|
||||||
"github.com/aquasecurity/trivy/pkg/k8s/report"
|
"github.com/aquasecurity/trivy/pkg/k8s/report"
|
||||||
"github.com/aquasecurity/trivy/pkg/types"
|
"github.com/aquasecurity/trivy/pkg/types"
|
||||||
)
|
)
|
||||||
@@ -38,7 +37,7 @@ var (
|
|||||||
Misconfigurations: []types.DetectedMisconfiguration{
|
Misconfigurations: []types.DetectedMisconfiguration{
|
||||||
{
|
{
|
||||||
ID: "ID100",
|
ID: "ID100",
|
||||||
Status: types.StatusFailure,
|
Status: types.MisconfStatusFailure,
|
||||||
Severity: "MEDIUM",
|
Severity: "MEDIUM",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -54,28 +53,28 @@ var (
|
|||||||
Misconfigurations: []types.DetectedMisconfiguration{
|
Misconfigurations: []types.DetectedMisconfiguration{
|
||||||
{
|
{
|
||||||
ID: "KSV-ID100",
|
ID: "KSV-ID100",
|
||||||
Status: types.StatusFailure,
|
Status: types.MisconfStatusFailure,
|
||||||
Severity: "LOW",
|
Severity: "LOW",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ID: "KSV-ID101",
|
ID: "KSV-ID101",
|
||||||
Status: types.StatusFailure,
|
Status: types.MisconfStatusFailure,
|
||||||
Severity: "MEDIUM",
|
Severity: "MEDIUM",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ID: "KSV-ID102",
|
ID: "KSV-ID102",
|
||||||
Status: types.StatusFailure,
|
Status: types.MisconfStatusFailure,
|
||||||
Severity: "HIGH",
|
Severity: "HIGH",
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
ID: "KCV-ID100",
|
ID: "KCV-ID100",
|
||||||
Status: types.StatusFailure,
|
Status: types.MisconfStatusFailure,
|
||||||
Severity: "LOW",
|
Severity: "LOW",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ID: "KCV-ID101",
|
ID: "KCV-ID101",
|
||||||
Status: types.StatusFailure,
|
Status: types.MisconfStatusFailure,
|
||||||
Severity: "MEDIUM",
|
Severity: "MEDIUM",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -88,7 +87,7 @@ var (
|
|||||||
Name: "lua",
|
Name: "lua",
|
||||||
Results: types.Results{
|
Results: types.Results{
|
||||||
{
|
{
|
||||||
Secrets: []ftypes.SecretFinding{
|
Secrets: []types.DetectedSecret{
|
||||||
{
|
{
|
||||||
RuleID: "secret1",
|
RuleID: "secret1",
|
||||||
Severity: "CRITICAL",
|
Severity: "CRITICAL",
|
||||||
@@ -110,37 +109,37 @@ var (
|
|||||||
Misconfigurations: []types.DetectedMisconfiguration{
|
Misconfigurations: []types.DetectedMisconfiguration{
|
||||||
{
|
{
|
||||||
ID: "ID100",
|
ID: "ID100",
|
||||||
Status: types.StatusFailure,
|
Status: types.MisconfStatusFailure,
|
||||||
Severity: "LOW",
|
Severity: "LOW",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ID: "ID101",
|
ID: "ID101",
|
||||||
Status: types.StatusFailure,
|
Status: types.MisconfStatusFailure,
|
||||||
Severity: "MEDIUM",
|
Severity: "MEDIUM",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ID: "ID102",
|
ID: "ID102",
|
||||||
Status: types.StatusFailure,
|
Status: types.MisconfStatusFailure,
|
||||||
Severity: "HIGH",
|
Severity: "HIGH",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ID: "ID103",
|
ID: "ID103",
|
||||||
Status: types.StatusFailure,
|
Status: types.MisconfStatusFailure,
|
||||||
Severity: "CRITICAL",
|
Severity: "CRITICAL",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ID: "ID104",
|
ID: "ID104",
|
||||||
Status: types.StatusFailure,
|
Status: types.MisconfStatusFailure,
|
||||||
Severity: "UNKNOWN",
|
Severity: "UNKNOWN",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ID: "ID105",
|
ID: "ID105",
|
||||||
Status: types.StatusFailure,
|
Status: types.MisconfStatusFailure,
|
||||||
Severity: "LOW",
|
Severity: "LOW",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ID: "ID106",
|
ID: "ID106",
|
||||||
Status: types.StatusFailure,
|
Status: types.MisconfStatusFailure,
|
||||||
Severity: "HIGH",
|
Severity: "HIGH",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -266,16 +266,16 @@ func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgModuleSerialize2(in *jle
|
|||||||
in.Delim('[')
|
in.Delim('[')
|
||||||
if out.Secrets == nil {
|
if out.Secrets == nil {
|
||||||
if !in.IsDelim(']') {
|
if !in.IsDelim(']') {
|
||||||
out.Secrets = make([]types1.SecretFinding, 0, 0)
|
out.Secrets = make([]types.DetectedSecret, 0, 0)
|
||||||
} else {
|
} else {
|
||||||
out.Secrets = []types1.SecretFinding{}
|
out.Secrets = []types.DetectedSecret{}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
out.Secrets = (out.Secrets)[:0]
|
out.Secrets = (out.Secrets)[:0]
|
||||||
}
|
}
|
||||||
for !in.IsDelim(']') {
|
for !in.IsDelim(']') {
|
||||||
var v10 types1.SecretFinding
|
var v10 types.DetectedSecret
|
||||||
easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes1(in, &v10)
|
easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgTypes3(in, &v10)
|
||||||
out.Secrets = append(out.Secrets, v10)
|
out.Secrets = append(out.Secrets, v10)
|
||||||
in.WantComma()
|
in.WantComma()
|
||||||
}
|
}
|
||||||
@@ -298,7 +298,7 @@ func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgModuleSerialize2(in *jle
|
|||||||
}
|
}
|
||||||
for !in.IsDelim(']') {
|
for !in.IsDelim(']') {
|
||||||
var v11 types.DetectedLicense
|
var v11 types.DetectedLicense
|
||||||
easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgTypes3(in, &v11)
|
easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgTypes4(in, &v11)
|
||||||
out.Licenses = append(out.Licenses, v11)
|
out.Licenses = append(out.Licenses, v11)
|
||||||
in.WantComma()
|
in.WantComma()
|
||||||
}
|
}
|
||||||
@@ -321,7 +321,7 @@ func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgModuleSerialize2(in *jle
|
|||||||
}
|
}
|
||||||
for !in.IsDelim(']') {
|
for !in.IsDelim(']') {
|
||||||
var v12 types1.CustomResource
|
var v12 types1.CustomResource
|
||||||
easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes2(in, &v12)
|
easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes1(in, &v12)
|
||||||
out.CustomResources = append(out.CustomResources, v12)
|
out.CustomResources = append(out.CustomResources, v12)
|
||||||
in.WantComma()
|
in.WantComma()
|
||||||
}
|
}
|
||||||
@@ -412,7 +412,7 @@ func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgModuleSerialize2(out *jw
|
|||||||
if v19 > 0 {
|
if v19 > 0 {
|
||||||
out.RawByte(',')
|
out.RawByte(',')
|
||||||
}
|
}
|
||||||
easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes1(out, v20)
|
easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgTypes3(out, v20)
|
||||||
}
|
}
|
||||||
out.RawByte(']')
|
out.RawByte(']')
|
||||||
}
|
}
|
||||||
@@ -426,7 +426,7 @@ func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgModuleSerialize2(out *jw
|
|||||||
if v21 > 0 {
|
if v21 > 0 {
|
||||||
out.RawByte(',')
|
out.RawByte(',')
|
||||||
}
|
}
|
||||||
easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgTypes3(out, v22)
|
easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgTypes4(out, v22)
|
||||||
}
|
}
|
||||||
out.RawByte(']')
|
out.RawByte(']')
|
||||||
}
|
}
|
||||||
@@ -440,7 +440,7 @@ func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgModuleSerialize2(out *jw
|
|||||||
if v23 > 0 {
|
if v23 > 0 {
|
||||||
out.RawByte(',')
|
out.RawByte(',')
|
||||||
}
|
}
|
||||||
easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes2(out, v24)
|
easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes1(out, v24)
|
||||||
}
|
}
|
||||||
out.RawByte(']')
|
out.RawByte(']')
|
||||||
}
|
}
|
||||||
@@ -471,7 +471,7 @@ func (v *Result) UnmarshalJSON(data []byte) error {
|
|||||||
func (v *Result) UnmarshalEasyJSON(l *jlexer.Lexer) {
|
func (v *Result) UnmarshalEasyJSON(l *jlexer.Lexer) {
|
||||||
easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgModuleSerialize2(l, v)
|
easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgModuleSerialize2(l, v)
|
||||||
}
|
}
|
||||||
func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes2(in *jlexer.Lexer, out *types1.CustomResource) {
|
func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes1(in *jlexer.Lexer, out *types1.CustomResource) {
|
||||||
isTopLevel := in.IsStart()
|
isTopLevel := in.IsStart()
|
||||||
if in.IsNull() {
|
if in.IsNull() {
|
||||||
if isTopLevel {
|
if isTopLevel {
|
||||||
@@ -495,7 +495,7 @@ func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes2(in *jlexer.L
|
|||||||
case "FilePath":
|
case "FilePath":
|
||||||
out.FilePath = string(in.String())
|
out.FilePath = string(in.String())
|
||||||
case "Layer":
|
case "Layer":
|
||||||
easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes3(in, &out.Layer)
|
easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes2(in, &out.Layer)
|
||||||
case "Data":
|
case "Data":
|
||||||
if m, ok := out.Data.(easyjson.Unmarshaler); ok {
|
if m, ok := out.Data.(easyjson.Unmarshaler); ok {
|
||||||
m.UnmarshalEasyJSON(in)
|
m.UnmarshalEasyJSON(in)
|
||||||
@@ -514,7 +514,7 @@ func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes2(in *jlexer.L
|
|||||||
in.Consumed()
|
in.Consumed()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes2(out *jwriter.Writer, in types1.CustomResource) {
|
func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes1(out *jwriter.Writer, in types1.CustomResource) {
|
||||||
out.RawByte('{')
|
out.RawByte('{')
|
||||||
first := true
|
first := true
|
||||||
_ = first
|
_ = first
|
||||||
@@ -531,7 +531,7 @@ func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes2(out *jwriter
|
|||||||
{
|
{
|
||||||
const prefix string = ",\"Layer\":"
|
const prefix string = ",\"Layer\":"
|
||||||
out.RawString(prefix)
|
out.RawString(prefix)
|
||||||
easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes3(out, in.Layer)
|
easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes2(out, in.Layer)
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
const prefix string = ",\"Data\":"
|
const prefix string = ",\"Data\":"
|
||||||
@@ -546,7 +546,7 @@ func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes2(out *jwriter
|
|||||||
}
|
}
|
||||||
out.RawByte('}')
|
out.RawByte('}')
|
||||||
}
|
}
|
||||||
func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes3(in *jlexer.Lexer, out *types1.Layer) {
|
func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes2(in *jlexer.Lexer, out *types1.Layer) {
|
||||||
isTopLevel := in.IsStart()
|
isTopLevel := in.IsStart()
|
||||||
if in.IsNull() {
|
if in.IsNull() {
|
||||||
if isTopLevel {
|
if isTopLevel {
|
||||||
@@ -581,7 +581,7 @@ func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes3(in *jlexer.L
|
|||||||
in.Consumed()
|
in.Consumed()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes3(out *jwriter.Writer, in types1.Layer) {
|
func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes2(out *jwriter.Writer, in types1.Layer) {
|
||||||
out.RawByte('{')
|
out.RawByte('{')
|
||||||
first := true
|
first := true
|
||||||
_ = first
|
_ = first
|
||||||
@@ -613,7 +613,7 @@ func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes3(out *jwriter
|
|||||||
}
|
}
|
||||||
out.RawByte('}')
|
out.RawByte('}')
|
||||||
}
|
}
|
||||||
func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgTypes3(in *jlexer.Lexer, out *types.DetectedLicense) {
|
func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgTypes4(in *jlexer.Lexer, out *types.DetectedLicense) {
|
||||||
isTopLevel := in.IsStart()
|
isTopLevel := in.IsStart()
|
||||||
if in.IsNull() {
|
if in.IsNull() {
|
||||||
if isTopLevel {
|
if isTopLevel {
|
||||||
@@ -656,7 +656,7 @@ func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgTypes3(in *jlexer.Lexer,
|
|||||||
in.Consumed()
|
in.Consumed()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgTypes3(out *jwriter.Writer, in types.DetectedLicense) {
|
func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgTypes4(out *jwriter.Writer, in types.DetectedLicense) {
|
||||||
out.RawByte('{')
|
out.RawByte('{')
|
||||||
first := true
|
first := true
|
||||||
_ = first
|
_ = first
|
||||||
@@ -697,7 +697,7 @@ func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgTypes3(out *jwriter.Writ
|
|||||||
}
|
}
|
||||||
out.RawByte('}')
|
out.RawByte('}')
|
||||||
}
|
}
|
||||||
func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes1(in *jlexer.Lexer, out *types1.SecretFinding) {
|
func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgTypes3(in *jlexer.Lexer, out *types.DetectedSecret) {
|
||||||
isTopLevel := in.IsStart()
|
isTopLevel := in.IsStart()
|
||||||
if in.IsNull() {
|
if in.IsNull() {
|
||||||
if isTopLevel {
|
if isTopLevel {
|
||||||
@@ -729,11 +729,11 @@ func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes1(in *jlexer.L
|
|||||||
case "EndLine":
|
case "EndLine":
|
||||||
out.EndLine = int(in.Int())
|
out.EndLine = int(in.Int())
|
||||||
case "Code":
|
case "Code":
|
||||||
easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes4(in, &out.Code)
|
easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes3(in, &out.Code)
|
||||||
case "Match":
|
case "Match":
|
||||||
out.Match = string(in.String())
|
out.Match = string(in.String())
|
||||||
case "Layer":
|
case "Layer":
|
||||||
easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes3(in, &out.Layer)
|
easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes2(in, &out.Layer)
|
||||||
default:
|
default:
|
||||||
in.SkipRecursive()
|
in.SkipRecursive()
|
||||||
}
|
}
|
||||||
@@ -744,7 +744,7 @@ func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes1(in *jlexer.L
|
|||||||
in.Consumed()
|
in.Consumed()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes1(out *jwriter.Writer, in types1.SecretFinding) {
|
func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgTypes3(out *jwriter.Writer, in types.DetectedSecret) {
|
||||||
out.RawByte('{')
|
out.RawByte('{')
|
||||||
first := true
|
first := true
|
||||||
_ = first
|
_ = first
|
||||||
@@ -781,7 +781,7 @@ func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes1(out *jwriter
|
|||||||
{
|
{
|
||||||
const prefix string = ",\"Code\":"
|
const prefix string = ",\"Code\":"
|
||||||
out.RawString(prefix)
|
out.RawString(prefix)
|
||||||
easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes4(out, in.Code)
|
easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes3(out, in.Code)
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
const prefix string = ",\"Match\":"
|
const prefix string = ",\"Match\":"
|
||||||
@@ -791,11 +791,11 @@ func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes1(out *jwriter
|
|||||||
if true {
|
if true {
|
||||||
const prefix string = ",\"Layer\":"
|
const prefix string = ",\"Layer\":"
|
||||||
out.RawString(prefix)
|
out.RawString(prefix)
|
||||||
easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes3(out, in.Layer)
|
easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes2(out, in.Layer)
|
||||||
}
|
}
|
||||||
out.RawByte('}')
|
out.RawByte('}')
|
||||||
}
|
}
|
||||||
func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes4(in *jlexer.Lexer, out *types1.Code) {
|
func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes3(in *jlexer.Lexer, out *types1.Code) {
|
||||||
isTopLevel := in.IsStart()
|
isTopLevel := in.IsStart()
|
||||||
if in.IsNull() {
|
if in.IsNull() {
|
||||||
if isTopLevel {
|
if isTopLevel {
|
||||||
@@ -831,7 +831,7 @@ func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes4(in *jlexer.L
|
|||||||
}
|
}
|
||||||
for !in.IsDelim(']') {
|
for !in.IsDelim(']') {
|
||||||
var v25 types1.Line
|
var v25 types1.Line
|
||||||
easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes5(in, &v25)
|
easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes4(in, &v25)
|
||||||
out.Lines = append(out.Lines, v25)
|
out.Lines = append(out.Lines, v25)
|
||||||
in.WantComma()
|
in.WantComma()
|
||||||
}
|
}
|
||||||
@@ -847,7 +847,7 @@ func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes4(in *jlexer.L
|
|||||||
in.Consumed()
|
in.Consumed()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes4(out *jwriter.Writer, in types1.Code) {
|
func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes3(out *jwriter.Writer, in types1.Code) {
|
||||||
out.RawByte('{')
|
out.RawByte('{')
|
||||||
first := true
|
first := true
|
||||||
_ = first
|
_ = first
|
||||||
@@ -862,14 +862,14 @@ func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes4(out *jwriter
|
|||||||
if v26 > 0 {
|
if v26 > 0 {
|
||||||
out.RawByte(',')
|
out.RawByte(',')
|
||||||
}
|
}
|
||||||
easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes5(out, v27)
|
easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes4(out, v27)
|
||||||
}
|
}
|
||||||
out.RawByte(']')
|
out.RawByte(']')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
out.RawByte('}')
|
out.RawByte('}')
|
||||||
}
|
}
|
||||||
func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes5(in *jlexer.Lexer, out *types1.Line) {
|
func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes4(in *jlexer.Lexer, out *types1.Line) {
|
||||||
isTopLevel := in.IsStart()
|
isTopLevel := in.IsStart()
|
||||||
if in.IsNull() {
|
if in.IsNull() {
|
||||||
if isTopLevel {
|
if isTopLevel {
|
||||||
@@ -914,7 +914,7 @@ func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes5(in *jlexer.L
|
|||||||
in.Consumed()
|
in.Consumed()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes5(out *jwriter.Writer, in types1.Line) {
|
func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes4(out *jwriter.Writer, in types1.Line) {
|
||||||
out.RawByte('{')
|
out.RawByte('{')
|
||||||
first := true
|
first := true
|
||||||
_ = first
|
_ = first
|
||||||
@@ -1027,9 +1027,9 @@ func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgTypes2(in *jlexer.Lexer,
|
|||||||
case "Status":
|
case "Status":
|
||||||
out.Status = types.MisconfStatus(in.String())
|
out.Status = types.MisconfStatus(in.String())
|
||||||
case "Layer":
|
case "Layer":
|
||||||
easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes3(in, &out.Layer)
|
easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes2(in, &out.Layer)
|
||||||
case "CauseMetadata":
|
case "CauseMetadata":
|
||||||
easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes6(in, &out.CauseMetadata)
|
easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes5(in, &out.CauseMetadata)
|
||||||
case "Traces":
|
case "Traces":
|
||||||
if in.IsNull() {
|
if in.IsNull() {
|
||||||
in.Skip()
|
in.Skip()
|
||||||
@@ -1210,7 +1210,7 @@ func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgTypes2(out *jwriter.Writ
|
|||||||
} else {
|
} else {
|
||||||
out.RawString(prefix)
|
out.RawString(prefix)
|
||||||
}
|
}
|
||||||
easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes3(out, in.Layer)
|
easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes2(out, in.Layer)
|
||||||
}
|
}
|
||||||
if true {
|
if true {
|
||||||
const prefix string = ",\"CauseMetadata\":"
|
const prefix string = ",\"CauseMetadata\":"
|
||||||
@@ -1220,7 +1220,7 @@ func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgTypes2(out *jwriter.Writ
|
|||||||
} else {
|
} else {
|
||||||
out.RawString(prefix)
|
out.RawString(prefix)
|
||||||
}
|
}
|
||||||
easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes6(out, in.CauseMetadata)
|
easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes5(out, in.CauseMetadata)
|
||||||
}
|
}
|
||||||
if len(in.Traces) != 0 {
|
if len(in.Traces) != 0 {
|
||||||
const prefix string = ",\"Traces\":"
|
const prefix string = ",\"Traces\":"
|
||||||
@@ -1243,7 +1243,7 @@ func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgTypes2(out *jwriter.Writ
|
|||||||
}
|
}
|
||||||
out.RawByte('}')
|
out.RawByte('}')
|
||||||
}
|
}
|
||||||
func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes6(in *jlexer.Lexer, out *types1.CauseMetadata) {
|
func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes5(in *jlexer.Lexer, out *types1.CauseMetadata) {
|
||||||
isTopLevel := in.IsStart()
|
isTopLevel := in.IsStart()
|
||||||
if in.IsNull() {
|
if in.IsNull() {
|
||||||
if isTopLevel {
|
if isTopLevel {
|
||||||
@@ -1273,7 +1273,7 @@ func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes6(in *jlexer.L
|
|||||||
case "EndLine":
|
case "EndLine":
|
||||||
out.EndLine = int(in.Int())
|
out.EndLine = int(in.Int())
|
||||||
case "Code":
|
case "Code":
|
||||||
easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes4(in, &out.Code)
|
easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes3(in, &out.Code)
|
||||||
case "Occurrences":
|
case "Occurrences":
|
||||||
if in.IsNull() {
|
if in.IsNull() {
|
||||||
in.Skip()
|
in.Skip()
|
||||||
@@ -1291,7 +1291,7 @@ func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes6(in *jlexer.L
|
|||||||
}
|
}
|
||||||
for !in.IsDelim(']') {
|
for !in.IsDelim(']') {
|
||||||
var v34 types1.Occurrence
|
var v34 types1.Occurrence
|
||||||
easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes7(in, &v34)
|
easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes6(in, &v34)
|
||||||
out.Occurrences = append(out.Occurrences, v34)
|
out.Occurrences = append(out.Occurrences, v34)
|
||||||
in.WantComma()
|
in.WantComma()
|
||||||
}
|
}
|
||||||
@@ -1307,7 +1307,7 @@ func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes6(in *jlexer.L
|
|||||||
in.Consumed()
|
in.Consumed()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes6(out *jwriter.Writer, in types1.CauseMetadata) {
|
func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes5(out *jwriter.Writer, in types1.CauseMetadata) {
|
||||||
out.RawByte('{')
|
out.RawByte('{')
|
||||||
first := true
|
first := true
|
||||||
_ = first
|
_ = first
|
||||||
@@ -1365,7 +1365,7 @@ func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes6(out *jwriter
|
|||||||
} else {
|
} else {
|
||||||
out.RawString(prefix)
|
out.RawString(prefix)
|
||||||
}
|
}
|
||||||
easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes4(out, in.Code)
|
easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes3(out, in.Code)
|
||||||
}
|
}
|
||||||
if len(in.Occurrences) != 0 {
|
if len(in.Occurrences) != 0 {
|
||||||
const prefix string = ",\"Occurrences\":"
|
const prefix string = ",\"Occurrences\":"
|
||||||
@@ -1381,14 +1381,14 @@ func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes6(out *jwriter
|
|||||||
if v35 > 0 {
|
if v35 > 0 {
|
||||||
out.RawByte(',')
|
out.RawByte(',')
|
||||||
}
|
}
|
||||||
easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes7(out, v36)
|
easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes6(out, v36)
|
||||||
}
|
}
|
||||||
out.RawByte(']')
|
out.RawByte(']')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
out.RawByte('}')
|
out.RawByte('}')
|
||||||
}
|
}
|
||||||
func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes7(in *jlexer.Lexer, out *types1.Occurrence) {
|
func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes6(in *jlexer.Lexer, out *types1.Occurrence) {
|
||||||
isTopLevel := in.IsStart()
|
isTopLevel := in.IsStart()
|
||||||
if in.IsNull() {
|
if in.IsNull() {
|
||||||
if isTopLevel {
|
if isTopLevel {
|
||||||
@@ -1412,7 +1412,7 @@ func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes7(in *jlexer.L
|
|||||||
case "Filename":
|
case "Filename":
|
||||||
out.Filename = string(in.String())
|
out.Filename = string(in.String())
|
||||||
case "Location":
|
case "Location":
|
||||||
easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes8(in, &out.Location)
|
easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes7(in, &out.Location)
|
||||||
default:
|
default:
|
||||||
in.SkipRecursive()
|
in.SkipRecursive()
|
||||||
}
|
}
|
||||||
@@ -1423,7 +1423,7 @@ func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes7(in *jlexer.L
|
|||||||
in.Consumed()
|
in.Consumed()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes7(out *jwriter.Writer, in types1.Occurrence) {
|
func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes6(out *jwriter.Writer, in types1.Occurrence) {
|
||||||
out.RawByte('{')
|
out.RawByte('{')
|
||||||
first := true
|
first := true
|
||||||
_ = first
|
_ = first
|
||||||
@@ -1451,11 +1451,11 @@ func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes7(out *jwriter
|
|||||||
} else {
|
} else {
|
||||||
out.RawString(prefix)
|
out.RawString(prefix)
|
||||||
}
|
}
|
||||||
easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes8(out, in.Location)
|
easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes7(out, in.Location)
|
||||||
}
|
}
|
||||||
out.RawByte('}')
|
out.RawByte('}')
|
||||||
}
|
}
|
||||||
func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes8(in *jlexer.Lexer, out *types1.Location) {
|
func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes7(in *jlexer.Lexer, out *types1.Location) {
|
||||||
isTopLevel := in.IsStart()
|
isTopLevel := in.IsStart()
|
||||||
if in.IsNull() {
|
if in.IsNull() {
|
||||||
if isTopLevel {
|
if isTopLevel {
|
||||||
@@ -1488,7 +1488,7 @@ func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes8(in *jlexer.L
|
|||||||
in.Consumed()
|
in.Consumed()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes8(out *jwriter.Writer, in types1.Location) {
|
func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes7(out *jwriter.Writer, in types1.Location) {
|
||||||
out.RawByte('{')
|
out.RawByte('{')
|
||||||
first := true
|
first := true
|
||||||
_ = first
|
_ = first
|
||||||
@@ -1629,7 +1629,7 @@ func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgTypes(in *jlexer.Lexer,
|
|||||||
in.AddError((out.Status).UnmarshalJSON(data))
|
in.AddError((out.Status).UnmarshalJSON(data))
|
||||||
}
|
}
|
||||||
case "Layer":
|
case "Layer":
|
||||||
easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes3(in, &out.Layer)
|
easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes2(in, &out.Layer)
|
||||||
case "SeveritySource":
|
case "SeveritySource":
|
||||||
out.SeveritySource = types2.SourceID(in.String())
|
out.SeveritySource = types2.SourceID(in.String())
|
||||||
case "PrimaryURL":
|
case "PrimaryURL":
|
||||||
@@ -1885,7 +1885,7 @@ func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgTypes(out *jwriter.Write
|
|||||||
} else {
|
} else {
|
||||||
out.RawString(prefix)
|
out.RawString(prefix)
|
||||||
}
|
}
|
||||||
easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes3(out, in.Layer)
|
easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes2(out, in.Layer)
|
||||||
}
|
}
|
||||||
if in.SeveritySource != "" {
|
if in.SeveritySource != "" {
|
||||||
const prefix string = ",\"SeveritySource\":"
|
const prefix string = ",\"SeveritySource\":"
|
||||||
@@ -2297,7 +2297,7 @@ func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes(in *jlexer.Le
|
|||||||
if out.BuildInfo == nil {
|
if out.BuildInfo == nil {
|
||||||
out.BuildInfo = new(types1.BuildInfo)
|
out.BuildInfo = new(types1.BuildInfo)
|
||||||
}
|
}
|
||||||
easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes9(in, out.BuildInfo)
|
easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes8(in, out.BuildInfo)
|
||||||
}
|
}
|
||||||
case "Indirect":
|
case "Indirect":
|
||||||
out.Indirect = bool(in.Bool())
|
out.Indirect = bool(in.Bool())
|
||||||
@@ -2325,7 +2325,7 @@ func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes(in *jlexer.Le
|
|||||||
in.Delim(']')
|
in.Delim(']')
|
||||||
}
|
}
|
||||||
case "Layer":
|
case "Layer":
|
||||||
easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes3(in, &out.Layer)
|
easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes2(in, &out.Layer)
|
||||||
case "FilePath":
|
case "FilePath":
|
||||||
out.FilePath = string(in.String())
|
out.FilePath = string(in.String())
|
||||||
case "Digest":
|
case "Digest":
|
||||||
@@ -2347,7 +2347,7 @@ func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes(in *jlexer.Le
|
|||||||
}
|
}
|
||||||
for !in.IsDelim(']') {
|
for !in.IsDelim(']') {
|
||||||
var v52 types1.Location
|
var v52 types1.Location
|
||||||
easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes8(in, &v52)
|
easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes7(in, &v52)
|
||||||
out.Locations = append(out.Locations, v52)
|
out.Locations = append(out.Locations, v52)
|
||||||
in.WantComma()
|
in.WantComma()
|
||||||
}
|
}
|
||||||
@@ -2553,7 +2553,7 @@ func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes(out *jwriter.
|
|||||||
} else {
|
} else {
|
||||||
out.RawString(prefix)
|
out.RawString(prefix)
|
||||||
}
|
}
|
||||||
easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes9(out, *in.BuildInfo)
|
easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes8(out, *in.BuildInfo)
|
||||||
}
|
}
|
||||||
if in.Indirect {
|
if in.Indirect {
|
||||||
const prefix string = ",\"Indirect\":"
|
const prefix string = ",\"Indirect\":"
|
||||||
@@ -2592,7 +2592,7 @@ func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes(out *jwriter.
|
|||||||
} else {
|
} else {
|
||||||
out.RawString(prefix)
|
out.RawString(prefix)
|
||||||
}
|
}
|
||||||
easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes3(out, in.Layer)
|
easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes2(out, in.Layer)
|
||||||
}
|
}
|
||||||
if in.FilePath != "" {
|
if in.FilePath != "" {
|
||||||
const prefix string = ",\"FilePath\":"
|
const prefix string = ",\"FilePath\":"
|
||||||
@@ -2628,7 +2628,7 @@ func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes(out *jwriter.
|
|||||||
if v58 > 0 {
|
if v58 > 0 {
|
||||||
out.RawByte(',')
|
out.RawByte(',')
|
||||||
}
|
}
|
||||||
easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes8(out, v59)
|
easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes7(out, v59)
|
||||||
}
|
}
|
||||||
out.RawByte(']')
|
out.RawByte(']')
|
||||||
}
|
}
|
||||||
@@ -2654,7 +2654,7 @@ func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes(out *jwriter.
|
|||||||
}
|
}
|
||||||
out.RawByte('}')
|
out.RawByte('}')
|
||||||
}
|
}
|
||||||
func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes9(in *jlexer.Lexer, out *types1.BuildInfo) {
|
func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes8(in *jlexer.Lexer, out *types1.BuildInfo) {
|
||||||
isTopLevel := in.IsStart()
|
isTopLevel := in.IsStart()
|
||||||
if in.IsNull() {
|
if in.IsNull() {
|
||||||
if isTopLevel {
|
if isTopLevel {
|
||||||
@@ -2710,7 +2710,7 @@ func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes9(in *jlexer.L
|
|||||||
in.Consumed()
|
in.Consumed()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes9(out *jwriter.Writer, in types1.BuildInfo) {
|
func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes8(out *jwriter.Writer, in types1.BuildInfo) {
|
||||||
out.RawByte('{')
|
out.RawByte('{')
|
||||||
first := true
|
first := true
|
||||||
_ = first
|
_ = first
|
||||||
|
|||||||
@@ -197,7 +197,7 @@ func TestReportWriter_Sarif(t *testing.T) {
|
|||||||
Message: "Message",
|
Message: "Message",
|
||||||
Severity: "HIGH",
|
Severity: "HIGH",
|
||||||
PrimaryURL: "https://avd.aquasec.com/appshield/ksv001",
|
PrimaryURL: "https://avd.aquasec.com/appshield/ksv001",
|
||||||
Status: types.StatusFailure,
|
Status: types.MisconfStatusFailure,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Type: "Kubernetes Security Check",
|
Type: "Kubernetes Security Check",
|
||||||
@@ -206,7 +206,7 @@ func TestReportWriter_Sarif(t *testing.T) {
|
|||||||
Message: "Message",
|
Message: "Message",
|
||||||
Severity: "CRITICAL",
|
Severity: "CRITICAL",
|
||||||
PrimaryURL: "https://avd.aquasec.com/appshield/ksv002",
|
PrimaryURL: "https://avd.aquasec.com/appshield/ksv002",
|
||||||
Status: types.StatusPassed,
|
Status: types.MisconfStatusPassed,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -338,7 +338,7 @@ func TestReportWriter_Sarif(t *testing.T) {
|
|||||||
{
|
{
|
||||||
Target: "library/test",
|
Target: "library/test",
|
||||||
Class: types.ClassSecret,
|
Class: types.ClassSecret,
|
||||||
Secrets: []ftypes.SecretFinding{
|
Secrets: []types.DetectedSecret{
|
||||||
{
|
{
|
||||||
RuleID: "aws-secret-access-key",
|
RuleID: "aws-secret-access-key",
|
||||||
Category: "AWS",
|
Category: "AWS",
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ func (r *misconfigRenderer) Render() string {
|
|||||||
func (r *misconfigRenderer) countSeverities() map[string]int {
|
func (r *misconfigRenderer) countSeverities() map[string]int {
|
||||||
severityCount := make(map[string]int)
|
severityCount := make(map[string]int)
|
||||||
for _, misconf := range r.result.Misconfigurations {
|
for _, misconf := range r.result.Misconfigurations {
|
||||||
if misconf.Status == types.StatusFailure {
|
if misconf.Status == types.MisconfStatusFailure {
|
||||||
severityCount[misconf.Severity]++
|
severityCount[misconf.Severity]++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -110,11 +110,11 @@ func (r *misconfigRenderer) renderSummary(misconf types.DetectedMisconfiguration
|
|||||||
// show pass/fail/exception unless we are only showing failures
|
// show pass/fail/exception unless we are only showing failures
|
||||||
if r.includeNonFailures {
|
if r.includeNonFailures {
|
||||||
switch misconf.Status {
|
switch misconf.Status {
|
||||||
case types.StatusPassed:
|
case types.MisconfStatusPassed:
|
||||||
r.printf("<green><bold>%s: ", misconf.Status)
|
r.printf("<green><bold>%s: ", misconf.Status)
|
||||||
case types.StatusFailure:
|
case types.MisconfStatusFailure:
|
||||||
r.printf("<red><bold>%s: ", misconf.Status)
|
r.printf("<red><bold>%s: ", misconf.Status)
|
||||||
case types.StatusException:
|
case types.MisconfStatusException:
|
||||||
r.printf("<yellow><bold>%s: ", misconf.Status)
|
r.printf("<yellow><bold>%s: ", misconf.Status)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -217,7 +217,7 @@ func (r *misconfigRenderer) outputTrace() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
c := green
|
c := green
|
||||||
if misconf.Status == types.StatusFailure {
|
if misconf.Status == types.MisconfStatusFailure {
|
||||||
c = red
|
c = red
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,19 +9,19 @@ import (
|
|||||||
|
|
||||||
"github.com/aquasecurity/tml"
|
"github.com/aquasecurity/tml"
|
||||||
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
|
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
|
||||||
"github.com/aquasecurity/trivy/pkg/fanal/types"
|
"github.com/aquasecurity/trivy/pkg/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
type secretRenderer struct {
|
type secretRenderer struct {
|
||||||
w *bytes.Buffer
|
w *bytes.Buffer
|
||||||
target string
|
target string
|
||||||
secrets []types.SecretFinding
|
secrets []types.DetectedSecret
|
||||||
severities []dbTypes.Severity
|
severities []dbTypes.Severity
|
||||||
width int
|
width int
|
||||||
ansi bool
|
ansi bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewSecretRenderer(target string, secrets []types.SecretFinding, ansi bool, severities []dbTypes.Severity) *secretRenderer {
|
func NewSecretRenderer(target string, secrets []types.DetectedSecret, ansi bool, severities []dbTypes.Severity) *secretRenderer {
|
||||||
width, _, err := term.GetSize(0)
|
width, _, err := term.GetSize(0)
|
||||||
if err != nil || width == 0 {
|
if err != nil || width == 0 {
|
||||||
width = 40
|
width = 40
|
||||||
@@ -76,13 +76,13 @@ func (r *secretRenderer) printSingleDivider() {
|
|||||||
r.printf("<dim>%s\r\n", strings.Repeat("─", r.width))
|
r.printf("<dim>%s\r\n", strings.Repeat("─", r.width))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *secretRenderer) renderSingle(secret types.SecretFinding) {
|
func (r *secretRenderer) renderSingle(secret types.DetectedSecret) {
|
||||||
r.renderSummary(secret)
|
r.renderSummary(secret)
|
||||||
r.renderCode(secret)
|
r.renderCode(secret)
|
||||||
r.printf("\r\n\r\n")
|
r.printf("\r\n\r\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *secretRenderer) renderSummary(secret types.SecretFinding) {
|
func (r *secretRenderer) renderSummary(secret types.DetectedSecret) {
|
||||||
|
|
||||||
// severity
|
// severity
|
||||||
switch secret.Severity {
|
switch secret.Severity {
|
||||||
@@ -108,7 +108,7 @@ func (r *secretRenderer) renderSummary(secret types.SecretFinding) {
|
|||||||
r.printSingleDivider()
|
r.printSingleDivider()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *secretRenderer) renderCode(secret types.SecretFinding) {
|
func (r *secretRenderer) renderCode(secret types.DetectedSecret) {
|
||||||
// highlight code if we can...
|
// highlight code if we can...
|
||||||
if lines := secret.Code.Lines; len(lines) > 0 {
|
if lines := secret.Code.Lines; len(lines) > 0 {
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package table_test
|
package table_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/aquasecurity/trivy/pkg/types"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
@@ -15,12 +16,12 @@ func TestSecretRenderer(t *testing.T) {
|
|||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
input []ftypes.SecretFinding
|
input []types.DetectedSecret
|
||||||
want string
|
want string
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "single line",
|
name: "single line",
|
||||||
input: []ftypes.SecretFinding{
|
input: []types.DetectedSecret{
|
||||||
{
|
{
|
||||||
RuleID: "rule-id",
|
RuleID: "rule-id",
|
||||||
Category: ftypes.SecretRuleCategory("category"),
|
Category: ftypes.SecretRuleCategory("category"),
|
||||||
@@ -62,7 +63,7 @@ this is a title
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "multiple line",
|
name: "multiple line",
|
||||||
input: []ftypes.SecretFinding{
|
input: []types.DetectedSecret{
|
||||||
{
|
{
|
||||||
RuleID: "rule-id",
|
RuleID: "rule-id",
|
||||||
Category: ftypes.SecretRuleCategory("category"),
|
Category: ftypes.SecretRuleCategory("category"),
|
||||||
@@ -135,7 +136,10 @@ this is a title
|
|||||||
|
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
t.Run(test.name, func(t *testing.T) {
|
t.Run(test.name, func(t *testing.T) {
|
||||||
renderer := table.NewSecretRenderer("my-file", test.input, false, []dbTypes.Severity{dbTypes.SeverityHigh, dbTypes.SeverityMedium})
|
renderer := table.NewSecretRenderer("my-file", test.input, false, []dbTypes.Severity{
|
||||||
|
dbTypes.SeverityHigh,
|
||||||
|
dbTypes.SeverityMedium,
|
||||||
|
})
|
||||||
assert.Equal(t, test.want, strings.ReplaceAll(renderer.Render(), "\r\n", "\n"))
|
assert.Equal(t, test.want, strings.ReplaceAll(renderer.Render(), "\r\n", "\n"))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/fatih/color"
|
"github.com/fatih/color"
|
||||||
"golang.org/x/exp/slices"
|
"golang.org/x/exp/slices"
|
||||||
@@ -36,8 +35,8 @@ type Writer struct {
|
|||||||
// Show dependency origin tree
|
// Show dependency origin tree
|
||||||
Tree bool
|
Tree bool
|
||||||
|
|
||||||
// We have to show a message once about using the '-format json' subcommand to get the full pkgPath
|
// Show suppressed findings
|
||||||
ShowMessageOnce *sync.Once
|
ShowSuppressed bool
|
||||||
|
|
||||||
// For misconfigurations
|
// For misconfigurations
|
||||||
IncludeNonFailures bool
|
IncludeNonFailures bool
|
||||||
@@ -54,6 +53,7 @@ type Renderer interface {
|
|||||||
|
|
||||||
// Write writes the result on standard output
|
// Write writes the result on standard output
|
||||||
func (tw Writer) Write(_ context.Context, report types.Report) error {
|
func (tw Writer) Write(_ context.Context, report types.Report) error {
|
||||||
|
|
||||||
for _, result := range report.Results {
|
for _, result := range report.Results {
|
||||||
// Not display a table of custom resources
|
// Not display a table of custom resources
|
||||||
if result.Class == types.ClassCustom {
|
if result.Class == types.ClassCustom {
|
||||||
@@ -73,7 +73,7 @@ func (tw Writer) write(result types.Result) {
|
|||||||
switch {
|
switch {
|
||||||
// vulnerability
|
// vulnerability
|
||||||
case result.Class == types.ClassOSPkg || result.Class == types.ClassLangPkg:
|
case result.Class == types.ClassOSPkg || result.Class == types.ClassLangPkg:
|
||||||
renderer = NewVulnerabilityRenderer(result, tw.isOutputToTerminal(), tw.Tree, tw.Severities)
|
renderer = NewVulnerabilityRenderer(result, tw.isOutputToTerminal(), tw.Tree, tw.ShowSuppressed, tw.Severities)
|
||||||
// misconfiguration
|
// misconfiguration
|
||||||
case result.Class == types.ClassConfig:
|
case result.Class == types.ClassConfig:
|
||||||
renderer = NewMisconfigRenderer(result, tw.Severities, tw.Trace, tw.IncludeNonFailures, tw.isOutputToTerminal())
|
renderer = NewMisconfigRenderer(result, tw.Severities, tw.Trace, tw.IncludeNonFailures, tw.isOutputToTerminal())
|
||||||
|
|||||||
@@ -2,17 +2,17 @@ package table_test
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
ftypes "github.com/aquasecurity/trivy/pkg/fanal/types"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
|
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
|
||||||
ftypes "github.com/aquasecurity/trivy/pkg/fanal/types"
|
|
||||||
"github.com/aquasecurity/trivy/pkg/report/table"
|
"github.com/aquasecurity/trivy/pkg/report/table"
|
||||||
"github.com/aquasecurity/trivy/pkg/types"
|
"github.com/aquasecurity/trivy/pkg/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestReportWriter_Table(t *testing.T) {
|
func TestWriter_Write(t *testing.T) {
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
name string
|
name string
|
||||||
results types.Results
|
results types.Results
|
||||||
@@ -20,7 +20,7 @@ func TestReportWriter_Table(t *testing.T) {
|
|||||||
includeNonFailures bool
|
includeNonFailures bool
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "happy path full",
|
name: "vulnerability and custom resource",
|
||||||
results: types.Results{
|
results: types.Results{
|
||||||
{
|
{
|
||||||
Target: "test",
|
Target: "test",
|
||||||
@@ -39,6 +39,12 @@ func TestReportWriter_Table(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
CustomResources: []ftypes.CustomResource{
|
||||||
|
{
|
||||||
|
Type: "test",
|
||||||
|
Data: "test",
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
expectedOutput: `
|
expectedOutput: `
|
||||||
@@ -52,294 +58,18 @@ Total: 1 (MEDIUM: 0, HIGH: 1)
|
|||||||
│ foo │ CVE-2020-0001 │ HIGH │ will_not_fix │ 1.2.3 │ │ foobar │
|
│ foo │ CVE-2020-0001 │ HIGH │ will_not_fix │ 1.2.3 │ │ foobar │
|
||||||
│ │ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2020-0001 │
|
│ │ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2020-0001 │
|
||||||
└─────────┴───────────────┴──────────┴──────────────┴───────────────────┴───────────────┴───────────────────────────────────────────┘
|
└─────────┴───────────────┴──────────┴──────────────┴───────────────────┴───────────────┴───────────────────────────────────────────┘
|
||||||
`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "happy path with filePath in result",
|
|
||||||
results: types.Results{
|
|
||||||
{
|
|
||||||
Target: "test",
|
|
||||||
Class: types.ClassLangPkg,
|
|
||||||
Vulnerabilities: []types.DetectedVulnerability{
|
|
||||||
{
|
|
||||||
VulnerabilityID: "CVE-2020-0001",
|
|
||||||
PkgName: "foo",
|
|
||||||
PkgPath: "foo/bar",
|
|
||||||
InstalledVersion: "1.2.3",
|
|
||||||
FixedVersion: "3.4.5",
|
|
||||||
PrimaryURL: "https://avd.aquasec.com/nvd/cve-2020-0001",
|
|
||||||
Status: dbTypes.StatusFixed,
|
|
||||||
Vulnerability: dbTypes.Vulnerability{
|
|
||||||
Title: "foobar",
|
|
||||||
Description: "baz",
|
|
||||||
Severity: "HIGH",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
expectedOutput: `
|
|
||||||
test ()
|
|
||||||
=======
|
|
||||||
Total: 1 (MEDIUM: 0, HIGH: 1)
|
|
||||||
|
|
||||||
┌───────────┬───────────────┬──────────┬────────┬───────────────────┬───────────────┬───────────────────────────────────────────┐
|
|
||||||
│ Library │ Vulnerability │ Severity │ Status │ Installed Version │ Fixed Version │ Title │
|
|
||||||
├───────────┼───────────────┼──────────┼────────┼───────────────────┼───────────────┼───────────────────────────────────────────┤
|
|
||||||
│ foo (bar) │ CVE-2020-0001 │ HIGH │ fixed │ 1.2.3 │ 3.4.5 │ foobar │
|
|
||||||
│ │ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2020-0001 │
|
|
||||||
└───────────┴───────────────┴──────────┴────────┴───────────────────┴───────────────┴───────────────────────────────────────────┘
|
|
||||||
`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "no title for vuln and missing primary link",
|
|
||||||
results: types.Results{
|
|
||||||
{
|
|
||||||
Target: "test",
|
|
||||||
Class: types.ClassLangPkg,
|
|
||||||
Vulnerabilities: []types.DetectedVulnerability{
|
|
||||||
{
|
|
||||||
VulnerabilityID: "CVE-2020-0001",
|
|
||||||
PkgName: "foo",
|
|
||||||
InstalledVersion: "1.2.3",
|
|
||||||
FixedVersion: "3.4.5",
|
|
||||||
Status: dbTypes.StatusFixed,
|
|
||||||
Vulnerability: dbTypes.Vulnerability{
|
|
||||||
Description: "foobar",
|
|
||||||
Severity: "HIGH",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
expectedOutput: `
|
|
||||||
test ()
|
|
||||||
=======
|
|
||||||
Total: 1 (MEDIUM: 0, HIGH: 1)
|
|
||||||
|
|
||||||
┌─────────┬───────────────┬──────────┬────────┬───────────────────┬───────────────┬────────┐
|
|
||||||
│ Library │ Vulnerability │ Severity │ Status │ Installed Version │ Fixed Version │ Title │
|
|
||||||
├─────────┼───────────────┼──────────┼────────┼───────────────────┼───────────────┼────────┤
|
|
||||||
│ foo │ CVE-2020-0001 │ HIGH │ fixed │ 1.2.3 │ 3.4.5 │ foobar │
|
|
||||||
└─────────┴───────────────┴──────────┴────────┴───────────────────┴───────────────┴────────┘
|
|
||||||
`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "long title for vuln",
|
|
||||||
results: types.Results{
|
|
||||||
{
|
|
||||||
Target: "test",
|
|
||||||
Class: types.ClassLangPkg,
|
|
||||||
Vulnerabilities: []types.DetectedVulnerability{
|
|
||||||
{
|
|
||||||
VulnerabilityID: "CVE-2020-1234",
|
|
||||||
PkgName: "foo",
|
|
||||||
InstalledVersion: "1.2.3",
|
|
||||||
FixedVersion: "3.4.5",
|
|
||||||
PrimaryURL: "https://avd.aquasec.com/nvd/cve-2020-1234",
|
|
||||||
Status: dbTypes.StatusFixed,
|
|
||||||
Vulnerability: dbTypes.Vulnerability{
|
|
||||||
Title: "a b c d e f g h i j k l m n o p q r s t u v",
|
|
||||||
Description: "foobar",
|
|
||||||
Severity: "HIGH",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
expectedOutput: `
|
|
||||||
test ()
|
|
||||||
=======
|
|
||||||
Total: 1 (MEDIUM: 0, HIGH: 1)
|
|
||||||
|
|
||||||
┌─────────┬───────────────┬──────────┬────────┬───────────────────┬───────────────┬───────────────────────────────────────────┐
|
|
||||||
│ Library │ Vulnerability │ Severity │ Status │ Installed Version │ Fixed Version │ Title │
|
|
||||||
├─────────┼───────────────┼──────────┼────────┼───────────────────┼───────────────┼───────────────────────────────────────────┤
|
|
||||||
│ foo │ CVE-2020-1234 │ HIGH │ fixed │ 1.2.3 │ 3.4.5 │ a b c d e f g h i j k l... │
|
|
||||||
│ │ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2020-1234 │
|
|
||||||
└─────────┴───────────────┴──────────┴────────┴───────────────────┴───────────────┴───────────────────────────────────────────┘
|
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "no vulns",
|
name: "no vulns",
|
||||||
|
results: types.Results{
|
||||||
|
{
|
||||||
|
Target: "test",
|
||||||
|
Class: types.ClassLangPkg,
|
||||||
|
},
|
||||||
|
},
|
||||||
expectedOutput: ``,
|
expectedOutput: ``,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: "happy path with vulnerability origin graph with direct dependency info",
|
|
||||||
results: types.Results{
|
|
||||||
{
|
|
||||||
Target: "package-lock.json",
|
|
||||||
Class: types.ClassLangPkg,
|
|
||||||
Type: "npm",
|
|
||||||
Packages: []ftypes.Package{
|
|
||||||
{
|
|
||||||
ID: "node-fetch@1.7.3",
|
|
||||||
Name: "node-fetch",
|
|
||||||
Version: "1.7.3",
|
|
||||||
Indirect: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
ID: "isomorphic-fetch@2.2.1",
|
|
||||||
Name: "isomorphic-fetch",
|
|
||||||
Version: "2.2.1",
|
|
||||||
Indirect: true,
|
|
||||||
DependsOn: []string{
|
|
||||||
"node-fetch@1.7.3",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
ID: "fbjs@0.8.18",
|
|
||||||
Name: "fbjs",
|
|
||||||
Version: "0.8.18",
|
|
||||||
Indirect: true,
|
|
||||||
DependsOn: []string{
|
|
||||||
"isomorphic-fetch@2.2.1",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
ID: "sanitize-html@1.20.0",
|
|
||||||
Name: "sanitize-html",
|
|
||||||
Version: "1.20.0",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
ID: "styled-components@3.1.3",
|
|
||||||
Name: "styled-components",
|
|
||||||
Version: "3.1.3",
|
|
||||||
DependsOn: []string{
|
|
||||||
"fbjs@0.8.18",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Vulnerabilities: []types.DetectedVulnerability{
|
|
||||||
{
|
|
||||||
VulnerabilityID: "CVE-2022-0235",
|
|
||||||
PkgID: "node-fetch@1.7.3",
|
|
||||||
PkgName: "node-fetch",
|
|
||||||
Vulnerability: dbTypes.Vulnerability{
|
|
||||||
Title: "foobar",
|
|
||||||
Description: "baz",
|
|
||||||
Severity: "HIGH",
|
|
||||||
},
|
|
||||||
InstalledVersion: "1.7.3",
|
|
||||||
FixedVersion: "2.6.7, 3.1.1",
|
|
||||||
Status: dbTypes.StatusFixed,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
VulnerabilityID: "CVE-2021-26539",
|
|
||||||
PkgID: "sanitize-html@1.20.0",
|
|
||||||
PkgName: "sanitize-html",
|
|
||||||
Vulnerability: dbTypes.Vulnerability{
|
|
||||||
Title: "foobar",
|
|
||||||
Description: "baz",
|
|
||||||
Severity: "MEDIUM",
|
|
||||||
},
|
|
||||||
InstalledVersion: "1.20.0",
|
|
||||||
FixedVersion: "2.3.1",
|
|
||||||
Status: dbTypes.StatusFixed,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
expectedOutput: `
|
|
||||||
package-lock.json (npm)
|
|
||||||
=======================
|
|
||||||
Total: 2 (MEDIUM: 1, HIGH: 1)
|
|
||||||
|
|
||||||
┌───────────────┬────────────────┬──────────┬────────┬───────────────────┬───────────────┬────────┐
|
|
||||||
│ Library │ Vulnerability │ Severity │ Status │ Installed Version │ Fixed Version │ Title │
|
|
||||||
├───────────────┼────────────────┼──────────┼────────┼───────────────────┼───────────────┼────────┤
|
|
||||||
│ node-fetch │ CVE-2022-0235 │ HIGH │ fixed │ 1.7.3 │ 2.6.7, 3.1.1 │ foobar │
|
|
||||||
├───────────────┼────────────────┼──────────┤ ├───────────────────┼───────────────┤ │
|
|
||||||
│ sanitize-html │ CVE-2021-26539 │ MEDIUM │ │ 1.20.0 │ 2.3.1 │ │
|
|
||||||
└───────────────┴────────────────┴──────────┴────────┴───────────────────┴───────────────┴────────┘
|
|
||||||
|
|
||||||
Dependency Origin Tree (Reversed)
|
|
||||||
=================================
|
|
||||||
package-lock.json
|
|
||||||
├── node-fetch@1.7.3, (MEDIUM: 0, HIGH: 1)
|
|
||||||
│ └── ...(omitted)...
|
|
||||||
│ └── styled-components@3.1.3
|
|
||||||
└── sanitize-html@1.20.0, (MEDIUM: 1, HIGH: 0)
|
|
||||||
`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "happy path with vulnerability origin graph without direct dependency info",
|
|
||||||
results: types.Results{
|
|
||||||
{
|
|
||||||
Target: "package-lock.json",
|
|
||||||
Class: types.ClassLangPkg,
|
|
||||||
Type: "npm",
|
|
||||||
Packages: []ftypes.Package{
|
|
||||||
{
|
|
||||||
ID: "node-fetch@1.7.3",
|
|
||||||
Name: "node-fetch",
|
|
||||||
Version: "1.7.3",
|
|
||||||
Indirect: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
ID: "isomorphic-fetch@2.2.1",
|
|
||||||
Name: "isomorphic-fetch",
|
|
||||||
Version: "2.2.1",
|
|
||||||
Indirect: true,
|
|
||||||
DependsOn: []string{
|
|
||||||
"node-fetch@1.7.3",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
ID: "fbjs@0.8.18",
|
|
||||||
Name: "fbjs",
|
|
||||||
Version: "0.8.18",
|
|
||||||
Indirect: true,
|
|
||||||
DependsOn: []string{
|
|
||||||
"isomorphic-fetch@2.2.1",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
ID: "styled-components@3.1.3",
|
|
||||||
Name: "styled-components",
|
|
||||||
Version: "3.1.3",
|
|
||||||
Indirect: true,
|
|
||||||
DependsOn: []string{
|
|
||||||
"fbjs@0.8.18",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Vulnerabilities: []types.DetectedVulnerability{
|
|
||||||
{
|
|
||||||
VulnerabilityID: "CVE-2022-0235",
|
|
||||||
PkgID: "node-fetch@1.7.3",
|
|
||||||
PkgName: "node-fetch",
|
|
||||||
Vulnerability: dbTypes.Vulnerability{
|
|
||||||
Title: "foobar",
|
|
||||||
Description: "baz",
|
|
||||||
Severity: "HIGH",
|
|
||||||
},
|
|
||||||
InstalledVersion: "1.7.3",
|
|
||||||
FixedVersion: "2.6.7, 3.1.1",
|
|
||||||
Status: dbTypes.StatusFixed,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
expectedOutput: `
|
|
||||||
package-lock.json (npm)
|
|
||||||
=======================
|
|
||||||
Total: 1 (MEDIUM: 0, HIGH: 1)
|
|
||||||
|
|
||||||
┌────────────┬───────────────┬──────────┬────────┬───────────────────┬───────────────┬────────┐
|
|
||||||
│ Library │ Vulnerability │ Severity │ Status │ Installed Version │ Fixed Version │ Title │
|
|
||||||
├────────────┼───────────────┼──────────┼────────┼───────────────────┼───────────────┼────────┤
|
|
||||||
│ node-fetch │ CVE-2022-0235 │ HIGH │ fixed │ 1.7.3 │ 2.6.7, 3.1.1 │ foobar │
|
|
||||||
└────────────┴───────────────┴──────────┴────────┴───────────────────┴───────────────┴────────┘
|
|
||||||
|
|
||||||
Dependency Origin Tree (Reversed)
|
|
||||||
=================================
|
|
||||||
package-lock.json
|
|
||||||
└── node-fetch@1.7.3, (MEDIUM: 0, HIGH: 1)
|
|
||||||
└── ...(omitted)...
|
|
||||||
└── styled-components@3.1.3
|
|
||||||
`,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
|
|||||||
@@ -21,35 +21,56 @@ import (
|
|||||||
"github.com/aquasecurity/trivy/pkg/types"
|
"github.com/aquasecurity/trivy/pkg/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var showSuppressedOnce = sync.OnceFunc(func() {
|
||||||
|
log.Logger.Info(`Some vulnerabilities have been ignored/suppressed. Use the "--show-suppressed" flag to display them.`)
|
||||||
|
})
|
||||||
|
|
||||||
type vulnerabilityRenderer struct {
|
type vulnerabilityRenderer struct {
|
||||||
w *bytes.Buffer
|
w *bytes.Buffer
|
||||||
tableWriter *table.Table
|
|
||||||
result types.Result
|
result types.Result
|
||||||
isTerminal bool
|
isTerminal bool
|
||||||
tree bool
|
tree bool // Show dependency tree
|
||||||
|
showSuppressed bool // Show suppressed vulnerabilities
|
||||||
severities []dbTypes.Severity
|
severities []dbTypes.Severity
|
||||||
once *sync.Once
|
once *sync.Once
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewVulnerabilityRenderer(result types.Result, isTerminal, tree bool, severities []dbTypes.Severity) *vulnerabilityRenderer {
|
func NewVulnerabilityRenderer(result types.Result, isTerminal, tree, suppressed bool, severities []dbTypes.Severity) *vulnerabilityRenderer {
|
||||||
buf := bytes.NewBuffer([]byte{})
|
buf := bytes.NewBuffer([]byte{})
|
||||||
if !isTerminal {
|
if !isTerminal {
|
||||||
tml.DisableFormatting()
|
tml.DisableFormatting()
|
||||||
}
|
}
|
||||||
return &vulnerabilityRenderer{
|
return &vulnerabilityRenderer{
|
||||||
w: buf,
|
w: buf,
|
||||||
tableWriter: newTableWriter(buf, isTerminal),
|
|
||||||
result: result,
|
result: result,
|
||||||
isTerminal: isTerminal,
|
isTerminal: isTerminal,
|
||||||
tree: tree,
|
tree: tree,
|
||||||
|
showSuppressed: suppressed,
|
||||||
severities: severities,
|
severities: severities,
|
||||||
once: new(sync.Once),
|
once: new(sync.Once),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *vulnerabilityRenderer) Render() string {
|
func (r *vulnerabilityRenderer) Render() string {
|
||||||
r.setHeaders()
|
r.renderDetectedVulnerabilities()
|
||||||
r.setVulnerabilityRows(r.result.Vulnerabilities)
|
|
||||||
|
if r.tree {
|
||||||
|
r.renderDependencyTree()
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.showSuppressed {
|
||||||
|
r.renderModifiedVulnerabilities()
|
||||||
|
} else if len(r.result.ModifiedFindings) > 0 {
|
||||||
|
showSuppressedOnce()
|
||||||
|
}
|
||||||
|
|
||||||
|
return r.w.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *vulnerabilityRenderer) renderDetectedVulnerabilities() {
|
||||||
|
tw := newTableWriter(r.w, r.isTerminal)
|
||||||
|
r.setHeaders(tw)
|
||||||
|
r.setVulnerabilityRows(tw, r.result.Vulnerabilities)
|
||||||
|
|
||||||
severityCount := r.countSeverities(r.result.Vulnerabilities)
|
severityCount := r.countSeverities(r.result.Vulnerabilities)
|
||||||
total, summaries := summarize(r.severities, severityCount)
|
total, summaries := summarize(r.severities, severityCount)
|
||||||
@@ -61,15 +82,10 @@ func (r *vulnerabilityRenderer) Render() string {
|
|||||||
RenderTarget(r.w, target, r.isTerminal)
|
RenderTarget(r.w, target, r.isTerminal)
|
||||||
r.printf("Total: %d (%s)\n\n", total, strings.Join(summaries, ", "))
|
r.printf("Total: %d (%s)\n\n", total, strings.Join(summaries, ", "))
|
||||||
|
|
||||||
r.tableWriter.Render()
|
tw.Render()
|
||||||
if r.tree {
|
|
||||||
r.renderDependencyTree()
|
|
||||||
}
|
|
||||||
|
|
||||||
return r.w.String()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *vulnerabilityRenderer) setHeaders() {
|
func (r *vulnerabilityRenderer) setHeaders(tw *table.Table) {
|
||||||
if len(r.result.Vulnerabilities) == 0 {
|
if len(r.result.Vulnerabilities) == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -82,10 +98,10 @@ func (r *vulnerabilityRenderer) setHeaders() {
|
|||||||
"Fixed Version",
|
"Fixed Version",
|
||||||
"Title",
|
"Title",
|
||||||
}
|
}
|
||||||
r.tableWriter.SetHeaders(header...)
|
tw.SetHeaders(header...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *vulnerabilityRenderer) setVulnerabilityRows(vulns []types.DetectedVulnerability) {
|
func (r *vulnerabilityRenderer) setVulnerabilityRows(tw *table.Table, vulns []types.DetectedVulnerability) {
|
||||||
for _, v := range vulns {
|
for _, v := range vulns {
|
||||||
lib := v.PkgName
|
lib := v.PkgName
|
||||||
if v.PkgPath != "" {
|
if v.PkgPath != "" {
|
||||||
@@ -139,7 +155,7 @@ func (r *vulnerabilityRenderer) setVulnerabilityRows(vulns []types.DetectedVulne
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
r.tableWriter.AddRow(row...)
|
tw.AddRow(row...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -151,6 +167,46 @@ func (r *vulnerabilityRenderer) countSeverities(vulns []types.DetectedVulnerabil
|
|||||||
return severityCount
|
return severityCount
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *vulnerabilityRenderer) renderModifiedVulnerabilities() {
|
||||||
|
tw := newTableWriter(r.w, r.isTerminal)
|
||||||
|
header := []string{
|
||||||
|
"Library",
|
||||||
|
"Vulnerability",
|
||||||
|
"Severity",
|
||||||
|
"Status",
|
||||||
|
"Statement",
|
||||||
|
"Source",
|
||||||
|
}
|
||||||
|
tw.SetHeaders(header...)
|
||||||
|
|
||||||
|
var total int
|
||||||
|
for _, m := range r.result.ModifiedFindings {
|
||||||
|
if m.Type != types.FindingTypeVulnerability {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
vuln := m.Finding.(types.DetectedVulnerability)
|
||||||
|
total++
|
||||||
|
|
||||||
|
stmt := lo.Ternary(m.Statement != "", m.Statement, "N/A")
|
||||||
|
tw.AddRow(vuln.PkgName, vuln.VulnerabilityID, vuln.Severity, string(m.Status), stmt, m.Source)
|
||||||
|
}
|
||||||
|
|
||||||
|
if total == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
title := fmt.Sprintf("Suppressed Vulnerabilities (Total: %d)", total)
|
||||||
|
if r.isTerminal {
|
||||||
|
// nolint
|
||||||
|
_ = tml.Fprintf(r.w, "\n<underline>%s</underline>\n\n", title)
|
||||||
|
} else {
|
||||||
|
_, _ = fmt.Fprintf(r.w, "\n%s\n", title)
|
||||||
|
_, _ = fmt.Fprintf(r.w, "%s\n", strings.Repeat("=", len(title)))
|
||||||
|
}
|
||||||
|
|
||||||
|
tw.Render()
|
||||||
|
}
|
||||||
|
|
||||||
func (r *vulnerabilityRenderer) renderDependencyTree() {
|
func (r *vulnerabilityRenderer) renderDependencyTree() {
|
||||||
// Get parents of each dependency
|
// Get parents of each dependency
|
||||||
parents := ftypes.Packages(r.result.Packages).ParentDeps()
|
parents := ftypes.Packages(r.result.Packages).ParentDeps()
|
||||||
|
|||||||
410
pkg/report/table/vulnerability_test.go
Normal file
410
pkg/report/table/vulnerability_test.go
Normal file
@@ -0,0 +1,410 @@
|
|||||||
|
package table_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
|
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
|
||||||
|
ftypes "github.com/aquasecurity/trivy/pkg/fanal/types"
|
||||||
|
"github.com/aquasecurity/trivy/pkg/report/table"
|
||||||
|
"github.com/aquasecurity/trivy/pkg/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_vulnerabilityRenderer_Render(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
result types.Result
|
||||||
|
want string
|
||||||
|
includeNonFailures bool
|
||||||
|
showSuppressed bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "happy path full",
|
||||||
|
result: types.Result{
|
||||||
|
Target: "test",
|
||||||
|
Class: types.ClassLangPkg,
|
||||||
|
Vulnerabilities: []types.DetectedVulnerability{
|
||||||
|
{
|
||||||
|
VulnerabilityID: "CVE-2020-0001",
|
||||||
|
PkgName: "foo",
|
||||||
|
InstalledVersion: "1.2.3",
|
||||||
|
PrimaryURL: "https://avd.aquasec.com/nvd/cve-2020-0001",
|
||||||
|
Status: dbTypes.StatusWillNotFix,
|
||||||
|
Vulnerability: dbTypes.Vulnerability{
|
||||||
|
Title: "foobar",
|
||||||
|
Description: "baz",
|
||||||
|
Severity: "HIGH",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// It won't be shown as `showSuppressed` is false.
|
||||||
|
ModifiedFindings: []types.ModifiedFinding{
|
||||||
|
{
|
||||||
|
Type: types.FindingTypeVulnerability,
|
||||||
|
Status: types.FindingStatusIgnored,
|
||||||
|
Source: ".trivyignore",
|
||||||
|
Finding: types.DetectedVulnerability{
|
||||||
|
VulnerabilityID: "CVE-2020-0002",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
want: `
|
||||||
|
test ()
|
||||||
|
=======
|
||||||
|
Total: 1 (MEDIUM: 0, HIGH: 1)
|
||||||
|
|
||||||
|
┌─────────┬───────────────┬──────────┬──────────────┬───────────────────┬───────────────┬───────────────────────────────────────────┐
|
||||||
|
│ Library │ Vulnerability │ Severity │ Status │ Installed Version │ Fixed Version │ Title │
|
||||||
|
├─────────┼───────────────┼──────────┼──────────────┼───────────────────┼───────────────┼───────────────────────────────────────────┤
|
||||||
|
│ foo │ CVE-2020-0001 │ HIGH │ will_not_fix │ 1.2.3 │ │ foobar │
|
||||||
|
│ │ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2020-0001 │
|
||||||
|
└─────────┴───────────────┴──────────┴──────────────┴───────────────────┴───────────────┴───────────────────────────────────────────┘
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "happy path with filePath in result",
|
||||||
|
result: types.Result{
|
||||||
|
Target: "test",
|
||||||
|
Class: types.ClassLangPkg,
|
||||||
|
Vulnerabilities: []types.DetectedVulnerability{
|
||||||
|
{
|
||||||
|
VulnerabilityID: "CVE-2020-0001",
|
||||||
|
PkgName: "foo",
|
||||||
|
PkgPath: "foo/bar",
|
||||||
|
InstalledVersion: "1.2.3",
|
||||||
|
FixedVersion: "3.4.5",
|
||||||
|
PrimaryURL: "https://avd.aquasec.com/nvd/cve-2020-0001",
|
||||||
|
Status: dbTypes.StatusFixed,
|
||||||
|
Vulnerability: dbTypes.Vulnerability{
|
||||||
|
Title: "foobar",
|
||||||
|
Description: "baz",
|
||||||
|
Severity: "HIGH",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
want: `
|
||||||
|
test ()
|
||||||
|
=======
|
||||||
|
Total: 1 (MEDIUM: 0, HIGH: 1)
|
||||||
|
|
||||||
|
┌───────────┬───────────────┬──────────┬────────┬───────────────────┬───────────────┬───────────────────────────────────────────┐
|
||||||
|
│ Library │ Vulnerability │ Severity │ Status │ Installed Version │ Fixed Version │ Title │
|
||||||
|
├───────────┼───────────────┼──────────┼────────┼───────────────────┼───────────────┼───────────────────────────────────────────┤
|
||||||
|
│ foo (bar) │ CVE-2020-0001 │ HIGH │ fixed │ 1.2.3 │ 3.4.5 │ foobar │
|
||||||
|
│ │ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2020-0001 │
|
||||||
|
└───────────┴───────────────┴──────────┴────────┴───────────────────┴───────────────┴───────────────────────────────────────────┘
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "no title for vuln and missing primary link",
|
||||||
|
result: types.Result{
|
||||||
|
Target: "test",
|
||||||
|
Class: types.ClassLangPkg,
|
||||||
|
Vulnerabilities: []types.DetectedVulnerability{
|
||||||
|
{
|
||||||
|
VulnerabilityID: "CVE-2020-0001",
|
||||||
|
PkgName: "foo",
|
||||||
|
InstalledVersion: "1.2.3",
|
||||||
|
FixedVersion: "3.4.5",
|
||||||
|
Status: dbTypes.StatusFixed,
|
||||||
|
Vulnerability: dbTypes.Vulnerability{
|
||||||
|
Description: "foobar",
|
||||||
|
Severity: "HIGH",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
want: `
|
||||||
|
test ()
|
||||||
|
=======
|
||||||
|
Total: 1 (MEDIUM: 0, HIGH: 1)
|
||||||
|
|
||||||
|
┌─────────┬───────────────┬──────────┬────────┬───────────────────┬───────────────┬────────┐
|
||||||
|
│ Library │ Vulnerability │ Severity │ Status │ Installed Version │ Fixed Version │ Title │
|
||||||
|
├─────────┼───────────────┼──────────┼────────┼───────────────────┼───────────────┼────────┤
|
||||||
|
│ foo │ CVE-2020-0001 │ HIGH │ fixed │ 1.2.3 │ 3.4.5 │ foobar │
|
||||||
|
└─────────┴───────────────┴──────────┴────────┴───────────────────┴───────────────┴────────┘
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "long title for vuln",
|
||||||
|
result: types.Result{
|
||||||
|
Target: "test",
|
||||||
|
Class: types.ClassLangPkg,
|
||||||
|
Vulnerabilities: []types.DetectedVulnerability{
|
||||||
|
{
|
||||||
|
VulnerabilityID: "CVE-2020-1234",
|
||||||
|
PkgName: "foo",
|
||||||
|
InstalledVersion: "1.2.3",
|
||||||
|
FixedVersion: "3.4.5",
|
||||||
|
PrimaryURL: "https://avd.aquasec.com/nvd/cve-2020-1234",
|
||||||
|
Status: dbTypes.StatusFixed,
|
||||||
|
Vulnerability: dbTypes.Vulnerability{
|
||||||
|
Title: "a b c d e f g h i j k l m n o p q r s t u v",
|
||||||
|
Description: "foobar",
|
||||||
|
Severity: "HIGH",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
want: `
|
||||||
|
test ()
|
||||||
|
=======
|
||||||
|
Total: 1 (MEDIUM: 0, HIGH: 1)
|
||||||
|
|
||||||
|
┌─────────┬───────────────┬──────────┬────────┬───────────────────┬───────────────┬───────────────────────────────────────────┐
|
||||||
|
│ Library │ Vulnerability │ Severity │ Status │ Installed Version │ Fixed Version │ Title │
|
||||||
|
├─────────┼───────────────┼──────────┼────────┼───────────────────┼───────────────┼───────────────────────────────────────────┤
|
||||||
|
│ foo │ CVE-2020-1234 │ HIGH │ fixed │ 1.2.3 │ 3.4.5 │ a b c d e f g h i j k l... │
|
||||||
|
│ │ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2020-1234 │
|
||||||
|
└─────────┴───────────────┴──────────┴────────┴───────────────────┴───────────────┴───────────────────────────────────────────┘
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "happy path with vulnerability origin graph with direct dependency info",
|
||||||
|
result: types.Result{
|
||||||
|
Target: "package-lock.json",
|
||||||
|
Class: types.ClassLangPkg,
|
||||||
|
Type: "npm",
|
||||||
|
Packages: []ftypes.Package{
|
||||||
|
{
|
||||||
|
ID: "node-fetch@1.7.3",
|
||||||
|
Name: "node-fetch",
|
||||||
|
Version: "1.7.3",
|
||||||
|
Indirect: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "isomorphic-fetch@2.2.1",
|
||||||
|
Name: "isomorphic-fetch",
|
||||||
|
Version: "2.2.1",
|
||||||
|
Indirect: true,
|
||||||
|
DependsOn: []string{
|
||||||
|
"node-fetch@1.7.3",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "fbjs@0.8.18",
|
||||||
|
Name: "fbjs",
|
||||||
|
Version: "0.8.18",
|
||||||
|
Indirect: true,
|
||||||
|
DependsOn: []string{
|
||||||
|
"isomorphic-fetch@2.2.1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "sanitize-html@1.20.0",
|
||||||
|
Name: "sanitize-html",
|
||||||
|
Version: "1.20.0",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "styled-components@3.1.3",
|
||||||
|
Name: "styled-components",
|
||||||
|
Version: "3.1.3",
|
||||||
|
DependsOn: []string{
|
||||||
|
"fbjs@0.8.18",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Vulnerabilities: []types.DetectedVulnerability{
|
||||||
|
{
|
||||||
|
VulnerabilityID: "CVE-2022-0235",
|
||||||
|
PkgID: "node-fetch@1.7.3",
|
||||||
|
PkgName: "node-fetch",
|
||||||
|
Vulnerability: dbTypes.Vulnerability{
|
||||||
|
Title: "foobar",
|
||||||
|
Description: "baz",
|
||||||
|
Severity: "HIGH",
|
||||||
|
},
|
||||||
|
InstalledVersion: "1.7.3",
|
||||||
|
FixedVersion: "2.6.7, 3.1.1",
|
||||||
|
Status: dbTypes.StatusFixed,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
VulnerabilityID: "CVE-2021-26539",
|
||||||
|
PkgID: "sanitize-html@1.20.0",
|
||||||
|
PkgName: "sanitize-html",
|
||||||
|
Vulnerability: dbTypes.Vulnerability{
|
||||||
|
Title: "foobar",
|
||||||
|
Description: "baz",
|
||||||
|
Severity: "MEDIUM",
|
||||||
|
},
|
||||||
|
InstalledVersion: "1.20.0",
|
||||||
|
FixedVersion: "2.3.1",
|
||||||
|
Status: dbTypes.StatusFixed,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
want: `
|
||||||
|
package-lock.json (npm)
|
||||||
|
=======================
|
||||||
|
Total: 2 (MEDIUM: 1, HIGH: 1)
|
||||||
|
|
||||||
|
┌───────────────┬────────────────┬──────────┬────────┬───────────────────┬───────────────┬────────┐
|
||||||
|
│ Library │ Vulnerability │ Severity │ Status │ Installed Version │ Fixed Version │ Title │
|
||||||
|
├───────────────┼────────────────┼──────────┼────────┼───────────────────┼───────────────┼────────┤
|
||||||
|
│ node-fetch │ CVE-2022-0235 │ HIGH │ fixed │ 1.7.3 │ 2.6.7, 3.1.1 │ foobar │
|
||||||
|
├───────────────┼────────────────┼──────────┤ ├───────────────────┼───────────────┤ │
|
||||||
|
│ sanitize-html │ CVE-2021-26539 │ MEDIUM │ │ 1.20.0 │ 2.3.1 │ │
|
||||||
|
└───────────────┴────────────────┴──────────┴────────┴───────────────────┴───────────────┴────────┘
|
||||||
|
|
||||||
|
Dependency Origin Tree (Reversed)
|
||||||
|
=================================
|
||||||
|
package-lock.json
|
||||||
|
├── node-fetch@1.7.3, (MEDIUM: 0, HIGH: 1)
|
||||||
|
│ └── ...(omitted)...
|
||||||
|
│ └── styled-components@3.1.3
|
||||||
|
└── sanitize-html@1.20.0, (MEDIUM: 1, HIGH: 0)
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "happy path with vulnerability origin graph without direct dependency info",
|
||||||
|
result: types.Result{
|
||||||
|
Target: "package-lock.json",
|
||||||
|
Class: types.ClassLangPkg,
|
||||||
|
Type: "npm",
|
||||||
|
Packages: []ftypes.Package{
|
||||||
|
{
|
||||||
|
ID: "node-fetch@1.7.3",
|
||||||
|
Name: "node-fetch",
|
||||||
|
Version: "1.7.3",
|
||||||
|
Indirect: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "isomorphic-fetch@2.2.1",
|
||||||
|
Name: "isomorphic-fetch",
|
||||||
|
Version: "2.2.1",
|
||||||
|
Indirect: true,
|
||||||
|
DependsOn: []string{
|
||||||
|
"node-fetch@1.7.3",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "fbjs@0.8.18",
|
||||||
|
Name: "fbjs",
|
||||||
|
Version: "0.8.18",
|
||||||
|
Indirect: true,
|
||||||
|
DependsOn: []string{
|
||||||
|
"isomorphic-fetch@2.2.1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "styled-components@3.1.3",
|
||||||
|
Name: "styled-components",
|
||||||
|
Version: "3.1.3",
|
||||||
|
Indirect: true,
|
||||||
|
DependsOn: []string{
|
||||||
|
"fbjs@0.8.18",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Vulnerabilities: []types.DetectedVulnerability{
|
||||||
|
{
|
||||||
|
VulnerabilityID: "CVE-2022-0235",
|
||||||
|
PkgID: "node-fetch@1.7.3",
|
||||||
|
PkgName: "node-fetch",
|
||||||
|
Vulnerability: dbTypes.Vulnerability{
|
||||||
|
Title: "foobar",
|
||||||
|
Description: "baz",
|
||||||
|
Severity: "HIGH",
|
||||||
|
},
|
||||||
|
InstalledVersion: "1.7.3",
|
||||||
|
FixedVersion: "2.6.7, 3.1.1",
|
||||||
|
Status: dbTypes.StatusFixed,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
want: `
|
||||||
|
package-lock.json (npm)
|
||||||
|
=======================
|
||||||
|
Total: 1 (MEDIUM: 0, HIGH: 1)
|
||||||
|
|
||||||
|
┌────────────┬───────────────┬──────────┬────────┬───────────────────┬───────────────┬────────┐
|
||||||
|
│ Library │ Vulnerability │ Severity │ Status │ Installed Version │ Fixed Version │ Title │
|
||||||
|
├────────────┼───────────────┼──────────┼────────┼───────────────────┼───────────────┼────────┤
|
||||||
|
│ node-fetch │ CVE-2022-0235 │ HIGH │ fixed │ 1.7.3 │ 2.6.7, 3.1.1 │ foobar │
|
||||||
|
└────────────┴───────────────┴──────────┴────────┴───────────────────┴───────────────┴────────┘
|
||||||
|
|
||||||
|
Dependency Origin Tree (Reversed)
|
||||||
|
=================================
|
||||||
|
package-lock.json
|
||||||
|
└── node-fetch@1.7.3, (MEDIUM: 0, HIGH: 1)
|
||||||
|
└── ...(omitted)...
|
||||||
|
└── styled-components@3.1.3
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "show suppressed vulnerabilities",
|
||||||
|
result: types.Result{
|
||||||
|
Target: "test",
|
||||||
|
Class: types.ClassLangPkg,
|
||||||
|
Vulnerabilities: []types.DetectedVulnerability{
|
||||||
|
{
|
||||||
|
VulnerabilityID: "CVE-2020-0001",
|
||||||
|
PkgName: "foo",
|
||||||
|
InstalledVersion: "1.2.3",
|
||||||
|
PrimaryURL: "https://avd.aquasec.com/nvd/cve-2020-0001",
|
||||||
|
Status: dbTypes.StatusWillNotFix,
|
||||||
|
Vulnerability: dbTypes.Vulnerability{
|
||||||
|
Title: "title1",
|
||||||
|
Description: "desc1",
|
||||||
|
Severity: "HIGH",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ModifiedFindings: []types.ModifiedFinding{
|
||||||
|
{
|
||||||
|
Type: types.FindingTypeVulnerability,
|
||||||
|
Status: types.FindingStatusIgnored,
|
||||||
|
Statement: "Not exploitable",
|
||||||
|
Source: ".trivyignore.yaml",
|
||||||
|
Finding: types.DetectedVulnerability{
|
||||||
|
VulnerabilityID: "CVE-2020-0002",
|
||||||
|
PkgName: "bar",
|
||||||
|
InstalledVersion: "1.2.3",
|
||||||
|
Status: dbTypes.StatusWillNotFix,
|
||||||
|
Vulnerability: dbTypes.Vulnerability{
|
||||||
|
Title: "title2",
|
||||||
|
Description: "desc2",
|
||||||
|
Severity: "MEDIUM",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
showSuppressed: true,
|
||||||
|
want: `
|
||||||
|
test ()
|
||||||
|
=======
|
||||||
|
Total: 1 (MEDIUM: 0, HIGH: 1)
|
||||||
|
|
||||||
|
┌─────────┬───────────────┬──────────┬──────────────┬───────────────────┬───────────────┬───────────────────────────────────────────┐
|
||||||
|
│ Library │ Vulnerability │ Severity │ Status │ Installed Version │ Fixed Version │ Title │
|
||||||
|
├─────────┼───────────────┼──────────┼──────────────┼───────────────────┼───────────────┼───────────────────────────────────────────┤
|
||||||
|
│ foo │ CVE-2020-0001 │ HIGH │ will_not_fix │ 1.2.3 │ │ title1 │
|
||||||
|
│ │ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2020-0001 │
|
||||||
|
└─────────┴───────────────┴──────────┴──────────────┴───────────────────┴───────────────┴───────────────────────────────────────────┘
|
||||||
|
|
||||||
|
Suppressed Vulnerabilities (Total: 1)
|
||||||
|
=====================================
|
||||||
|
┌─────────┬───────────────┬──────────┬─────────┬─────────────────┬───────────────────┐
|
||||||
|
│ Library │ Vulnerability │ Severity │ Status │ Statement │ Source │
|
||||||
|
├─────────┼───────────────┼──────────┼─────────┼─────────────────┼───────────────────┤
|
||||||
|
│ bar │ CVE-2020-0002 │ MEDIUM │ ignored │ Not exploitable │ .trivyignore.yaml │
|
||||||
|
└─────────┴───────────────┴──────────┴─────────┴─────────────────┴───────────────────┘
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
r := table.NewVulnerabilityRenderer(tt.result, false, true, tt.showSuppressed, []dbTypes.Severity{
|
||||||
|
dbTypes.SeverityHigh,
|
||||||
|
dbTypes.SeverityMedium,
|
||||||
|
})
|
||||||
|
assert.Equal(t, tt.want, r.Render(), tt.name)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,7 +5,6 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
|
||||||
|
|
||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
@@ -49,7 +48,7 @@ func Write(ctx context.Context, report types.Report, option flag.Options) (err e
|
|||||||
Output: output,
|
Output: output,
|
||||||
Severities: option.Severities,
|
Severities: option.Severities,
|
||||||
Tree: option.DependencyTree,
|
Tree: option.DependencyTree,
|
||||||
ShowMessageOnce: &sync.Once{},
|
ShowSuppressed: option.ShowSuppressed,
|
||||||
IncludeNonFailures: option.IncludeNonFailures,
|
IncludeNonFailures: option.IncludeNonFailures,
|
||||||
Trace: option.Trace,
|
Trace: option.Trace,
|
||||||
LicenseRiskThreshold: option.LicenseRiskThreshold,
|
LicenseRiskThreshold: option.LicenseRiskThreshold,
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ func TestResults_Failed(t *testing.T) {
|
|||||||
{
|
{
|
||||||
Type: "Docker Security Check",
|
Type: "Docker Security Check",
|
||||||
ID: "ID-001",
|
ID: "ID-001",
|
||||||
Status: types.StatusFailure,
|
Status: types.MisconfStatusFailure,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -67,7 +67,7 @@ func TestResults_Failed(t *testing.T) {
|
|||||||
{
|
{
|
||||||
Type: "Docker Security Check",
|
Type: "Docker Security Check",
|
||||||
ID: "ID-001",
|
ID: "ID-001",
|
||||||
Status: types.StatusPassed,
|
Status: types.MisconfStatusPassed,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"sort"
|
"sort"
|
||||||
|
|
||||||
"github.com/open-policy-agent/opa/rego"
|
"github.com/open-policy-agent/opa/rego"
|
||||||
@@ -13,7 +14,6 @@ import (
|
|||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
|
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
|
||||||
ftypes "github.com/aquasecurity/trivy/pkg/fanal/types"
|
|
||||||
"github.com/aquasecurity/trivy/pkg/types"
|
"github.com/aquasecurity/trivy/pkg/types"
|
||||||
"github.com/aquasecurity/trivy/pkg/vex"
|
"github.com/aquasecurity/trivy/pkg/vex"
|
||||||
)
|
)
|
||||||
@@ -35,12 +35,7 @@ type FilterOption struct {
|
|||||||
|
|
||||||
// Filter filters out the report
|
// Filter filters out the report
|
||||||
func Filter(ctx context.Context, report types.Report, opt FilterOption) error {
|
func Filter(ctx context.Context, report types.Report, opt FilterOption) error {
|
||||||
// Filter out vulnerabilities based on the given VEX document.
|
ignoreConf, err := parseIgnoreFile(ctx, opt.IgnoreFile)
|
||||||
if err := filterByVEX(report, opt); err != nil {
|
|
||||||
return xerrors.Errorf("VEX error: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
ignoreConf, err := getIgnoredFindings(ctx, opt.IgnoreFile)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return xerrors.Errorf("%s error: %w", opt.IgnoreFile, err)
|
return xerrors.Errorf("%s error: %w", opt.IgnoreFile, err)
|
||||||
}
|
}
|
||||||
@@ -50,6 +45,12 @@ func Filter(ctx context.Context, report types.Report, opt FilterOption) error {
|
|||||||
return xerrors.Errorf("unable to filter vulnerabilities: %w", err)
|
return xerrors.Errorf("unable to filter vulnerabilities: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Filter out vulnerabilities based on the given VEX document.
|
||||||
|
if err = filterByVEX(report, opt); err != nil {
|
||||||
|
return xerrors.Errorf("VEX error: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,29 +61,17 @@ func FilterResult(ctx context.Context, result *types.Result, ignoreConf IgnoreCo
|
|||||||
return s.String()
|
return s.String()
|
||||||
})
|
})
|
||||||
|
|
||||||
filteredVulns := filterVulnerabilities(result, severities, opt.IgnoreStatuses, ignoreConf.Vulnerabilities)
|
filterVulnerabilities(result, severities, opt.IgnoreStatuses, ignoreConf)
|
||||||
misconfSummary, filteredMisconfs := filterMisconfigurations(result, severities, opt.IncludeNonFailures, ignoreConf.Misconfigurations)
|
filterMisconfigurations(result, severities, opt.IncludeNonFailures, ignoreConf)
|
||||||
result.Secrets = filterSecrets(result, severities, ignoreConf.Secrets)
|
filterSecrets(result, severities, ignoreConf)
|
||||||
result.Licenses = filterLicenses(result.Licenses, severities, opt.IgnoreLicenses, ignoreConf.Licenses)
|
filterLicenses(result, severities, opt.IgnoreLicenses, ignoreConf)
|
||||||
|
|
||||||
var ignoredMisconfs int
|
|
||||||
if opt.PolicyFile != "" {
|
if opt.PolicyFile != "" {
|
||||||
var err error
|
if err := applyPolicy(ctx, result, opt.PolicyFile); err != nil {
|
||||||
var ignored int
|
|
||||||
filteredVulns, filteredMisconfs, ignored, err = applyPolicy(ctx, filteredVulns, filteredMisconfs, opt.PolicyFile)
|
|
||||||
if err != nil {
|
|
||||||
return xerrors.Errorf("failed to apply the policy: %w", err)
|
return xerrors.Errorf("failed to apply the policy: %w", err)
|
||||||
}
|
}
|
||||||
ignoredMisconfs += ignored
|
|
||||||
}
|
}
|
||||||
sort.Sort(types.BySeverity(filteredVulns))
|
sort.Sort(types.BySeverity(result.Vulnerabilities))
|
||||||
|
|
||||||
result.Vulnerabilities = filteredVulns
|
|
||||||
result.MisconfSummary = misconfSummary
|
|
||||||
if result.MisconfSummary != nil {
|
|
||||||
result.MisconfSummary.Exceptions += ignoredMisconfs
|
|
||||||
}
|
|
||||||
result.Misconfigurations = filteredMisconfs
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -102,15 +91,13 @@ func filterByVEX(report types.Report, opt FilterOption) error {
|
|||||||
if len(result.Vulnerabilities) == 0 {
|
if len(result.Vulnerabilities) == 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
report.Results[i].Vulnerabilities = vexDoc.Filter(result.Vulnerabilities)
|
vexDoc.Filter(&report.Results[i])
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func filterVulnerabilities(result *types.Result, severities []string, ignoreStatuses []dbTypes.Status,
|
func filterVulnerabilities(result *types.Result, severities []string, ignoreStatuses []dbTypes.Status, ignoreConfig IgnoreConfig) {
|
||||||
ignoreFindings IgnoreFindings) []types.DetectedVulnerability {
|
|
||||||
uniqVulns := make(map[string]types.DetectedVulnerability)
|
uniqVulns := make(map[string]types.DetectedVulnerability)
|
||||||
|
|
||||||
for _, vuln := range result.Vulnerabilities {
|
for _, vuln := range result.Vulnerabilities {
|
||||||
if vuln.Severity == "" {
|
if vuln.Severity == "" {
|
||||||
vuln.Severity = dbTypes.SeverityUnknown.String()
|
vuln.Severity = dbTypes.SeverityUnknown.String()
|
||||||
@@ -123,9 +110,12 @@ func filterVulnerabilities(result *types.Result, severities []string, ignoreStat
|
|||||||
// Filter by status
|
// Filter by status
|
||||||
case slices.Contains(ignoreStatuses, vuln.Status):
|
case slices.Contains(ignoreStatuses, vuln.Status):
|
||||||
continue
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
// Filter by ignore file
|
// Filter by ignore file
|
||||||
case ignoreFindings.Match(result.Target, vuln.VulnerabilityID) ||
|
if f := ignoreConfig.MatchVulnerability(vuln.VulnerabilityID, result.Target, vuln.PkgPath); f != nil {
|
||||||
ignoreFindings.Match(vuln.PkgPath, vuln.VulnerabilityID):
|
result.ModifiedFindings = append(result.ModifiedFindings,
|
||||||
|
types.NewModifiedFinding(vuln, types.FindingStatusIgnored, f.Statement, ignoreConfig.FilePath))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -136,96 +126,116 @@ func filterVulnerabilities(result *types.Result, severities []string, ignoreStat
|
|||||||
}
|
}
|
||||||
uniqVulns[key] = vuln
|
uniqVulns[key] = vuln
|
||||||
}
|
}
|
||||||
if len(uniqVulns) == 0 {
|
|
||||||
return nil
|
// Override the detected vulnerabilities
|
||||||
|
result.Vulnerabilities = maps.Values(uniqVulns)
|
||||||
|
if len(result.Vulnerabilities) == 0 {
|
||||||
|
result.Vulnerabilities = nil
|
||||||
}
|
}
|
||||||
return maps.Values(uniqVulns)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func filterMisconfigurations(result *types.Result, severities []string, includeNonFailures bool,
|
func filterMisconfigurations(result *types.Result, severities []string, includeNonFailures bool,
|
||||||
ignoreMisconfs IgnoreFindings) (*types.MisconfSummary, []types.DetectedMisconfiguration) {
|
ignoreConfig IgnoreConfig) {
|
||||||
var filtered []types.DetectedMisconfiguration
|
var filtered []types.DetectedMisconfiguration
|
||||||
summary := new(types.MisconfSummary)
|
result.MisconfSummary = new(types.MisconfSummary)
|
||||||
|
|
||||||
for _, misconf := range result.Misconfigurations {
|
for _, misconf := range result.Misconfigurations {
|
||||||
if !slices.Contains(severities, misconf.Severity) {
|
|
||||||
// Filter by severity
|
// Filter by severity
|
||||||
|
if !slices.Contains(severities, misconf.Severity) {
|
||||||
continue
|
continue
|
||||||
} else if ignoreMisconfs.Match(result.Target, misconf.ID) || ignoreMisconfs.Match(result.Target, misconf.AVDID) {
|
}
|
||||||
// Filter misconfigurations by ignore file
|
|
||||||
summary.Exceptions++
|
// Filter by ignore file
|
||||||
|
if f := ignoreConfig.MatchMisconfiguration(misconf.ID, misconf.AVDID, result.Target); f != nil {
|
||||||
|
result.MisconfSummary.Exceptions++
|
||||||
|
result.ModifiedFindings = append(result.ModifiedFindings,
|
||||||
|
types.NewModifiedFinding(misconf, types.FindingStatusIgnored, f.Statement, ignoreConfig.FilePath))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// Count successes, failures, and exceptions
|
// Count successes, failures, and exceptions
|
||||||
summarize(misconf.Status, summary)
|
summarize(misconf.Status, result.MisconfSummary)
|
||||||
|
|
||||||
if misconf.Status != types.StatusFailure && !includeNonFailures {
|
if misconf.Status != types.MisconfStatusFailure && !includeNonFailures {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
filtered = append(filtered, misconf)
|
filtered = append(filtered, misconf)
|
||||||
}
|
}
|
||||||
|
|
||||||
if summary.Empty() {
|
result.Misconfigurations = filtered
|
||||||
return nil, nil
|
if result.MisconfSummary.Empty() {
|
||||||
|
result.Misconfigurations = nil
|
||||||
|
result.MisconfSummary = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return summary, filtered
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func filterSecrets(result *types.Result, severities []string, ignoreFindings IgnoreFindings) []ftypes.SecretFinding {
|
func filterSecrets(result *types.Result, severities []string, ignoreConfig IgnoreConfig) {
|
||||||
var filtered []ftypes.SecretFinding
|
var filtered []types.DetectedSecret
|
||||||
for _, secret := range result.Secrets {
|
for _, secret := range result.Secrets {
|
||||||
if !slices.Contains(severities, secret.Severity) {
|
if !slices.Contains(severities, secret.Severity) {
|
||||||
// Filter by severity
|
// Filter by severity
|
||||||
continue
|
continue
|
||||||
} else if ignoreFindings.Match(result.Target, secret.RuleID) {
|
} else if f := ignoreConfig.MatchSecret(secret.RuleID, result.Target); f != nil {
|
||||||
// Filter by ignore file
|
// Filter by ignore file
|
||||||
|
result.ModifiedFindings = append(result.ModifiedFindings,
|
||||||
|
types.NewModifiedFinding(secret, types.FindingStatusIgnored, f.Statement, ignoreConfig.FilePath))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
filtered = append(filtered, secret)
|
filtered = append(filtered, secret)
|
||||||
}
|
}
|
||||||
return filtered
|
result.Secrets = filtered
|
||||||
}
|
}
|
||||||
|
|
||||||
func filterLicenses(licenses []types.DetectedLicense, severities, ignoreLicenseNames []string, ignoreFindings IgnoreFindings) []types.DetectedLicense {
|
func filterLicenses(result *types.Result, severities, ignoreLicenseNames []string, ignoreConfig IgnoreConfig) {
|
||||||
// Merge ignore license names into ignored findings
|
// Merge ignore license names into ignored findings
|
||||||
|
var ignoreLicenses IgnoreFindings
|
||||||
for _, licenseName := range ignoreLicenseNames {
|
for _, licenseName := range ignoreLicenseNames {
|
||||||
ignoreFindings = append(ignoreFindings, IgnoreFinding{
|
ignoreLicenses = append(ignoreLicenses, IgnoreFinding{
|
||||||
ID: licenseName,
|
ID: licenseName,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
var filtered []types.DetectedLicense
|
var filtered []types.DetectedLicense
|
||||||
for _, l := range licenses {
|
for _, l := range result.Licenses {
|
||||||
if !slices.Contains(severities, l.Severity) {
|
|
||||||
// Filter by severity
|
// Filter by severity
|
||||||
continue
|
if !slices.Contains(severities, l.Severity) {
|
||||||
} else if ignoreFindings.Match(l.FilePath, l.Name) {
|
|
||||||
// Filter by ignore file or ignore license names
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Filter by `--ignored-licenses`
|
||||||
|
if f := ignoreLicenses.Match(l.Name, l.FilePath); f != nil {
|
||||||
|
result.ModifiedFindings = append(result.ModifiedFindings,
|
||||||
|
types.NewModifiedFinding(l, types.FindingStatusIgnored, "", "--ignored-licenses"))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Filter by ignore file
|
||||||
|
if f := ignoreConfig.MatchLicense(l.Name, l.FilePath); f != nil {
|
||||||
|
result.ModifiedFindings = append(result.ModifiedFindings,
|
||||||
|
types.NewModifiedFinding(l, types.FindingStatusIgnored, f.Statement, ignoreConfig.FilePath))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
filtered = append(filtered, l)
|
filtered = append(filtered, l)
|
||||||
}
|
}
|
||||||
return filtered
|
result.Licenses = filtered
|
||||||
}
|
}
|
||||||
|
|
||||||
func summarize(status types.MisconfStatus, summary *types.MisconfSummary) {
|
func summarize(status types.MisconfStatus, summary *types.MisconfSummary) {
|
||||||
switch status {
|
switch status {
|
||||||
case types.StatusFailure:
|
case types.MisconfStatusFailure:
|
||||||
summary.Failures++
|
summary.Failures++
|
||||||
case types.StatusPassed:
|
case types.MisconfStatusPassed:
|
||||||
summary.Successes++
|
summary.Successes++
|
||||||
case types.StatusException:
|
case types.MisconfStatusException:
|
||||||
summary.Exceptions++
|
summary.Exceptions++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func applyPolicy(ctx context.Context, vulns []types.DetectedVulnerability, misconfs []types.DetectedMisconfiguration,
|
func applyPolicy(ctx context.Context, result *types.Result, policyFile string) error {
|
||||||
policyFile string) ([]types.DetectedVulnerability, []types.DetectedMisconfiguration, int, error) {
|
|
||||||
policy, err := os.ReadFile(policyFile)
|
policy, err := os.ReadFile(policyFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, 0, xerrors.Errorf("unable to read the policy file: %w", err)
|
return xerrors.Errorf("unable to read the policy file: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
query, err := rego.New(
|
query, err := rego.New(
|
||||||
@@ -234,38 +244,53 @@ func applyPolicy(ctx context.Context, vulns []types.DetectedVulnerability, misco
|
|||||||
rego.Module("trivy.rego", string(policy)),
|
rego.Module("trivy.rego", string(policy)),
|
||||||
).PrepareForEval(ctx)
|
).PrepareForEval(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, 0, xerrors.Errorf("unable to prepare for eval: %w", err)
|
return xerrors.Errorf("unable to prepare for eval: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
policyFile = filepath.ToSlash(filepath.Clean(policyFile))
|
||||||
|
|
||||||
// Vulnerabilities
|
// Vulnerabilities
|
||||||
var filteredVulns []types.DetectedVulnerability
|
var filteredVulns []types.DetectedVulnerability
|
||||||
for _, vuln := range vulns {
|
for _, vuln := range result.Vulnerabilities {
|
||||||
ignored, err := evaluate(ctx, query, vuln)
|
ignored, err := evaluate(ctx, query, vuln)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, 0, err
|
return err
|
||||||
}
|
}
|
||||||
if ignored {
|
if ignored {
|
||||||
|
result.ModifiedFindings = append(result.ModifiedFindings,
|
||||||
|
types.NewModifiedFinding(vuln, types.FindingStatusIgnored, "Filtered by Rego", policyFile))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
filteredVulns = append(filteredVulns, vuln)
|
filteredVulns = append(filteredVulns, vuln)
|
||||||
}
|
}
|
||||||
|
result.Vulnerabilities = filteredVulns
|
||||||
|
|
||||||
// Misconfigurations
|
// Misconfigurations
|
||||||
var ignoredMisconfs int
|
|
||||||
var filteredMisconfs []types.DetectedMisconfiguration
|
var filteredMisconfs []types.DetectedMisconfiguration
|
||||||
for _, misconf := range misconfs {
|
for _, misconf := range result.Misconfigurations {
|
||||||
ignored, err := evaluate(ctx, query, misconf)
|
ignored, err := evaluate(ctx, query, misconf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, 0, err
|
return err
|
||||||
}
|
}
|
||||||
if ignored {
|
if ignored {
|
||||||
ignoredMisconfs++
|
result.MisconfSummary.Exceptions++
|
||||||
|
switch misconf.Status {
|
||||||
|
case types.MisconfStatusFailure:
|
||||||
|
result.MisconfSummary.Failures--
|
||||||
|
case types.MisconfStatusPassed:
|
||||||
|
result.MisconfSummary.Successes--
|
||||||
|
}
|
||||||
|
result.ModifiedFindings = append(result.ModifiedFindings,
|
||||||
|
types.NewModifiedFinding(misconf, types.FindingStatusIgnored, "Filtered by Rego", policyFile))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
filteredMisconfs = append(filteredMisconfs, misconf)
|
filteredMisconfs = append(filteredMisconfs, misconf)
|
||||||
}
|
}
|
||||||
return filteredVulns, filteredMisconfs, ignoredMisconfs, nil
|
result.Misconfigurations = filteredMisconfs
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func evaluate(ctx context.Context, query rego.PreparedEvalQuery, input interface{}) (bool, error) {
|
func evaluate(ctx context.Context, query rego.PreparedEvalQuery, input interface{}) (bool, error) {
|
||||||
results, err := query.Eval(ctx, rego.EvalInput(input))
|
results, err := query.Eval(ctx, rego.EvalInput(input))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -17,6 +17,143 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestFilter(t *testing.T) {
|
func TestFilter(t *testing.T) {
|
||||||
|
var (
|
||||||
|
vuln1 = types.DetectedVulnerability{
|
||||||
|
VulnerabilityID: "CVE-2019-0001",
|
||||||
|
PkgName: "foo",
|
||||||
|
PkgIdentifier: ftypes.PkgIdentifier{
|
||||||
|
PURL: &packageurl.PackageURL{
|
||||||
|
Type: packageurl.TypeGolang,
|
||||||
|
Namespace: "github.com/aquasecurity",
|
||||||
|
Name: "foo",
|
||||||
|
Version: "1.2.3",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
InstalledVersion: "1.2.3",
|
||||||
|
FixedVersion: "1.2.4",
|
||||||
|
Vulnerability: dbTypes.Vulnerability{
|
||||||
|
Severity: dbTypes.SeverityLow.String(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
vuln2 = types.DetectedVulnerability{
|
||||||
|
VulnerabilityID: "CVE-2019-0002",
|
||||||
|
PkgName: "foo",
|
||||||
|
PkgIdentifier: ftypes.PkgIdentifier{
|
||||||
|
PURL: &packageurl.PackageURL{
|
||||||
|
Type: packageurl.TypeGolang,
|
||||||
|
Namespace: "github.com/aquasecurity",
|
||||||
|
Name: "foo",
|
||||||
|
Version: "4.5.6",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
InstalledVersion: "1.2.3",
|
||||||
|
FixedVersion: "1.2.4",
|
||||||
|
Vulnerability: dbTypes.Vulnerability{
|
||||||
|
Severity: dbTypes.SeverityCritical.String(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
vuln3 = types.DetectedVulnerability{
|
||||||
|
VulnerabilityID: "CVE-2019-0003",
|
||||||
|
PkgName: "foo",
|
||||||
|
InstalledVersion: "1.2.3",
|
||||||
|
FixedVersion: "1.2.4",
|
||||||
|
Vulnerability: dbTypes.Vulnerability{
|
||||||
|
Severity: dbTypes.SeverityLow.String(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
vuln4 = types.DetectedVulnerability{
|
||||||
|
VulnerabilityID: "CVE-2019-0004",
|
||||||
|
PkgName: "foo",
|
||||||
|
InstalledVersion: "1.2.3",
|
||||||
|
FixedVersion: "1.2.4",
|
||||||
|
Vulnerability: dbTypes.Vulnerability{
|
||||||
|
Severity: dbTypes.SeverityLow.String(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
vuln5 = types.DetectedVulnerability{
|
||||||
|
VulnerabilityID: "CVE-2019-0005",
|
||||||
|
PkgName: "foo",
|
||||||
|
InstalledVersion: "1.2.3",
|
||||||
|
FixedVersion: "1.2.4",
|
||||||
|
Vulnerability: dbTypes.Vulnerability{
|
||||||
|
Severity: dbTypes.SeverityLow.String(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
vuln6 = types.DetectedVulnerability{
|
||||||
|
VulnerabilityID: "CVE-2019-0006",
|
||||||
|
PkgName: "foo",
|
||||||
|
InstalledVersion: "1.2.3",
|
||||||
|
FixedVersion: "1.2.4",
|
||||||
|
Vulnerability: dbTypes.Vulnerability{
|
||||||
|
Severity: dbTypes.SeverityLow.String(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
misconf1 = types.DetectedMisconfiguration{
|
||||||
|
Type: "Kubernetes Security Check",
|
||||||
|
ID: "ID100",
|
||||||
|
AVDID: "AVD-ID100",
|
||||||
|
Title: "Bad Deployment",
|
||||||
|
Message: "something bad",
|
||||||
|
Severity: dbTypes.SeverityHigh.String(),
|
||||||
|
Status: types.MisconfStatusFailure,
|
||||||
|
}
|
||||||
|
misconf2 = types.DetectedMisconfiguration{
|
||||||
|
Type: "Kubernetes Security Check",
|
||||||
|
ID: "ID200",
|
||||||
|
AVDID: "AVD-ID200",
|
||||||
|
Title: "Bad Pod",
|
||||||
|
Message: "something bad",
|
||||||
|
Severity: dbTypes.SeverityLow.String(),
|
||||||
|
Status: types.MisconfStatusPassed,
|
||||||
|
}
|
||||||
|
misconf3 = types.DetectedMisconfiguration{
|
||||||
|
Type: "Kubernetes Security Check",
|
||||||
|
ID: "ID300",
|
||||||
|
AVDID: "AVD-ID300",
|
||||||
|
Title: "Bad Job",
|
||||||
|
Message: "something bad",
|
||||||
|
Severity: dbTypes.SeverityLow.String(),
|
||||||
|
Status: types.MisconfStatusFailure,
|
||||||
|
}
|
||||||
|
secret1 = types.DetectedSecret{
|
||||||
|
RuleID: "generic-wanted-rule",
|
||||||
|
Severity: dbTypes.SeverityLow.String(),
|
||||||
|
Title: "Secret that should pass filter on rule id",
|
||||||
|
StartLine: 1,
|
||||||
|
EndLine: 2,
|
||||||
|
Match: "*****",
|
||||||
|
}
|
||||||
|
secret2 = types.DetectedSecret{
|
||||||
|
RuleID: "generic-unwanted-rule",
|
||||||
|
Severity: dbTypes.SeverityLow.String(),
|
||||||
|
Title: "Secret that should not pass filter on rule id",
|
||||||
|
StartLine: 3,
|
||||||
|
EndLine: 4,
|
||||||
|
Match: "*****",
|
||||||
|
}
|
||||||
|
secret3 = types.DetectedSecret{
|
||||||
|
RuleID: "generic-unwanted-rule2",
|
||||||
|
Severity: dbTypes.SeverityLow.String(),
|
||||||
|
Title: "Secret that should not pass filter on rule id",
|
||||||
|
StartLine: 5,
|
||||||
|
EndLine: 6,
|
||||||
|
Match: "*****",
|
||||||
|
}
|
||||||
|
license1 = types.DetectedLicense{
|
||||||
|
Name: "GPL-3.0",
|
||||||
|
Severity: dbTypes.SeverityLow.String(),
|
||||||
|
FilePath: "usr/share/gcc/python/libstdcxx/v6/__init__.py",
|
||||||
|
Category: "restricted",
|
||||||
|
Confidence: 1,
|
||||||
|
}
|
||||||
|
license2 = types.DetectedLicense{
|
||||||
|
Name: "GPL-3.0",
|
||||||
|
Severity: dbTypes.SeverityLow.String(),
|
||||||
|
FilePath: "usr/share/gcc/python/libstdcxx/v6/printers.py",
|
||||||
|
Category: "restricted",
|
||||||
|
Confidence: 1,
|
||||||
|
}
|
||||||
|
)
|
||||||
type args struct {
|
type args struct {
|
||||||
report types.Report
|
report types.Report
|
||||||
severities []dbTypes.Severity
|
severities []dbTypes.Severity
|
||||||
@@ -37,44 +174,14 @@ func TestFilter(t *testing.T) {
|
|||||||
Results: []types.Result{
|
Results: []types.Result{
|
||||||
{
|
{
|
||||||
Vulnerabilities: []types.DetectedVulnerability{
|
Vulnerabilities: []types.DetectedVulnerability{
|
||||||
{
|
vuln1,
|
||||||
VulnerabilityID: "CVE-2019-0001",
|
vuln2,
|
||||||
PkgName: "foo",
|
|
||||||
InstalledVersion: "1.2.3",
|
|
||||||
FixedVersion: "1.2.4",
|
|
||||||
Vulnerability: dbTypes.Vulnerability{
|
|
||||||
Severity: dbTypes.SeverityLow.String(),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
VulnerabilityID: "CVE-2019-0002",
|
|
||||||
PkgName: "bar",
|
|
||||||
InstalledVersion: "1.2.3",
|
|
||||||
FixedVersion: "1.2.4",
|
|
||||||
Vulnerability: dbTypes.Vulnerability{
|
|
||||||
Severity: dbTypes.SeverityCritical.String(),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
Misconfigurations: []types.DetectedMisconfiguration{
|
Misconfigurations: []types.DetectedMisconfiguration{
|
||||||
{
|
misconf1,
|
||||||
Type: "Kubernetes Security Check",
|
misconf2,
|
||||||
ID: "ID100",
|
|
||||||
Title: "Bad Deployment",
|
|
||||||
Message: "something bad",
|
|
||||||
Severity: dbTypes.SeverityHigh.String(),
|
|
||||||
Status: types.StatusFailure,
|
|
||||||
},
|
},
|
||||||
{
|
Secrets: []types.DetectedSecret{
|
||||||
Type: "Kubernetes Security Check",
|
|
||||||
ID: "ID200",
|
|
||||||
Title: "Bad Pod",
|
|
||||||
Message: "something bad",
|
|
||||||
Severity: dbTypes.SeverityMedium.String(),
|
|
||||||
Status: types.StatusPassed,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Secrets: []ftypes.SecretFinding{
|
|
||||||
{
|
{
|
||||||
RuleID: "generic-critical-rule",
|
RuleID: "generic-critical-rule",
|
||||||
Severity: dbTypes.SeverityCritical.String(),
|
Severity: dbTypes.SeverityCritical.String(),
|
||||||
@@ -104,15 +211,7 @@ func TestFilter(t *testing.T) {
|
|||||||
Results: []types.Result{
|
Results: []types.Result{
|
||||||
{
|
{
|
||||||
Vulnerabilities: []types.DetectedVulnerability{
|
Vulnerabilities: []types.DetectedVulnerability{
|
||||||
{
|
vuln2,
|
||||||
VulnerabilityID: "CVE-2019-0002",
|
|
||||||
PkgName: "bar",
|
|
||||||
InstalledVersion: "1.2.3",
|
|
||||||
FixedVersion: "1.2.4",
|
|
||||||
Vulnerability: dbTypes.Vulnerability{
|
|
||||||
Severity: dbTypes.SeverityCritical.String(),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
MisconfSummary: &types.MisconfSummary{
|
MisconfSummary: &types.MisconfSummary{
|
||||||
Successes: 0,
|
Successes: 0,
|
||||||
@@ -120,16 +219,9 @@ func TestFilter(t *testing.T) {
|
|||||||
Exceptions: 0,
|
Exceptions: 0,
|
||||||
},
|
},
|
||||||
Misconfigurations: []types.DetectedMisconfiguration{
|
Misconfigurations: []types.DetectedMisconfiguration{
|
||||||
{
|
misconf1,
|
||||||
Type: "Kubernetes Security Check",
|
|
||||||
ID: "ID100",
|
|
||||||
Title: "Bad Deployment",
|
|
||||||
Message: "something bad",
|
|
||||||
Severity: dbTypes.SeverityHigh.String(),
|
|
||||||
Status: types.StatusFailure,
|
|
||||||
},
|
},
|
||||||
},
|
Secrets: []types.DetectedSecret{
|
||||||
Secrets: []ftypes.SecretFinding{
|
|
||||||
{
|
{
|
||||||
RuleID: "generic-critical-rule",
|
RuleID: "generic-critical-rule",
|
||||||
Severity: dbTypes.SeverityCritical.String(),
|
Severity: dbTypes.SeverityCritical.String(),
|
||||||
@@ -150,40 +242,8 @@ func TestFilter(t *testing.T) {
|
|||||||
Results: types.Results{
|
Results: types.Results{
|
||||||
types.Result{
|
types.Result{
|
||||||
Vulnerabilities: []types.DetectedVulnerability{
|
Vulnerabilities: []types.DetectedVulnerability{
|
||||||
{
|
vuln1,
|
||||||
VulnerabilityID: "CVE-2019-0001",
|
vuln2,
|
||||||
PkgName: "foo",
|
|
||||||
PkgIdentifier: ftypes.PkgIdentifier{
|
|
||||||
PURL: &packageurl.PackageURL{
|
|
||||||
Type: packageurl.TypeGolang,
|
|
||||||
Namespace: "github.com/aquasecurity",
|
|
||||||
Name: "foo",
|
|
||||||
Version: "1.2.3",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
InstalledVersion: "1.2.3",
|
|
||||||
FixedVersion: "1.2.4",
|
|
||||||
Vulnerability: dbTypes.Vulnerability{
|
|
||||||
Severity: dbTypes.SeverityLow.String(),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
VulnerabilityID: "CVE-2019-0001",
|
|
||||||
PkgName: "bar",
|
|
||||||
PkgIdentifier: ftypes.PkgIdentifier{
|
|
||||||
PURL: &packageurl.PackageURL{
|
|
||||||
Type: packageurl.TypeGolang,
|
|
||||||
Namespace: "github.com/aquasecurity",
|
|
||||||
Name: "bar",
|
|
||||||
Version: "4.5.6",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
InstalledVersion: "4.5.6",
|
|
||||||
FixedVersion: "4.5.7",
|
|
||||||
Vulnerability: dbTypes.Vulnerability{
|
|
||||||
Severity: dbTypes.SeverityCritical.String(),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -201,22 +261,15 @@ func TestFilter(t *testing.T) {
|
|||||||
Results: types.Results{
|
Results: types.Results{
|
||||||
types.Result{
|
types.Result{
|
||||||
Vulnerabilities: []types.DetectedVulnerability{
|
Vulnerabilities: []types.DetectedVulnerability{
|
||||||
|
vuln2,
|
||||||
|
},
|
||||||
|
ModifiedFindings: []types.ModifiedFinding{
|
||||||
{
|
{
|
||||||
VulnerabilityID: "CVE-2019-0001",
|
Type: types.FindingTypeVulnerability,
|
||||||
PkgName: "bar",
|
Status: types.FindingStatusNotAffected,
|
||||||
PkgIdentifier: ftypes.PkgIdentifier{
|
Statement: "vulnerable_code_not_in_execute_path",
|
||||||
PURL: &packageurl.PackageURL{
|
Source: "OpenVEX",
|
||||||
Type: packageurl.TypeGolang,
|
Finding: vuln1,
|
||||||
Namespace: "github.com/aquasecurity",
|
|
||||||
Name: "bar",
|
|
||||||
Version: "4.5.6",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
InstalledVersion: "4.5.6",
|
|
||||||
FixedVersion: "4.5.7",
|
|
||||||
Vulnerability: dbTypes.Vulnerability{
|
|
||||||
Severity: dbTypes.SeverityCritical.String(),
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -231,25 +284,8 @@ func TestFilter(t *testing.T) {
|
|||||||
types.Result{
|
types.Result{
|
||||||
Target: "debian:11 (debian 11)",
|
Target: "debian:11 (debian 11)",
|
||||||
Vulnerabilities: []types.DetectedVulnerability{
|
Vulnerabilities: []types.DetectedVulnerability{
|
||||||
{
|
vuln1,
|
||||||
VulnerabilityID: "CVE-2019-0001",
|
vuln2,
|
||||||
PkgName: "foo",
|
|
||||||
InstalledVersion: "1.2.3",
|
|
||||||
FixedVersion: "1.2.4",
|
|
||||||
Vulnerability: dbTypes.Vulnerability{
|
|
||||||
Severity: dbTypes.SeverityLow.String(),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
VulnerabilityID: "CVE-2018-0002",
|
|
||||||
PkgName: "bar",
|
|
||||||
InstalledVersion: "1.2.3",
|
|
||||||
FixedVersion: "",
|
|
||||||
Status: dbTypes.StatusWillNotFix,
|
|
||||||
Vulnerability: dbTypes.Vulnerability{
|
|
||||||
Severity: dbTypes.SeverityHigh.String(),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -277,98 +313,28 @@ func TestFilter(t *testing.T) {
|
|||||||
Target: "package-lock.json",
|
Target: "package-lock.json",
|
||||||
Class: types.ClassLangPkg,
|
Class: types.ClassLangPkg,
|
||||||
Vulnerabilities: []types.DetectedVulnerability{
|
Vulnerabilities: []types.DetectedVulnerability{
|
||||||
{
|
vuln1, // ignored
|
||||||
// this vulnerability is ignored
|
vuln2, // filtered by severity
|
||||||
VulnerabilityID: "CVE-2019-0001",
|
vuln3,
|
||||||
PkgName: "foo",
|
vuln4,
|
||||||
InstalledVersion: "1.2.3",
|
vuln5, // ignored
|
||||||
FixedVersion: "1.2.4",
|
vuln6, // ignored
|
||||||
Vulnerability: dbTypes.Vulnerability{
|
|
||||||
Severity: dbTypes.SeverityLow.String(),
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// this vulnerability is ignored
|
Target: "deployment.yaml",
|
||||||
VulnerabilityID: "CVE-2019-0002",
|
|
||||||
PkgName: "foo",
|
|
||||||
InstalledVersion: "1.2.3",
|
|
||||||
FixedVersion: "1.2.4",
|
|
||||||
Vulnerability: dbTypes.Vulnerability{
|
|
||||||
Severity: dbTypes.SeverityLow.String(),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
VulnerabilityID: "CVE-2019-0003",
|
|
||||||
PkgName: "foo",
|
|
||||||
InstalledVersion: "1.2.3",
|
|
||||||
FixedVersion: "1.2.4",
|
|
||||||
Vulnerability: dbTypes.Vulnerability{
|
|
||||||
Severity: dbTypes.SeverityLow.String(),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
VulnerabilityID: "CVE-2022-0001",
|
|
||||||
PkgName: "foo",
|
|
||||||
InstalledVersion: "1.2.3",
|
|
||||||
FixedVersion: "1.2.4",
|
|
||||||
Vulnerability: dbTypes.Vulnerability{
|
|
||||||
Severity: dbTypes.SeverityLow.String(),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
// this vulnerability is ignored
|
|
||||||
VulnerabilityID: "CVE-2022-0002",
|
|
||||||
PkgName: "foo",
|
|
||||||
InstalledVersion: "1.2.3",
|
|
||||||
FixedVersion: "1.2.4",
|
|
||||||
Vulnerability: dbTypes.Vulnerability{
|
|
||||||
Severity: dbTypes.SeverityLow.String(),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
// this vulnerability is ignored
|
|
||||||
VulnerabilityID: "CVE-2022-0003",
|
|
||||||
PkgName: "foo",
|
|
||||||
InstalledVersion: "1.2.3",
|
|
||||||
FixedVersion: "1.2.4",
|
|
||||||
Vulnerability: dbTypes.Vulnerability{
|
|
||||||
Severity: dbTypes.SeverityLow.String(),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Target: "Dockerfile",
|
|
||||||
Class: types.ClassConfig,
|
Class: types.ClassConfig,
|
||||||
Misconfigurations: []types.DetectedMisconfiguration{
|
Misconfigurations: []types.DetectedMisconfiguration{
|
||||||
{
|
misconf1, // filtered by severity
|
||||||
Type: "Kubernetes Security Check",
|
misconf2,
|
||||||
ID: "ID100",
|
misconf3,
|
||||||
Title: "Bad Deployment",
|
|
||||||
Message: "something bad",
|
|
||||||
Severity: dbTypes.SeverityLow.String(),
|
|
||||||
Status: types.StatusFailure,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Secrets: []ftypes.SecretFinding{
|
Target: "config.yaml",
|
||||||
{
|
Secrets: []types.DetectedSecret{
|
||||||
RuleID: "generic-wanted-rule",
|
secret1,
|
||||||
Severity: dbTypes.SeverityLow.String(),
|
secret2,
|
||||||
Title: "Secret that should pass filter on rule id",
|
|
||||||
StartLine: 1,
|
|
||||||
EndLine: 2,
|
|
||||||
Match: "*****",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
RuleID: "generic-unwanted-rule",
|
|
||||||
Severity: dbTypes.SeverityLow.String(),
|
|
||||||
Title: "Secret that should not pass filter on rule id",
|
|
||||||
StartLine: 3,
|
|
||||||
EndLine: 4,
|
|
||||||
Match: "*****",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -382,44 +348,58 @@ func TestFilter(t *testing.T) {
|
|||||||
Target: "package-lock.json",
|
Target: "package-lock.json",
|
||||||
Class: types.ClassLangPkg,
|
Class: types.ClassLangPkg,
|
||||||
Vulnerabilities: []types.DetectedVulnerability{
|
Vulnerabilities: []types.DetectedVulnerability{
|
||||||
{
|
vuln3,
|
||||||
VulnerabilityID: "CVE-2019-0003",
|
vuln4,
|
||||||
PkgName: "foo",
|
|
||||||
InstalledVersion: "1.2.3",
|
|
||||||
FixedVersion: "1.2.4",
|
|
||||||
Vulnerability: dbTypes.Vulnerability{
|
|
||||||
Severity: dbTypes.SeverityLow.String(),
|
|
||||||
},
|
},
|
||||||
|
ModifiedFindings: []types.ModifiedFinding{
|
||||||
|
{
|
||||||
|
Type: types.FindingTypeVulnerability,
|
||||||
|
Status: types.FindingStatusIgnored,
|
||||||
|
Source: "testdata/.trivyignore",
|
||||||
|
Finding: vuln1,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
VulnerabilityID: "CVE-2022-0001",
|
Type: types.FindingTypeVulnerability,
|
||||||
PkgName: "foo",
|
Status: types.FindingStatusIgnored,
|
||||||
InstalledVersion: "1.2.3",
|
Source: "testdata/.trivyignore",
|
||||||
FixedVersion: "1.2.4",
|
Finding: vuln5,
|
||||||
Vulnerability: dbTypes.Vulnerability{
|
|
||||||
Severity: dbTypes.SeverityLow.String(),
|
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Type: types.FindingTypeVulnerability,
|
||||||
|
Status: types.FindingStatusIgnored,
|
||||||
|
Source: "testdata/.trivyignore",
|
||||||
|
Finding: vuln6,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Target: "Dockerfile",
|
Target: "deployment.yaml",
|
||||||
Class: types.ClassConfig,
|
Class: types.ClassConfig,
|
||||||
MisconfSummary: &types.MisconfSummary{
|
MisconfSummary: &types.MisconfSummary{
|
||||||
Successes: 0,
|
Successes: 1,
|
||||||
Failures: 0,
|
Failures: 0,
|
||||||
Exceptions: 1,
|
Exceptions: 1,
|
||||||
},
|
},
|
||||||
|
ModifiedFindings: []types.ModifiedFinding{
|
||||||
|
{
|
||||||
|
Type: types.FindingTypeMisconfiguration,
|
||||||
|
Status: types.FindingStatusIgnored,
|
||||||
|
Source: "testdata/.trivyignore",
|
||||||
|
Finding: misconf3,
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Secrets: []ftypes.SecretFinding{
|
Target: "config.yaml",
|
||||||
|
Secrets: []types.DetectedSecret{
|
||||||
|
secret1,
|
||||||
|
},
|
||||||
|
ModifiedFindings: []types.ModifiedFinding{
|
||||||
{
|
{
|
||||||
RuleID: "generic-wanted-rule",
|
Type: types.FindingTypeSecret,
|
||||||
Severity: dbTypes.SeverityLow.String(),
|
Status: types.FindingStatusIgnored,
|
||||||
Title: "Secret that should pass filter on rule id",
|
Source: "testdata/.trivyignore",
|
||||||
StartLine: 1,
|
Finding: secret2,
|
||||||
EndLine: 2,
|
|
||||||
Match: "*****",
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -434,146 +414,35 @@ func TestFilter(t *testing.T) {
|
|||||||
{
|
{
|
||||||
Target: "foo/package-lock.json",
|
Target: "foo/package-lock.json",
|
||||||
Vulnerabilities: []types.DetectedVulnerability{
|
Vulnerabilities: []types.DetectedVulnerability{
|
||||||
{
|
vuln1, // ignored
|
||||||
// this vulnerability is ignored
|
vuln2, // filtered by severity
|
||||||
VulnerabilityID: "CVE-2019-0001",
|
vuln3, // ignored
|
||||||
PkgName: "foo",
|
vuln4,
|
||||||
InstalledVersion: "1.2.3",
|
vuln5, // ignored
|
||||||
FixedVersion: "1.2.4",
|
vuln6,
|
||||||
Vulnerability: dbTypes.Vulnerability{
|
|
||||||
Severity: dbTypes.SeverityLow.String(),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
// this vulnerability is ignored
|
|
||||||
VulnerabilityID: "CVE-2019-0002",
|
|
||||||
PkgName: "foo",
|
|
||||||
InstalledVersion: "1.2.3",
|
|
||||||
FixedVersion: "1.2.4",
|
|
||||||
Vulnerability: dbTypes.Vulnerability{
|
|
||||||
Severity: dbTypes.SeverityLow.String(),
|
|
||||||
},
|
|
||||||
PkgPath: "bar/package.json",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
// this vulnerability is ignored
|
|
||||||
VulnerabilityID: "CVE-2019-0003",
|
|
||||||
PkgName: "foo",
|
|
||||||
InstalledVersion: "1.2.3",
|
|
||||||
FixedVersion: "1.2.4",
|
|
||||||
Vulnerability: dbTypes.Vulnerability{
|
|
||||||
Severity: dbTypes.SeverityLow.String(),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
VulnerabilityID: "CVE-2019-0004",
|
|
||||||
PkgName: "foo",
|
|
||||||
InstalledVersion: "1.2.3",
|
|
||||||
FixedVersion: "1.2.4",
|
|
||||||
Vulnerability: dbTypes.Vulnerability{
|
|
||||||
Severity: dbTypes.SeverityLow.String(),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
// this vulnerability is ignored
|
|
||||||
VulnerabilityID: "CVE-2019-0005",
|
|
||||||
PkgName: "foo",
|
|
||||||
InstalledVersion: "1.2.3",
|
|
||||||
FixedVersion: "1.2.4",
|
|
||||||
Vulnerability: dbTypes.Vulnerability{
|
|
||||||
Severity: dbTypes.SeverityLow.String(),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
VulnerabilityID: "CVE-2019-0006",
|
|
||||||
PkgName: "foo",
|
|
||||||
InstalledVersion: "1.2.3",
|
|
||||||
FixedVersion: "1.2.4",
|
|
||||||
Vulnerability: dbTypes.Vulnerability{
|
|
||||||
Severity: dbTypes.SeverityLow.String(),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Target: "app/Dockerfile",
|
Target: "app/Dockerfile",
|
||||||
Misconfigurations: []types.DetectedMisconfiguration{
|
Misconfigurations: []types.DetectedMisconfiguration{
|
||||||
{
|
misconf1, // filtered by severity
|
||||||
// this misconfiguration is ignored
|
misconf2, // ignored
|
||||||
Type: "Kubernetes Security Check",
|
misconf3,
|
||||||
ID: "ID100",
|
|
||||||
Title: "Bad Deployment",
|
|
||||||
Message: "something bad",
|
|
||||||
Severity: dbTypes.SeverityLow.String(),
|
|
||||||
Status: types.StatusFailure,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
// this misconfiguration is ignored
|
|
||||||
Type: "Kubernetes Security Check",
|
|
||||||
ID: "ID200",
|
|
||||||
Title: "Bad Deployment",
|
|
||||||
Message: "something bad",
|
|
||||||
Severity: dbTypes.SeverityLow.String(),
|
|
||||||
Status: types.StatusFailure,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Type: "Kubernetes Security Check",
|
|
||||||
ID: "ID300",
|
|
||||||
Title: "Bad Deployment",
|
|
||||||
Message: "something bad",
|
|
||||||
Severity: dbTypes.SeverityLow.String(),
|
|
||||||
Status: types.StatusFailure,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Target: "config.yaml",
|
Target: "config.yaml",
|
||||||
Secrets: []ftypes.SecretFinding{
|
Secrets: []types.DetectedSecret{
|
||||||
{
|
secret1,
|
||||||
RuleID: "generic-wanted-rule",
|
secret2, // ignored
|
||||||
Severity: dbTypes.SeverityLow.String(),
|
secret3, // ignored
|
||||||
Title: "Secret that should pass filter on rule id",
|
|
||||||
StartLine: 1,
|
|
||||||
EndLine: 2,
|
|
||||||
Match: "*****",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
// this secret is ignored
|
|
||||||
RuleID: "generic-unwanted-rule",
|
|
||||||
Severity: dbTypes.SeverityLow.String(),
|
|
||||||
Title: "Secret that should not pass filter on rule id",
|
|
||||||
StartLine: 3,
|
|
||||||
EndLine: 4,
|
|
||||||
Match: "*****",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
// this secret is ignored
|
|
||||||
RuleID: "generic-unwanted-rule2",
|
|
||||||
Severity: dbTypes.SeverityLow.String(),
|
|
||||||
Title: "Secret that should not pass filter on rule id",
|
|
||||||
StartLine: 5,
|
|
||||||
EndLine: 6,
|
|
||||||
Match: "*****",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
Target: "LICENSE.txt",
|
||||||
Licenses: []types.DetectedLicense{
|
Licenses: []types.DetectedLicense{
|
||||||
{
|
license1, // ignored
|
||||||
// this license is ignored
|
license2,
|
||||||
Name: "GPL-3.0",
|
|
||||||
Severity: dbTypes.SeverityLow.String(),
|
|
||||||
FilePath: "usr/share/gcc/python/libstdcxx/v6/__init__.py",
|
|
||||||
Category: "restricted",
|
|
||||||
Confidence: 1,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "GPL-3.0",
|
|
||||||
Severity: dbTypes.SeverityLow.String(),
|
|
||||||
FilePath: "usr/share/gcc/python/libstdcxx/v6/printers.py",
|
|
||||||
Category: "restricted",
|
|
||||||
Confidence: 1,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -586,23 +455,27 @@ func TestFilter(t *testing.T) {
|
|||||||
{
|
{
|
||||||
Target: "foo/package-lock.json",
|
Target: "foo/package-lock.json",
|
||||||
Vulnerabilities: []types.DetectedVulnerability{
|
Vulnerabilities: []types.DetectedVulnerability{
|
||||||
{
|
vuln4,
|
||||||
VulnerabilityID: "CVE-2019-0004",
|
vuln6,
|
||||||
PkgName: "foo",
|
|
||||||
InstalledVersion: "1.2.3",
|
|
||||||
FixedVersion: "1.2.4",
|
|
||||||
Vulnerability: dbTypes.Vulnerability{
|
|
||||||
Severity: dbTypes.SeverityLow.String(),
|
|
||||||
},
|
},
|
||||||
|
ModifiedFindings: []types.ModifiedFinding{
|
||||||
|
{
|
||||||
|
Type: types.FindingTypeVulnerability,
|
||||||
|
Status: types.FindingStatusIgnored,
|
||||||
|
Source: "testdata/.trivyignore.yaml",
|
||||||
|
Finding: vuln1,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
VulnerabilityID: "CVE-2019-0006",
|
Type: types.FindingTypeVulnerability,
|
||||||
PkgName: "foo",
|
Status: types.FindingStatusIgnored,
|
||||||
InstalledVersion: "1.2.3",
|
Source: "testdata/.trivyignore.yaml",
|
||||||
FixedVersion: "1.2.4",
|
Finding: vuln3,
|
||||||
Vulnerability: dbTypes.Vulnerability{
|
|
||||||
Severity: dbTypes.SeverityLow.String(),
|
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Type: types.FindingTypeVulnerability,
|
||||||
|
Status: types.FindingStatusIgnored,
|
||||||
|
Source: "testdata/.trivyignore.yaml",
|
||||||
|
Finding: vuln5,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -611,40 +484,51 @@ func TestFilter(t *testing.T) {
|
|||||||
MisconfSummary: &types.MisconfSummary{
|
MisconfSummary: &types.MisconfSummary{
|
||||||
Successes: 0,
|
Successes: 0,
|
||||||
Failures: 1,
|
Failures: 1,
|
||||||
Exceptions: 2,
|
Exceptions: 1,
|
||||||
},
|
},
|
||||||
Misconfigurations: []types.DetectedMisconfiguration{
|
Misconfigurations: []types.DetectedMisconfiguration{
|
||||||
|
misconf3,
|
||||||
|
},
|
||||||
|
ModifiedFindings: []types.ModifiedFinding{
|
||||||
{
|
{
|
||||||
Type: "Kubernetes Security Check",
|
Type: types.FindingTypeMisconfiguration,
|
||||||
ID: "ID300",
|
Status: types.FindingStatusIgnored,
|
||||||
Title: "Bad Deployment",
|
Source: "testdata/.trivyignore.yaml",
|
||||||
Message: "something bad",
|
Finding: misconf2,
|
||||||
Severity: dbTypes.SeverityLow.String(),
|
|
||||||
Status: types.StatusFailure,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Target: "config.yaml",
|
Target: "config.yaml",
|
||||||
Secrets: []ftypes.SecretFinding{
|
Secrets: []types.DetectedSecret{
|
||||||
|
secret1,
|
||||||
|
},
|
||||||
|
ModifiedFindings: []types.ModifiedFinding{
|
||||||
{
|
{
|
||||||
RuleID: "generic-wanted-rule",
|
Type: types.FindingTypeSecret,
|
||||||
Severity: dbTypes.SeverityLow.String(),
|
Status: types.FindingStatusIgnored,
|
||||||
Title: "Secret that should pass filter on rule id",
|
Source: "testdata/.trivyignore.yaml",
|
||||||
StartLine: 1,
|
Finding: secret2,
|
||||||
EndLine: 2,
|
},
|
||||||
Match: "*****",
|
{
|
||||||
|
Type: types.FindingTypeSecret,
|
||||||
|
Status: types.FindingStatusIgnored,
|
||||||
|
Source: "testdata/.trivyignore.yaml",
|
||||||
|
Finding: secret3,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
Target: "LICENSE.txt",
|
||||||
Licenses: []types.DetectedLicense{
|
Licenses: []types.DetectedLicense{
|
||||||
|
license2,
|
||||||
|
},
|
||||||
|
ModifiedFindings: []types.ModifiedFinding{
|
||||||
{
|
{
|
||||||
Name: "GPL-3.0",
|
Type: types.FindingTypeLicense,
|
||||||
Severity: dbTypes.SeverityLow.String(),
|
Status: types.FindingStatusIgnored,
|
||||||
FilePath: "usr/share/gcc/python/libstdcxx/v6/printers.py",
|
Source: "testdata/.trivyignore.yaml",
|
||||||
Category: "restricted",
|
Finding: license1,
|
||||||
Confidence: 1,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -652,60 +536,35 @@ func TestFilter(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "policy file",
|
name: "policy file for vulnerabilities",
|
||||||
args: args{
|
args: args{
|
||||||
report: types.Report{
|
report: types.Report{
|
||||||
Results: types.Results{
|
Results: types.Results{
|
||||||
{
|
{
|
||||||
Vulnerabilities: []types.DetectedVulnerability{
|
Vulnerabilities: []types.DetectedVulnerability{
|
||||||
{
|
vuln1,
|
||||||
VulnerabilityID: "CVE-2019-0001",
|
vuln2, // ignored by severity
|
||||||
PkgName: "foo",
|
vuln3, // ignored by policy
|
||||||
InstalledVersion: "1.2.3",
|
|
||||||
FixedVersion: "1.2.4",
|
|
||||||
Vulnerability: dbTypes.Vulnerability{
|
|
||||||
Severity: dbTypes.SeverityLow.String(),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
// this vulnerability is ignored
|
|
||||||
VulnerabilityID: "CVE-2019-0002",
|
|
||||||
PkgName: "foo",
|
|
||||||
InstalledVersion: "1.2.3",
|
|
||||||
FixedVersion: "1.2.4",
|
|
||||||
Vulnerability: dbTypes.Vulnerability{
|
|
||||||
Severity: dbTypes.SeverityLow.String(),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
// this vulnerability is ignored
|
|
||||||
VulnerabilityID: "CVE-2019-0003",
|
|
||||||
PkgName: "foo",
|
|
||||||
InstalledVersion: "1.2.3",
|
|
||||||
FixedVersion: "1.2.4",
|
|
||||||
Vulnerability: dbTypes.Vulnerability{
|
|
||||||
Severity: dbTypes.SeverityLow.String(),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
severities: []dbTypes.Severity{dbTypes.SeverityLow},
|
severities: []dbTypes.Severity{dbTypes.SeverityLow},
|
||||||
policyFile: "./testdata/test.rego",
|
policyFile: "./testdata/ignore-vuln.rego",
|
||||||
},
|
},
|
||||||
want: types.Report{
|
want: types.Report{
|
||||||
Results: types.Results{
|
Results: types.Results{
|
||||||
{
|
{
|
||||||
Vulnerabilities: []types.DetectedVulnerability{
|
Vulnerabilities: []types.DetectedVulnerability{
|
||||||
{
|
vuln1,
|
||||||
VulnerabilityID: "CVE-2019-0001",
|
|
||||||
PkgName: "foo",
|
|
||||||
InstalledVersion: "1.2.3",
|
|
||||||
FixedVersion: "1.2.4",
|
|
||||||
Vulnerability: dbTypes.Vulnerability{
|
|
||||||
Severity: dbTypes.SeverityLow.String(),
|
|
||||||
},
|
},
|
||||||
|
ModifiedFindings: []types.ModifiedFinding{
|
||||||
|
{
|
||||||
|
Type: types.FindingTypeVulnerability,
|
||||||
|
Status: types.FindingStatusIgnored,
|
||||||
|
Statement: "Filtered by Rego",
|
||||||
|
Source: "testdata/ignore-vuln.rego",
|
||||||
|
Finding: vuln3,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -713,60 +572,43 @@ func TestFilter(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "ignore file for misconf",
|
name: "policy file for misconfigurations",
|
||||||
args: args{
|
args: args{
|
||||||
report: types.Report{
|
report: types.Report{
|
||||||
Results: types.Results{
|
Results: types.Results{
|
||||||
{
|
{
|
||||||
Misconfigurations: []types.DetectedMisconfiguration{
|
Misconfigurations: []types.DetectedMisconfiguration{
|
||||||
{
|
misconf1,
|
||||||
ID: "AVD-TEST-0001",
|
misconf2,
|
||||||
AVDID: "AVD-TEST-0001",
|
misconf3, // ignored by policy
|
||||||
Title: "test-0001",
|
|
||||||
Description: "foo",
|
|
||||||
Severity: dbTypes.SeverityHigh.String(),
|
|
||||||
Status: types.StatusFailure,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
ID: "AVD-TEST-0002",
|
|
||||||
AVDID: "AVD-TEST-0002",
|
|
||||||
Title: "test-0002",
|
|
||||||
Description: "bar",
|
|
||||||
Severity: dbTypes.SeverityHigh.String(),
|
|
||||||
Status: types.StatusPassed,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
// this misconf is ignored
|
|
||||||
ID: "AVD-TEST-0003",
|
|
||||||
AVDID: "AVD-TEST-0003",
|
|
||||||
Title: "test-0003",
|
|
||||||
Description: "baz",
|
|
||||||
Severity: dbTypes.SeverityHigh.String(),
|
|
||||||
Status: types.StatusFailure,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
severities: []dbTypes.Severity{
|
||||||
|
dbTypes.SeverityLow,
|
||||||
|
dbTypes.SeverityHigh,
|
||||||
},
|
},
|
||||||
severities: []dbTypes.Severity{dbTypes.SeverityHigh},
|
policyFile: "./testdata/ignore-misconf.rego",
|
||||||
policyFile: "./testdata/test-ignore-policy-misconf.rego",
|
|
||||||
},
|
},
|
||||||
want: types.Report{
|
want: types.Report{
|
||||||
Results: types.Results{
|
Results: types.Results{
|
||||||
{
|
{
|
||||||
MisconfSummary: &types.MisconfSummary{
|
MisconfSummary: &types.MisconfSummary{
|
||||||
Successes: 1,
|
Successes: 1,
|
||||||
Failures: 2,
|
Failures: 1,
|
||||||
Exceptions: 1,
|
Exceptions: 1,
|
||||||
},
|
},
|
||||||
Misconfigurations: []types.DetectedMisconfiguration{
|
Misconfigurations: []types.DetectedMisconfiguration{
|
||||||
|
misconf1,
|
||||||
|
},
|
||||||
|
ModifiedFindings: []types.ModifiedFinding{
|
||||||
{
|
{
|
||||||
ID: "AVD-TEST-0001",
|
Type: types.FindingTypeMisconfiguration,
|
||||||
AVDID: "AVD-TEST-0001",
|
Status: types.FindingStatusIgnored,
|
||||||
Title: "test-0001",
|
Statement: "Filtered by Rego",
|
||||||
Description: "foo",
|
Source: "testdata/ignore-misconf.rego",
|
||||||
Severity: dbTypes.SeverityHigh.String(),
|
Finding: misconf3,
|
||||||
Status: types.StatusFailure,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ type IgnoreFinding struct {
|
|||||||
|
|
||||||
type IgnoreFindings []IgnoreFinding
|
type IgnoreFindings []IgnoreFinding
|
||||||
|
|
||||||
func (f *IgnoreFindings) Match(path, id string) bool {
|
func (f *IgnoreFindings) Match(id, path string) *IgnoreFinding {
|
||||||
for _, finding := range *f {
|
for _, finding := range *f {
|
||||||
if id != finding.ID {
|
if id != finding.ID {
|
||||||
continue
|
continue
|
||||||
@@ -53,10 +53,10 @@ func (f *IgnoreFindings) Match(path, id string) bool {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
log.Logger.Debugw("Ignored", log.String("id", id), log.String("path", path))
|
log.Logger.Debugw("Ignored", log.String("id", id), log.String("path", path))
|
||||||
return true
|
return &finding
|
||||||
|
|
||||||
}
|
}
|
||||||
return false
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func pathMatch(path string, patterns []string) bool {
|
func pathMatch(path string, patterns []string) bool {
|
||||||
@@ -96,13 +96,48 @@ func (f *IgnoreFindings) Filter(ctx context.Context) {
|
|||||||
|
|
||||||
// IgnoreConfig represents the structure of .trivyignore.yaml.
|
// IgnoreConfig represents the structure of .trivyignore.yaml.
|
||||||
type IgnoreConfig struct {
|
type IgnoreConfig struct {
|
||||||
|
FilePath string
|
||||||
Vulnerabilities IgnoreFindings `yaml:"vulnerabilities"`
|
Vulnerabilities IgnoreFindings `yaml:"vulnerabilities"`
|
||||||
Misconfigurations IgnoreFindings `yaml:"misconfigurations"`
|
Misconfigurations IgnoreFindings `yaml:"misconfigurations"`
|
||||||
Secrets IgnoreFindings `yaml:"secrets"`
|
Secrets IgnoreFindings `yaml:"secrets"`
|
||||||
Licenses IgnoreFindings `yaml:"licenses"`
|
Licenses IgnoreFindings `yaml:"licenses"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func getIgnoredFindings(ctx context.Context, ignoreFile string) (IgnoreConfig, error) {
|
func (c *IgnoreConfig) MatchVulnerability(vulnID, filePath, pkgPath string) *IgnoreFinding {
|
||||||
|
paths := []string{
|
||||||
|
filePath,
|
||||||
|
pkgPath,
|
||||||
|
}
|
||||||
|
for _, p := range paths {
|
||||||
|
if f := c.Vulnerabilities.Match(vulnID, p); f != nil {
|
||||||
|
return f
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *IgnoreConfig) MatchMisconfiguration(misconfID, avdID, filePath string) *IgnoreFinding {
|
||||||
|
ids := []string{
|
||||||
|
misconfID,
|
||||||
|
avdID,
|
||||||
|
}
|
||||||
|
for _, id := range ids {
|
||||||
|
if f := c.Misconfigurations.Match(id, filePath); f != nil {
|
||||||
|
return f
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *IgnoreConfig) MatchSecret(secretID, filePath string) *IgnoreFinding {
|
||||||
|
return c.Secrets.Match(secretID, filePath)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *IgnoreConfig) MatchLicense(licenseID, filePath string) *IgnoreFinding {
|
||||||
|
return c.Licenses.Match(licenseID, filePath)
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseIgnoreFile(ctx context.Context, ignoreFile string) (IgnoreConfig, error) {
|
||||||
var conf IgnoreConfig
|
var conf IgnoreConfig
|
||||||
if _, err := os.Stat(ignoreFile); errors.Is(err, fs.ErrNotExist) {
|
if _, err := os.Stat(ignoreFile); errors.Is(err, fs.ErrNotExist) {
|
||||||
// .trivyignore doesn't necessarily exist
|
// .trivyignore doesn't necessarily exist
|
||||||
@@ -132,6 +167,7 @@ func getIgnoredFindings(ctx context.Context, ignoreFile string) (IgnoreConfig, e
|
|||||||
conf.Misconfigurations.Filter(ctx)
|
conf.Misconfigurations.Filter(ctx)
|
||||||
conf.Secrets.Filter(ctx)
|
conf.Secrets.Filter(ctx)
|
||||||
conf.Licenses.Filter(ctx)
|
conf.Licenses.Filter(ctx)
|
||||||
|
conf.FilePath = filepath.ToSlash(filepath.Clean(ignoreFile))
|
||||||
|
|
||||||
return conf, nil
|
return conf, nil
|
||||||
}
|
}
|
||||||
|
|||||||
8
pkg/result/testdata/.trivyignore
vendored
8
pkg/result/testdata/.trivyignore
vendored
@@ -1,12 +1,12 @@
|
|||||||
# vulnerabilities
|
# vulnerabilities
|
||||||
CVE-2019-0001
|
CVE-2019-0001
|
||||||
CVE-2019-0002
|
CVE-2019-0002
|
||||||
CVE-2022-0001 exp:2020-01-01
|
CVE-2019-0004 exp:2020-01-01
|
||||||
CVE-2022-0002 exp:9999-01-01
|
CVE-2019-0005 exp:9999-01-01
|
||||||
CVE-2022-0003 exp:9999-01-01 key2:value2
|
CVE-2019-0006 exp:9999-01-01 key2:value2
|
||||||
|
|
||||||
# misconfigurations
|
# misconfigurations
|
||||||
ID100
|
ID300
|
||||||
|
|
||||||
# secrets
|
# secrets
|
||||||
generic-unwanted-rule
|
generic-unwanted-rule
|
||||||
@@ -5,5 +5,5 @@ import data.lib.trivy
|
|||||||
default ignore=false
|
default ignore=false
|
||||||
|
|
||||||
ignore {
|
ignore {
|
||||||
input.AVDID != "AVD-TEST-0001"
|
input.AVDID != "AVD-ID100"
|
||||||
}
|
}
|
||||||
@@ -393,7 +393,7 @@ func ConvertFromRPCResults(rpcResults []*scanner.Result) []types.Result {
|
|||||||
Type: ftypes.TargetType(result.Type),
|
Type: ftypes.TargetType(result.Type),
|
||||||
Packages: ConvertFromRPCPkgs(result.Packages),
|
Packages: ConvertFromRPCPkgs(result.Packages),
|
||||||
CustomResources: ConvertFromRPCCustomResources(result.CustomResources),
|
CustomResources: ConvertFromRPCCustomResources(result.CustomResources),
|
||||||
Secrets: ConvertFromRPCSecretFindings(result.Secrets),
|
Secrets: ConvertFromRPCDetectedSecrets(result.Secrets),
|
||||||
Licenses: ConvertFromRPCDetectedLicenses(result.Licenses),
|
Licenses: ConvertFromRPCDetectedLicenses(result.Licenses),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -461,6 +461,15 @@ func ConvertFromRPCCode(rpcCode *common.Code) ftypes.Code {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ConvertFromRPCDetectedSecrets(rpcFindings []*common.SecretFinding) []types.DetectedSecret {
|
||||||
|
if len(rpcFindings) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return lo.Map(ConvertFromRPCSecretFindings(rpcFindings), func(s ftypes.SecretFinding, _ int) types.DetectedSecret {
|
||||||
|
return types.DetectedSecret(s)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func ConvertFromRPCSecretFindings(rpcFindings []*common.SecretFinding) []ftypes.SecretFinding {
|
func ConvertFromRPCSecretFindings(rpcFindings []*common.SecretFinding) []ftypes.SecretFinding {
|
||||||
var findings []ftypes.SecretFinding
|
var findings []ftypes.SecretFinding
|
||||||
for _, finding := range rpcFindings {
|
for _, finding := range rpcFindings {
|
||||||
@@ -913,16 +922,19 @@ func ConvertToMissingBlobsRequest(imageID string, layerIDs []string) *cache.Miss
|
|||||||
func ConvertToRPCScanResponse(results types.Results, fos ftypes.OS) *scanner.ScanResponse {
|
func ConvertToRPCScanResponse(results types.Results, fos ftypes.OS) *scanner.ScanResponse {
|
||||||
var rpcResults []*scanner.Result
|
var rpcResults []*scanner.Result
|
||||||
for _, result := range results {
|
for _, result := range results {
|
||||||
|
secretFindings := lo.Map(result.Secrets, func(s types.DetectedSecret, _ int) ftypes.SecretFinding {
|
||||||
|
return ftypes.SecretFinding(s)
|
||||||
|
})
|
||||||
rpcResults = append(rpcResults, &scanner.Result{
|
rpcResults = append(rpcResults, &scanner.Result{
|
||||||
Target: result.Target,
|
Target: result.Target,
|
||||||
Class: string(result.Class),
|
Class: string(result.Class),
|
||||||
Type: string(result.Type),
|
Type: string(result.Type),
|
||||||
|
Packages: ConvertToRPCPkgs(result.Packages),
|
||||||
Vulnerabilities: ConvertToRPCVulns(result.Vulnerabilities),
|
Vulnerabilities: ConvertToRPCVulns(result.Vulnerabilities),
|
||||||
Misconfigurations: ConvertToRPCMisconfs(result.Misconfigurations),
|
Misconfigurations: ConvertToRPCMisconfs(result.Misconfigurations),
|
||||||
Packages: ConvertToRPCPkgs(result.Packages),
|
Secrets: ConvertToRPCSecretFindings(secretFindings),
|
||||||
CustomResources: ConvertToRPCCustomResources(result.CustomResources),
|
|
||||||
Secrets: ConvertToRPCSecretFindings(result.Secrets),
|
|
||||||
Licenses: ConvertToRPCLicenses(result.Licenses),
|
Licenses: ConvertToRPCLicenses(result.Licenses),
|
||||||
|
CustomResources: ConvertToRPCCustomResources(result.CustomResources),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -885,7 +885,7 @@ func TestMarshaler_Marshal(t *testing.T) {
|
|||||||
{
|
{
|
||||||
Target: "key.pem",
|
Target: "key.pem",
|
||||||
Class: types.ClassSecret,
|
Class: types.ClassSecret,
|
||||||
Secrets: []ftypes.SecretFinding{
|
Secrets: []types.DetectedSecret{
|
||||||
{
|
{
|
||||||
RuleID: "private-key",
|
RuleID: "private-key",
|
||||||
Category: "AsymmetricPrivateKey",
|
Category: "AsymmetricPrivateKey",
|
||||||
|
|||||||
@@ -229,16 +229,16 @@ func (s Scanner) MisconfsToResults(misconfs []ftypes.Misconfiguration) types.Res
|
|||||||
var detected []types.DetectedMisconfiguration
|
var detected []types.DetectedMisconfiguration
|
||||||
|
|
||||||
for _, f := range misconf.Failures {
|
for _, f := range misconf.Failures {
|
||||||
detected = append(detected, toDetectedMisconfiguration(f, dbTypes.SeverityCritical, types.StatusFailure, misconf.Layer))
|
detected = append(detected, toDetectedMisconfiguration(f, dbTypes.SeverityCritical, types.MisconfStatusFailure, misconf.Layer))
|
||||||
}
|
}
|
||||||
for _, w := range misconf.Warnings {
|
for _, w := range misconf.Warnings {
|
||||||
detected = append(detected, toDetectedMisconfiguration(w, dbTypes.SeverityMedium, types.StatusFailure, misconf.Layer))
|
detected = append(detected, toDetectedMisconfiguration(w, dbTypes.SeverityMedium, types.MisconfStatusFailure, misconf.Layer))
|
||||||
}
|
}
|
||||||
for _, w := range misconf.Successes {
|
for _, w := range misconf.Successes {
|
||||||
detected = append(detected, toDetectedMisconfiguration(w, dbTypes.SeverityUnknown, types.StatusPassed, misconf.Layer))
|
detected = append(detected, toDetectedMisconfiguration(w, dbTypes.SeverityUnknown, types.MisconfStatusPassed, misconf.Layer))
|
||||||
}
|
}
|
||||||
for _, w := range misconf.Exceptions {
|
for _, w := range misconf.Exceptions {
|
||||||
detected = append(detected, toDetectedMisconfiguration(w, dbTypes.SeverityUnknown, types.StatusException, misconf.Layer))
|
detected = append(detected, toDetectedMisconfiguration(w, dbTypes.SeverityUnknown, types.MisconfStatusException, misconf.Layer))
|
||||||
}
|
}
|
||||||
|
|
||||||
results = append(results, types.Result{
|
results = append(results, types.Result{
|
||||||
@@ -268,7 +268,9 @@ func (s Scanner) secretsToResults(secrets []ftypes.Secret, options types.ScanOpt
|
|||||||
results = append(results, types.Result{
|
results = append(results, types.Result{
|
||||||
Target: secret.FilePath,
|
Target: secret.FilePath,
|
||||||
Class: types.ClassSecret,
|
Class: types.ClassSecret,
|
||||||
Secrets: secret.Findings,
|
Secrets: lo.Map(secret.Findings, func(secret ftypes.SecretFinding, index int) types.DetectedSecret {
|
||||||
|
return types.DetectedSecret(secret)
|
||||||
|
}),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return results
|
return results
|
||||||
|
|||||||
@@ -981,7 +981,7 @@ func TestScanner_Scan(t *testing.T) {
|
|||||||
Message: "something bad",
|
Message: "something bad",
|
||||||
Namespace: "main.kubernetes.id100",
|
Namespace: "main.kubernetes.id100",
|
||||||
Severity: "HIGH",
|
Severity: "HIGH",
|
||||||
Status: types.StatusFailure,
|
Status: types.MisconfStatusFailure,
|
||||||
Layer: ftypes.Layer{
|
Layer: ftypes.Layer{
|
||||||
DiffID: "sha256:9922bc15eeefe1637b803ef2106f178152ce19a391f24aec838cbe2e48e73303",
|
DiffID: "sha256:9922bc15eeefe1637b803ef2106f178152ce19a391f24aec838cbe2e48e73303",
|
||||||
},
|
},
|
||||||
@@ -997,7 +997,7 @@ func TestScanner_Scan(t *testing.T) {
|
|||||||
References: []string{
|
References: []string{
|
||||||
"https://avd.aquasec.com/misconfig/id200",
|
"https://avd.aquasec.com/misconfig/id200",
|
||||||
},
|
},
|
||||||
Status: types.StatusPassed,
|
Status: types.MisconfStatusPassed,
|
||||||
Layer: ftypes.Layer{
|
Layer: ftypes.Layer{
|
||||||
DiffID: "sha256:9922bc15eeefe1637b803ef2106f178152ce19a391f24aec838cbe2e48e73303",
|
DiffID: "sha256:9922bc15eeefe1637b803ef2106f178152ce19a391f24aec838cbe2e48e73303",
|
||||||
},
|
},
|
||||||
@@ -1016,7 +1016,7 @@ func TestScanner_Scan(t *testing.T) {
|
|||||||
Message: "No issues found",
|
Message: "No issues found",
|
||||||
Namespace: "main.kubernetes.id300",
|
Namespace: "main.kubernetes.id300",
|
||||||
Severity: "MEDIUM",
|
Severity: "MEDIUM",
|
||||||
Status: types.StatusFailure,
|
Status: types.MisconfStatusFailure,
|
||||||
Layer: ftypes.Layer{
|
Layer: ftypes.Layer{
|
||||||
DiffID: "sha256:9922bc15eeefe1637b803ef2106f178152ce19a391f24aec838cbe2e48e73303",
|
DiffID: "sha256:9922bc15eeefe1637b803ef2106f178152ce19a391f24aec838cbe2e48e73303",
|
||||||
},
|
},
|
||||||
@@ -1028,7 +1028,7 @@ func TestScanner_Scan(t *testing.T) {
|
|||||||
Message: "No issues found",
|
Message: "No issues found",
|
||||||
Namespace: "main.kubernetes.id100",
|
Namespace: "main.kubernetes.id100",
|
||||||
Severity: "HIGH",
|
Severity: "HIGH",
|
||||||
Status: types.StatusException,
|
Status: types.MisconfStatusException,
|
||||||
Layer: ftypes.Layer{
|
Layer: ftypes.Layer{
|
||||||
DiffID: "sha256:9922bc15eeefe1637b803ef2106f178152ce19a391f24aec838cbe2e48e73303",
|
DiffID: "sha256:9922bc15eeefe1637b803ef2106f178152ce19a391f24aec838cbe2e48e73303",
|
||||||
},
|
},
|
||||||
@@ -1199,7 +1199,7 @@ func TestScanner_Scan(t *testing.T) {
|
|||||||
Description: "Running containers with 'root' user can lead to a container escape situation. It is a best practice to run containers as non-root users, which can be done by adding a 'USER' statement to the Dockerfile.",
|
Description: "Running containers with 'root' user can lead to a container escape situation. It is a best practice to run containers as non-root users, which can be done by adding a 'USER' statement to the Dockerfile.",
|
||||||
Severity: "HIGH",
|
Severity: "HIGH",
|
||||||
Resolution: "Add 'USER <non root user name>' line to the Dockerfile",
|
Resolution: "Add 'USER <non root user name>' line to the Dockerfile",
|
||||||
Status: types.StatusFailure,
|
Status: types.MisconfStatusFailure,
|
||||||
PrimaryURL: "https://avd.aquasec.com/misconfig/ds002",
|
PrimaryURL: "https://avd.aquasec.com/misconfig/ds002",
|
||||||
References: []string{"https://avd.aquasec.com/misconfig/ds002"},
|
References: []string{"https://avd.aquasec.com/misconfig/ds002"},
|
||||||
CauseMetadata: ftypes.CauseMetadata{
|
CauseMetadata: ftypes.CauseMetadata{
|
||||||
@@ -1219,7 +1219,7 @@ func TestScanner_Scan(t *testing.T) {
|
|||||||
Description: "When using a 'FROM' statement you should use a specific tag to avoid uncontrolled behavior when the image is updated.",
|
Description: "When using a 'FROM' statement you should use a specific tag to avoid uncontrolled behavior when the image is updated.",
|
||||||
Severity: "MEDIUM",
|
Severity: "MEDIUM",
|
||||||
Resolution: "Add a tag to the image in the 'FROM' statement",
|
Resolution: "Add a tag to the image in the 'FROM' statement",
|
||||||
Status: types.StatusPassed,
|
Status: types.MisconfStatusPassed,
|
||||||
CauseMetadata: ftypes.CauseMetadata{
|
CauseMetadata: ftypes.CauseMetadata{
|
||||||
Provider: "Dockerfile",
|
Provider: "Dockerfile",
|
||||||
Service: "general",
|
Service: "general",
|
||||||
|
|||||||
47
pkg/types/finding.go
Normal file
47
pkg/types/finding.go
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
package types
|
||||||
|
|
||||||
|
type FindingType string
|
||||||
|
type FindingStatus string
|
||||||
|
|
||||||
|
const (
|
||||||
|
FindingTypeVulnerability FindingType = "vulnerability"
|
||||||
|
FindingTypeMisconfiguration FindingType = "misconfiguration"
|
||||||
|
FindingTypeSecret FindingType = "secret"
|
||||||
|
FindingTypeLicense FindingType = "license"
|
||||||
|
|
||||||
|
FindingStatusIgnored FindingStatus = "ignored" // Trivy
|
||||||
|
FindingStatusUnknown FindingStatus = "unknown" // Trivy
|
||||||
|
FindingStatusNotAffected FindingStatus = "not_affected" // VEX
|
||||||
|
FindingStatusAffected FindingStatus = "affected" // VEX
|
||||||
|
FindingStatusFixed FindingStatus = "fixed" // VEX
|
||||||
|
FindingStatusUnderInvestigation FindingStatus = "under_investigation" // VEX
|
||||||
|
)
|
||||||
|
|
||||||
|
// Finding represents one of the findings that Trivy can detect,
|
||||||
|
// such as vulnerabilities, misconfigurations, secrets, and licenses.
|
||||||
|
type finding interface {
|
||||||
|
findingType() FindingType
|
||||||
|
}
|
||||||
|
|
||||||
|
// ModifiedFinding represents a security finding that has been modified by an external source,
|
||||||
|
// such as .trivyignore and VEX. Currently, it is primarily used to account for vulnerabilities
|
||||||
|
// that are ignored via .trivyignore or identified as not impactful through VEX.
|
||||||
|
// However, it is planned to also store vulnerabilities whose severity has been adjusted by VEX,
|
||||||
|
// or that have been detected through Wasm modules in the future.
|
||||||
|
type ModifiedFinding struct {
|
||||||
|
Type FindingType
|
||||||
|
Status FindingStatus
|
||||||
|
Statement string
|
||||||
|
Source string
|
||||||
|
Finding finding // one of findings
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewModifiedFinding(f finding, status FindingStatus, statement, source string) ModifiedFinding {
|
||||||
|
return ModifiedFinding{
|
||||||
|
Type: f.findingType(),
|
||||||
|
Status: status,
|
||||||
|
Statement: statement,
|
||||||
|
Source: source,
|
||||||
|
Finding: f,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -29,3 +29,5 @@ type DetectedLicense struct {
|
|||||||
// Link is a SPDX link of the license
|
// Link is a SPDX link of the license
|
||||||
Link string
|
Link string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (DetectedLicense) findingType() FindingType { return FindingTypeLicense }
|
||||||
|
|||||||
@@ -28,17 +28,14 @@ type DetectedMisconfiguration struct {
|
|||||||
type MisconfStatus string
|
type MisconfStatus string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// StatusPassed represents successful status
|
// MisconfStatusPassed represents successful status
|
||||||
StatusPassed MisconfStatus = "PASS"
|
MisconfStatusPassed MisconfStatus = "PASS"
|
||||||
|
|
||||||
// StatusFailure represents failure status
|
// MisconfStatusFailure represents failure status
|
||||||
StatusFailure MisconfStatus = "FAIL"
|
MisconfStatusFailure MisconfStatus = "FAIL"
|
||||||
|
|
||||||
// StatusException Passed represents the status of exception
|
// MisconfStatusException Passed represents the status of exception
|
||||||
StatusException MisconfStatus = "EXCEPTION"
|
MisconfStatusException MisconfStatus = "EXCEPTION"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GetID retrun misconfig ID
|
func (DetectedMisconfiguration) findingType() FindingType { return FindingTypeMisconfiguration }
|
||||||
func (mc *DetectedMisconfiguration) GetID() string {
|
|
||||||
return mc.AVDID
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -108,14 +108,19 @@ type Result struct {
|
|||||||
Vulnerabilities []DetectedVulnerability `json:"Vulnerabilities,omitempty"`
|
Vulnerabilities []DetectedVulnerability `json:"Vulnerabilities,omitempty"`
|
||||||
MisconfSummary *MisconfSummary `json:"MisconfSummary,omitempty"`
|
MisconfSummary *MisconfSummary `json:"MisconfSummary,omitempty"`
|
||||||
Misconfigurations []DetectedMisconfiguration `json:"Misconfigurations,omitempty"`
|
Misconfigurations []DetectedMisconfiguration `json:"Misconfigurations,omitempty"`
|
||||||
Secrets []ftypes.SecretFinding `json:"Secrets,omitempty"`
|
Secrets []DetectedSecret `json:"Secrets,omitempty"`
|
||||||
Licenses []DetectedLicense `json:"Licenses,omitempty"`
|
Licenses []DetectedLicense `json:"Licenses,omitempty"`
|
||||||
CustomResources []ftypes.CustomResource `json:"CustomResources,omitempty"`
|
CustomResources []ftypes.CustomResource `json:"CustomResources,omitempty"`
|
||||||
|
|
||||||
|
// ModifiedFindings holds a list of findings that have been modified from their original state.
|
||||||
|
// This can include vulnerabilities that have been marked as ignored, not affected, or have had
|
||||||
|
// their severity adjusted. It is currently available only in the table format.
|
||||||
|
ModifiedFindings []ModifiedFinding `json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Result) IsEmpty() bool {
|
func (r *Result) IsEmpty() bool {
|
||||||
return len(r.Packages) == 0 && len(r.Vulnerabilities) == 0 && len(r.Misconfigurations) == 0 &&
|
return len(r.Packages) == 0 && len(r.Vulnerabilities) == 0 && len(r.Misconfigurations) == 0 &&
|
||||||
len(r.Secrets) == 0 && len(r.Licenses) == 0 && len(r.CustomResources) == 0
|
len(r.Secrets) == 0 && len(r.Licenses) == 0 && len(r.CustomResources) == 0 && len(r.ModifiedFindings) == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
type MisconfSummary struct {
|
type MisconfSummary struct {
|
||||||
@@ -135,7 +140,7 @@ func (results Results) Failed() bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
for _, m := range r.Misconfigurations {
|
for _, m := range r.Misconfigurations {
|
||||||
if m.Status == StatusFailure {
|
if m.Status == MisconfStatusFailure {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
9
pkg/types/secret.go
Normal file
9
pkg/types/secret.go
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
package types
|
||||||
|
|
||||||
|
import (
|
||||||
|
ftypes "github.com/aquasecurity/trivy/pkg/fanal/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
type DetectedSecret ftypes.SecretFinding
|
||||||
|
|
||||||
|
func (DetectedSecret) findingType() FindingType { return FindingTypeSecret }
|
||||||
@@ -30,10 +30,7 @@ type DetectedVulnerability struct {
|
|||||||
types.Vulnerability
|
types.Vulnerability
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetID retrun Vulnerability ID
|
func (DetectedVulnerability) findingType() FindingType { return FindingTypeVulnerability }
|
||||||
func (vuln *DetectedVulnerability) GetID() string {
|
|
||||||
return vuln.VulnerabilityID
|
|
||||||
}
|
|
||||||
|
|
||||||
// BySeverity implements sort.Interface based on the Severity field.
|
// BySeverity implements sort.Interface based on the Severity field.
|
||||||
type BySeverity []DetectedVulnerability
|
type BySeverity []DetectedVulnerability
|
||||||
|
|||||||
@@ -23,8 +23,8 @@ func newCSAF(advisory csaf.Advisory) VEX {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *CSAF) Filter(vulns []types.DetectedVulnerability) []types.DetectedVulnerability {
|
func (v *CSAF) Filter(result *types.Result) {
|
||||||
return lo.Filter(vulns, func(vuln types.DetectedVulnerability, _ int) bool {
|
result.Vulnerabilities = lo.Filter(result.Vulnerabilities, func(vuln types.DetectedVulnerability, _ int) bool {
|
||||||
found, ok := lo.Find(v.advisory.Vulnerabilities, func(item *csaf.Vulnerability) bool {
|
found, ok := lo.Find(v.advisory.Vulnerabilities, func(item *csaf.Vulnerability) bool {
|
||||||
return string(*item.CVE) == vuln.VulnerabilityID
|
return string(*item.CVE) == vuln.VulnerabilityID
|
||||||
})
|
})
|
||||||
@@ -32,31 +32,29 @@ func (v *CSAF) Filter(vulns []types.DetectedVulnerability) []types.DetectedVulne
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
return v.affected(found, vuln.PkgIdentifier.PURL)
|
if status := v.match(found, vuln.PkgIdentifier.PURL); status != "" {
|
||||||
|
result.ModifiedFindings = append(result.ModifiedFindings,
|
||||||
|
types.NewModifiedFinding(vuln, status, statement(found), "CSAF VEX"))
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *CSAF) affected(vuln *csaf.Vulnerability, pkgURL *packageurl.PackageURL) bool {
|
func (v *CSAF) match(vuln *csaf.Vulnerability, pkgURL *packageurl.PackageURL) types.FindingStatus {
|
||||||
if pkgURL == nil || vuln.ProductStatus == nil {
|
if pkgURL == nil || vuln.ProductStatus == nil {
|
||||||
return true
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
var status Status
|
var status types.FindingStatus
|
||||||
switch {
|
switch {
|
||||||
case v.matchPURL(vuln.ProductStatus.KnownNotAffected, pkgURL):
|
case v.matchPURL(vuln.ProductStatus.KnownNotAffected, pkgURL):
|
||||||
status = StatusNotAffected
|
status = types.FindingStatusNotAffected
|
||||||
case v.matchPURL(vuln.ProductStatus.Fixed, pkgURL):
|
case v.matchPURL(vuln.ProductStatus.Fixed, pkgURL):
|
||||||
status = StatusFixed
|
status = types.FindingStatusFixed
|
||||||
}
|
}
|
||||||
|
|
||||||
if status != "" {
|
return status
|
||||||
v.logger.Infow("Filtered out the detected vulnerability",
|
|
||||||
zap.String("vulnerability-id", string(*vuln.CVE)),
|
|
||||||
zap.String("status", string(status)))
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// matchPURL returns true if the given PackageURL is found in the ProductTree.
|
// matchPURL returns true if the given PackageURL is found in the ProductTree.
|
||||||
@@ -83,3 +81,13 @@ func (v *CSAF) matchPURL(products *csaf.Products, pkgURL *packageurl.PackageURL)
|
|||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func statement(vuln *csaf.Vulnerability) string {
|
||||||
|
threat, ok := lo.Find(vuln.Threats, func(threat *csaf.Threat) bool {
|
||||||
|
return lo.FromPtr(threat.Category) == csaf.CSAFThreatCategoryImpact
|
||||||
|
})
|
||||||
|
if !ok {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return lo.FromPtr(threat.Details)
|
||||||
|
}
|
||||||
|
|||||||
@@ -19,8 +19,8 @@ type CycloneDX struct {
|
|||||||
type Statement struct {
|
type Statement struct {
|
||||||
VulnerabilityID string
|
VulnerabilityID string
|
||||||
Affects []string
|
Affects []string
|
||||||
Status Status
|
Status types.FindingStatus
|
||||||
Justification string // TODO: define a type
|
Justification string
|
||||||
}
|
}
|
||||||
|
|
||||||
func newCycloneDX(cdxSBOM *ftypes.CycloneDX, vex *cdx.BOM) *CycloneDX {
|
func newCycloneDX(cdxSBOM *ftypes.CycloneDX, vex *cdx.BOM) *CycloneDX {
|
||||||
@@ -45,15 +45,20 @@ func newCycloneDX(cdxSBOM *ftypes.CycloneDX, vex *cdx.BOM) *CycloneDX {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *CycloneDX) Filter(vulns []types.DetectedVulnerability) []types.DetectedVulnerability {
|
func (v *CycloneDX) Filter(result *types.Result) {
|
||||||
return lo.Filter(vulns, func(vuln types.DetectedVulnerability, _ int) bool {
|
result.Vulnerabilities = lo.Filter(result.Vulnerabilities, func(vuln types.DetectedVulnerability, _ int) bool {
|
||||||
stmt, ok := lo.Find(v.statements, func(item Statement) bool {
|
stmt, ok := lo.Find(v.statements, func(item Statement) bool {
|
||||||
return item.VulnerabilityID == vuln.VulnerabilityID
|
return item.VulnerabilityID == vuln.VulnerabilityID
|
||||||
})
|
})
|
||||||
if !ok {
|
if !ok {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return v.affected(vuln, stmt)
|
if !v.affected(vuln, stmt) {
|
||||||
|
result.ModifiedFindings = append(result.ModifiedFindings,
|
||||||
|
types.NewModifiedFinding(vuln, stmt.Status, stmt.Justification, "CycloneDX VEX"))
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,29 +71,28 @@ func (v *CycloneDX) affected(vuln types.DetectedVulnerability, stmt Statement) b
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if v.sbom.SerialNumber != link.SerialNumber() || v.sbom.Version != link.Version() {
|
if v.sbom.SerialNumber != link.SerialNumber() || v.sbom.Version != link.Version() {
|
||||||
v.logger.Warnw("URN doesn't match with SBOM", zap.String("serial number", link.SerialNumber()),
|
v.logger.Warnw("URN doesn't match with SBOM",
|
||||||
|
zap.String("serial number", link.SerialNumber()),
|
||||||
zap.Int("version", link.Version()))
|
zap.Int("version", link.Version()))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if vuln.PkgIdentifier.Match(link.Reference()) && (stmt.Status == StatusNotAffected || stmt.Status == StatusFixed) {
|
if vuln.PkgIdentifier.Match(link.Reference()) && (stmt.Status == types.FindingStatusNotAffected || stmt.Status == types.FindingStatusFixed) {
|
||||||
v.logger.Infow("Filtered out the detected vulnerability", zap.String("vulnerability-id", vuln.VulnerabilityID),
|
|
||||||
zap.String("status", string(stmt.Status)), zap.String("justification", stmt.Justification))
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func cdxStatus(s cdx.ImpactAnalysisState) Status {
|
func cdxStatus(s cdx.ImpactAnalysisState) types.FindingStatus {
|
||||||
switch s {
|
switch s {
|
||||||
case cdx.IASResolved, cdx.IASResolvedWithPedigree:
|
case cdx.IASResolved, cdx.IASResolvedWithPedigree:
|
||||||
return StatusFixed
|
return types.FindingStatusFixed
|
||||||
case cdx.IASExploitable:
|
case cdx.IASExploitable:
|
||||||
return StatusAffected
|
return types.FindingStatusAffected
|
||||||
case cdx.IASInTriage:
|
case cdx.IASInTriage:
|
||||||
return StatusUnderInvestigation
|
return types.FindingStatusUnderInvestigation
|
||||||
case cdx.IASFalsePositive, cdx.IASNotAffected:
|
case cdx.IASFalsePositive, cdx.IASNotAffected:
|
||||||
return StatusNotAffected
|
return types.FindingStatusNotAffected
|
||||||
}
|
}
|
||||||
return StatusUnknown
|
return types.FindingStatusUnknown
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,31 +3,27 @@ package vex
|
|||||||
import (
|
import (
|
||||||
openvex "github.com/openvex/go-vex/pkg/vex"
|
openvex "github.com/openvex/go-vex/pkg/vex"
|
||||||
"github.com/samber/lo"
|
"github.com/samber/lo"
|
||||||
"go.uber.org/zap"
|
|
||||||
|
|
||||||
"github.com/aquasecurity/trivy/pkg/log"
|
|
||||||
"github.com/aquasecurity/trivy/pkg/types"
|
"github.com/aquasecurity/trivy/pkg/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
type OpenVEX struct {
|
type OpenVEX struct {
|
||||||
vex openvex.VEX
|
vex openvex.VEX
|
||||||
logger *zap.SugaredLogger
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func newOpenVEX(vex openvex.VEX) VEX {
|
func newOpenVEX(vex openvex.VEX) VEX {
|
||||||
return &OpenVEX{
|
return &OpenVEX{
|
||||||
vex: vex,
|
vex: vex,
|
||||||
logger: log.Logger.With(zap.String("VEX format", "OpenVEX")),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *OpenVEX) Filter(vulns []types.DetectedVulnerability) []types.DetectedVulnerability {
|
func (v *OpenVEX) Filter(result *types.Result) {
|
||||||
return lo.Filter(vulns, func(vuln types.DetectedVulnerability, _ int) bool {
|
result.Vulnerabilities = lo.Filter(result.Vulnerabilities, func(vuln types.DetectedVulnerability, _ int) bool {
|
||||||
var stmts []openvex.Statement
|
if vuln.PkgIdentifier.PURL == nil {
|
||||||
if vuln.PkgIdentifier.PURL != nil {
|
return true
|
||||||
matchedStmts := v.vex.Matches(vuln.VulnerabilityID, vuln.PkgIdentifier.PURL.String(), nil)
|
|
||||||
stmts = append(stmts, matchedStmts...)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
stmts := v.vex.Matches(vuln.VulnerabilityID, vuln.PkgIdentifier.PURL.String(), nil)
|
||||||
if len(stmts) == 0 {
|
if len(stmts) == 0 {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@@ -37,10 +33,23 @@ func (v *OpenVEX) Filter(vulns []types.DetectedVulnerability) []types.DetectedVu
|
|||||||
// cf. https://github.com/openvex/spec/blob/fa5ba0c0afedb008dc5ebad418548cacf16a3ca7/OPENVEX-SPEC.md#the-vex-statement
|
// cf. https://github.com/openvex/spec/blob/fa5ba0c0afedb008dc5ebad418548cacf16a3ca7/OPENVEX-SPEC.md#the-vex-statement
|
||||||
stmt := stmts[len(stmts)-1]
|
stmt := stmts[len(stmts)-1]
|
||||||
if stmt.Status == openvex.StatusNotAffected || stmt.Status == openvex.StatusFixed {
|
if stmt.Status == openvex.StatusNotAffected || stmt.Status == openvex.StatusFixed {
|
||||||
v.logger.Infow("Filtered out the detected vulnerability", zap.String("vulnerability-id", vuln.VulnerabilityID),
|
result.ModifiedFindings = append(result.ModifiedFindings,
|
||||||
zap.String("status", string(stmt.Status)), zap.String("justification", string(stmt.Justification)))
|
types.NewModifiedFinding(vuln, findingStatus(stmt.Status), string(stmt.Justification), "OpenVEX"))
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func findingStatus(status openvex.Status) types.FindingStatus {
|
||||||
|
switch status {
|
||||||
|
case openvex.StatusNotAffected:
|
||||||
|
return types.FindingStatusNotAffected
|
||||||
|
case openvex.StatusFixed:
|
||||||
|
return types.FindingStatusFixed
|
||||||
|
case openvex.StatusUnderInvestigation:
|
||||||
|
return types.FindingStatusUnderInvestigation
|
||||||
|
default:
|
||||||
|
return types.FindingStatusUnknown
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,11 +0,0 @@
|
|||||||
package vex
|
|
||||||
|
|
||||||
type Status string
|
|
||||||
|
|
||||||
const (
|
|
||||||
StatusNotAffected Status = "not_affected"
|
|
||||||
StatusAffected Status = "affected"
|
|
||||||
StatusFixed Status = "fixed"
|
|
||||||
StatusUnderInvestigation Status = "under_investigation"
|
|
||||||
StatusUnknown Status = "unknown"
|
|
||||||
)
|
|
||||||
@@ -20,7 +20,7 @@ import (
|
|||||||
// Note: This is in the experimental stage and does not yet support many specifications.
|
// Note: This is in the experimental stage and does not yet support many specifications.
|
||||||
// The implementation may change significantly.
|
// The implementation may change significantly.
|
||||||
type VEX interface {
|
type VEX interface {
|
||||||
Filter([]types.DetectedVulnerability) []types.DetectedVulnerability
|
Filter(*types.Result)
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(filePath string, report types.Report) (VEX, error) {
|
func New(filePath string, report types.Report) (VEX, error) {
|
||||||
|
|||||||
@@ -316,7 +316,12 @@ func TestVEX_Filter(t *testing.T) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.Equal(t, tt.want, v.Filter(tt.args.vulns))
|
|
||||||
|
got := &types.Result{
|
||||||
|
Vulnerabilities: tt.args.vulns,
|
||||||
|
}
|
||||||
|
v.Filter(got)
|
||||||
|
assert.Equal(t, tt.want, got.Vulnerabilities)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user