Compare commits

...

17 Commits

Author SHA1 Message Date
Michal Slusarczyk
d9fa353a06 Fixing Error retrieving template from path when --format is not template but template is provided (#556) 2020-07-13 14:01:08 +03:00
Michal Slusarczyk
9a1d7460f6 Adding contrib/junit.tpl to docker image (#554) 2020-07-09 09:23:31 +03:00
Simarpreet Singh
d18d17b861 db: Update trivy-db to include CVSS score info (#530)
* mod: Update trivy-db to include CVSS score info

Signed-off-by: Simarpreet Singh <simar@linux.com>

* mod: Update go.mod

Signed-off-by: Simarpreet Singh <simar@linux.com>

* mod: Update trivy-db to latest

Signed-off-by: Simarpreet Singh <simar@linux.com>
2020-07-07 08:16:42 -07:00
Liz Rice
4b57c0d4e6 docs: fix markdown (#553)
Correct markdown for MicroScanner link
2020-07-07 16:27:51 +03:00
rahul2393
ccd9b2d2c5 Added function to escape string in failure message title and descriptions (#551)
* Added function to escape string in failure message title and descriptions

* updated template to use xml.EscapeText

* Renamed template function
2020-07-06 12:43:11 +03:00
rahul2393
ec770cd819 Added JUNIT support (#541)
* added template for junit

* updated readme and junit format

* Added severity in testcase name instead of separate failure block
2020-06-25 17:23:04 +03:00
Teppei Fukuda
b7ec633fb2 chore(docs): mention air-gapped environment (#544)
* chore(docs): mention air-gapped environment

* Update docs/air-gap.md

Co-authored-by: Liz Rice <liz@lizrice.com>
2020-06-24 17:15:17 +03:00
Teppei Fukuda
7aabff1236 chore(README): add programming languages (#543) 2020-06-23 20:52:43 +03:00
Teppei Fukuda
9dc1bdffb1 fix(log): write error messages to stderr (#538) 2020-06-23 15:06:42 +03:00
Simarpreet Singh
2ac672a663 Use StoreMetadata from trivy-db (#509)
* db_test: Remove cruft

Signed-off-by: Simarpreet Singh <simar@linux.com>

* db: Add StoreMetadata from trivy-db.

Signed-off-by: Simarpreet Singh <simar@linux.com>

* mod: Update trivy-db dependency

Signed-off-by: Simarpreet Singh <simar@linux.com>

* mod: Bump trivy-db version

Signed-off-by: Simarpreet Singh <simar@linux.com>

* db: Eliminate metadata.Store

Signed-off-by: Simarpreet Singh <simar@linux.com>

* db: Add a TODO to move things into trivy-db repo

Signed-off-by: Simarpreet Singh <simar@linux.com>
2020-06-22 14:29:38 -07:00
Liz Rice
11ae6b29d5 docs: add more CI options to README (#535)
Add GitHub Actions and AWS CodePipeline to CI section of Readme
Correct a broken link to "Data sources"
2020-06-21 11:26:22 +03:00
Teppei Fukuda
f201f59e27 chore(Dockerfile): bump up alpine to 3.12 (#528) 2020-06-15 11:29:38 +03:00
Teppei Fukuda
25d45e1ac5 fix(alpine): replace go-deb-version with go-apk-version (#520)
* fix(alpine): add a failing test with go-deb-version

* fix(alpine): replace go-deb-version with go-apk-version

* chore(mod): update dependencies

* chore(mod): update go-apk-version
2020-06-11 12:55:34 +03:00
Oran Moshai
298ba99b8f fix: MissingBlobs is implemented different in FS and S3 the method log… (#522)
* fix: MissingBlobs is implemented diffrent in FS and S3 the method logic moved to cache.MissingBlobs

* fix(unittest): implement MockArtifactCache instead MockLocalArtifactCache

* fix(gofmt)

* fix naming convention

Co-authored-by: oranmoshai <oran.moshai@aquasec.com>
2020-06-10 10:38:37 +03:00
Teppei Fukuda
65cbe3cac3 fix(alpine): support 3.12 (#517) 2020-06-08 17:17:38 +03:00
Teppei Fukuda
f94e8dcf04 chore(README): prepare for v0.9.0 (#507)
* chore(README): prepare for v0.9.0

* chore(README): replace 'artifacts' with 'containers and other artifacts'

* chore: more detail for filesystem scan

Co-authored-by: Liz Rice <liz@lizrice.com>

* chore: more detail for embedding Trivy in the Dockerfile

Co-authored-by: Liz Rice <liz@lizrice.com>

* Update README.md

Co-authored-by: Liz Rice <liz@lizrice.com>

* Update README.md

Co-authored-by: Liz Rice <liz@lizrice.com>

* chore(README): add a new line

* chore(README): revert TOC and add blog links

* chore(README): add Microscanner link

Co-authored-by: Liz Rice <liz@lizrice.com>
2020-06-08 16:20:44 +03:00
Teppei Fukuda
9629303a0f fix(config): transpose arguments (#516) 2020-06-08 15:47:20 +03:00
21 changed files with 810 additions and 291 deletions

View File

@@ -1,5 +1,6 @@
FROM alpine:3.11
FROM alpine:3.12
RUN apk --no-cache add ca-certificates git rpm
COPY trivy /usr/local/bin/trivy
COPY contrib/gitlab.tpl contrib/gitlab.tpl
COPY contrib/junit.tpl contrib/junit.tpl
ENTRYPOINT ["trivy"]

404
README.md
View File

@@ -7,7 +7,7 @@
[![License: Apache-2.0](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://github.com/aquasecurity/trivy/blob/master/LICENSE)
[![Docker image](https://images.microbadger.com/badges/version/aquasec/trivy.svg)](https://microbadger.com/images/aquasec/trivy "Get your own version badge on microbadger.com")
A Simple and Comprehensive Vulnerability Scanner for Containers, Suitable for CI.
A Simple and Comprehensive Vulnerability Scanner for Containers and other Artifacts, Suitable for CI.
<img src="imgs/usage.gif" width="700">
<img src="imgs/usage1.png" width="600">
@@ -18,62 +18,77 @@ A Simple and Comprehensive Vulnerability Scanner for Containers, Suitable for CI
- [Abstract](#abstract)
- [Features](#features)
- [Installation](#installation)
- [RHEL/CentOS](#rhelcentos)
- [Debian/Ubuntu](#debianubuntu)
- [Arch Linux](#arch-linux)
- [Mac OS X / Homebrew](#homebrew)
- [Binary](#binary)
- [From source](#from-source)
* [RHEL/CentOS](#rhelcentos)
* [Debian/Ubuntu](#debianubuntu)
* [Arch Linux](#arch-linux)
* [Homebrew](#homebrew)
* [Install Script](#install-script)
* [Binary](#binary)
* [From source](#from-source)
- [Quick Start](#quick-start)
- [Basic](#basic)
- [Docker](#docker)
* [Image](#image)
+ [Basic](#basic)
+ [Docker](#docker)
* [Filesystem](#filesystem)
* [Embed in Dockerfile](#embed-in-dockerfile)
* [Git Repository](#git-repository)
- [Examples](#examples)
- [Standalone](#standalone)
- [Scan an image](#scan-an-image)
- [Scan an image file](#scan-an-image-file)
- [Scan an OCI image](#scan-an-oci-image)
- [Save the results as JSON](#save-the-results-as-json)
- [Save the results using a template](#save-the-results-using-a-template)
- [Filter the vulnerabilities by severities](#filter-the-vulnerabilities-by-severities)
- [Filter the vulnerabilities by type](#filter-the-vulnerabilities-by-type)
- [Skip an update of vulnerability DB](#skip-update-of-vulnerability-db)
- [Ignore unfixed vulnerabilities](#ignore-unfixed-vulnerabilities)
- [Specify exit code](#specify-exit-code)
- [Ignore the specified vulnerabilities](#ignore-the-specified-vulnerabilities)
- [Clear image caches](#clear-image-caches)
- [Reset](#reset)
- [Lightweight DB](#use-lightweight-db)
- [Client/Server](#client--server)
- [Server](#server)
- [Client](#client)
- [Authentication](#authentication)
* [Standalone](#standalone)
+ [Scan an image](#scan-an-image)
+ [Scan an image file](#scan-an-image-file)
+ [Scan an OCI image](#scan-an-oci-image)
+ [Scan a container from inside the container](#scan-a-container-from-inside-the-container)
+ [Scan a project including a lock file](#scan-a-project-including-a-lock-file)
+ [Embed in Dockerfile](#embed-in-dockerfile)
+ [Save the results as JSON](#save-the-results-as-json)
+ [Save the results using a template](#save-the-results-using-a-template)
+ [Filter the vulnerabilities by severities](#filter-the-vulnerabilities-by-severities)
+ [Filter the vulnerabilities by type](#filter-the-vulnerabilities-by-type)
+ [Skip update of vulnerability DB](#skip-update-of-vulnerability-db)
+ [Only download vulnerability database](#only-download-vulnerability-database)
+ [Ignore unfixed vulnerabilities](#ignore-unfixed-vulnerabilities)
+ [Specify exit code](#specify-exit-code)
+ [Ignore the specified vulnerabilities](#ignore-the-specified-vulnerabilities)
+ [Specify cache directory](#specify-cache-directory)
+ [Clear caches](#clear-caches)
+ [Reset](#reset)
+ [Use lightweight DB](#use-lightweight-db)
* [Client / Server](#client--server)
+ [Server](#server)
+ [Client](#client)
+ [Authentication](#authentication)
+ [Deprecated options](#deprecated-options)
- [Continuous Integration (CI)](#continuous-integration-ci)
- [Travis CI](#travis-ci)
- [CircleCI](#circleci)
- [GitLab CI](#gitlab-ci)
- [Authorization for Private Docker Registry](#authorization-for-private-docker-registry)
* [GitHub Actions](#github-actions)
* [Travis CI](#travis-ci)
* [CircleCI](#circleci)
* [GitLab CI](#gitlab-ci)
* [AWS CodePipeline](#aws-codepipeline)
* [Authorization for Private Docker Registry](#authorization-for-private-docker-registry)
- [Vulnerability Detection](#vulnerability-detection)
- [OS Packages](#os-packages)
- [Application Dependencies](#application-dependencies)
- [Usage](#usage)
* [OS Packages](#os-packages)
* [Application Dependencies](#application-dependencies)
* [Image Tar format](#image-tar-format)
* [Data sources](#data-sources)
- [Air-gapped environment](#air-gapped-environment)
- [Comparison with other scanners](#comparison-with-other-scanners)
- [Overview](#overview)
- [vs Clair](#vs-clair)
- [vs Anchore Engine](#vs-anchore-engine)
- [vs Quay, Docker Hub, GCR](#vs-quay-docker-hub-gcr)
- [Migration](#migration)
- [Usage](#usage)
* [Image](#image-1)
* [Client](#client-1)
* [Server](#server-1)
- [Q&A](#qa)
- [Homebrew](#homebrew)
- [Others](#others)
* [Homebrew](#homebrew-2)
* [Others](#others)
# Abstract
`Trivy` (`tri` pronounced like **tri**gger, `vy` pronounced like en**vy**) is a simple and comprehensive vulnerability scanner for containers.
`Trivy` (`tri` pronounced like **tri**gger, `vy` pronounced like en**vy**) is a simple and comprehensive vulnerability scanner for containers and other artifacts.
A software vulnerability is a glitch, flaw, or weakness present in the software or in an Operating System.
`Trivy` detects vulnerabilities of OS packages (Alpine, RHEL, CentOS, etc.) and application dependencies (Bundler, Composer, npm, yarn etc.).
`Trivy` is easy to use. Just install the binary and you're ready to scan. All you need to do for scanning is to specify an image name of the container.
`Trivy` detects vulnerabilities of OS packages (Alpine, RHEL, CentOS, etc.) and application dependencies (Bundler, Composer, npm, yarn, etc.).
`Trivy` is easy to use. Just install the binary and you're ready to scan. All you need to do for scanning is to specify a target such as an image name of the container.
It is considered to be used in CI. Before pushing to a container registry, you can scan your local container image easily.
It is considered to be used in CI. Before pushing to a container registry or deploying your application, you can scan your local container image and other artifacts easily.
See [here](#continuous-integration-ci) for details.
# Features
@@ -82,7 +97,7 @@ See [here](#continuous-integration-ci) for details.
- OS packages (Alpine, **Red Hat Universal Base Image**, Red Hat Enterprise Linux, CentOS, Oracle Linux, Debian, Ubuntu, Amazon Linux, openSUSE Leap, SUSE Enterprise Linux, Photon OS and Distroless)
- **Application dependencies** (Bundler, Composer, Pipenv, Poetry, npm, yarn and Cargo)
- Simple
- Specify only an image name
- Specify only an image name or artifact name
- See [Quick Start](#quick-start) and [Examples](#examples)
- Fast
- The first scan will finish within 10 seconds (depending on your network). Consequent scans will finish in single seconds.
@@ -94,13 +109,16 @@ See [here](#continuous-integration-ci) for details.
- **Especially Alpine Linux and RHEL/CentOS**
- Other OSes are also high
- DevSecOps
- **Suitable for CI** such as Travis CI, CircleCI, Jenkins, etc.
- **Suitable for CI** such as Travis CI, CircleCI, Jenkins, GitLab CI, etc.
- See [CI Example](#continuous-integration-ci)
- Support multiple formats
- A local image in Docker Engine which is running as a daemon
- A remote image in Docker Registry such as Docker Hub, ECR, GCR and ACR
- A tar archive stored in the `docker save` formatted file
- An image directory compliant with [OCI Image Format](https://github.com/opencontainers/image-spec)
- container image
- A local image in Docker Engine which is running as a daemon
- A remote image in Docker Registry such as Docker Hub, ECR, GCR and ACR
- A tar archive stored in the `docker save` formatted file
- An image directory compliant with [OCI Image Format](https://github.com/opencontainers/image-spec)
- local filesystem
- remote git repository
Please see [LICENSE](https://github.com/aquasecurity/trivy/blob/master/LICENSE) for Trivy licensing information. Note that Trivy uses vulnerability information from a variety of sources, some of which are licensed for non-commercial use only.
@@ -169,6 +187,13 @@ You can use homebrew on macOS.
$ brew install aquasecurity/trivy/trivy
```
## Install Script
This script downloads Trivy binary based on your OS and architecture.
```
$ curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/master/contrib/install.sh | sh -s -- -b /usr/local/bin
```
## Binary
Get the latest version from [this page](https://github.com/aquasecurity/trivy/releases/latest), and download the archive file for your operating system/architecture. Unpack the archive, and put the binary somewhere in your `$PATH` (on UNIX-y systems, /usr/local/bin or the like). Make sure it has execution bits turned on.
@@ -190,9 +215,11 @@ You also need to install `rpm` command for scanning images based on RHEL/CentOS.
# Quick Start
## Image
Simply specify an image name (and a tag). **The `latest` tag should be avoided as problems occur with the image cache.** See [Clear image caches](#clear-image-caches).
## Basic
### Basic
```
$ trivy image [YOUR_IMAGE_NAME]
@@ -225,7 +252,7 @@ Total: 1 (UNKNOWN: 0, LOW: 0, MEDIUM: 1, HIGH: 0, CRITICAL: 0)
</details>
## Docker
### Docker
Replace [YOUR_CACHE_DIR] with the cache directory on your machine.
@@ -269,6 +296,47 @@ Total: 1 (UNKNOWN: 0, LOW: 0, MEDIUM: 1, HIGH: 0, CRITICAL: 0)
</details>
## Filesystem
Scan a filesystem (such as a host machine, a virtual machine image, or an unpacked container image filesystem).
Trivy will look for vulnerabilities based on lock files such as Gemfile.lock and package-lock.json.
```
$ trivy fs /path/to/project
```
Scan your container from inside the container.
```
$ docker run --rm -it alpine:3.11
/ # curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/master/contrib/install.sh | sh -s -- -b /usr/local/bin
/ # trivy fs /
```
## Embed in Dockerfile
Scan your image as part of the build process by embedding Trivy in the Dockerfile. This approach can be used to update Dockerfiles currently using Aquas [Microscanner](https://github.com/aquasecurity/microscanner).
```
$ cat Dockerfile
FROM alpine:3.7
RUN apk add curl \
&& curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/master/contrib/install.sh | sh -s -- -b /usr/local/bin \
&& trivy filesystem --exit-code 1 --no-progress /
$ docker build -t vulnerable-image .
```
## Git Repository
Scan your remote git repository
```
$ trivy repo https://github.com/knqyf263/trivy-ci-test
```
Only public repositories are supported.
# Examples
## Standalone
@@ -285,17 +353,11 @@ $ trivy image knqyf263/vuln-image:1.2.3
<summary>Result</summary>
```
2019-05-16T12:58:55.967+0900 INFO Updating vulnerability database...
2019-05-16T12:59:03.150+0900 INFO Detecting Alpine vulnerabilities...
2019-05-16T12:59:03.156+0900 INFO Updating bundler Security DB...
2019-05-16T12:59:04.941+0900 INFO Detecting bundler vulnerabilities...
2019-05-16T12:59:04.942+0900 INFO Updating cargo Security DB...
2019-05-16T12:59:05.967+0900 INFO Detecting cargo vulnerabilities...
2019-05-16T12:59:05.967+0900 INFO Updating composer Security DB...
2019-05-16T12:59:07.834+0900 INFO Detecting composer vulnerabilities...
2019-05-16T12:59:07.834+0900 INFO Updating npm Security DB...
2019-05-16T12:59:10.285+0900 INFO Detecting npm vulnerabilities...
2019-05-16T12:59:10.285+0900 INFO Updating pipenv Security DB...
2019-05-16T12:59:11.487+0900 INFO Detecting pipenv vulnerabilities...
knqyf263/vuln-image:1.2.3 (alpine 3.7.1)
@@ -555,6 +617,132 @@ $ skopeo copy docker-daemon:alpine:3.11 oci:/path/to/alpine
$ trivy image --input /path/to/alpine
```
### Scan a container from inside the container
```
$ docker run --rm -it alpine:3.10.2
/ # curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/master/contrib/install.sh | sh -s -- -b /usr/local/bin
/ # trivy fs /
```
<details>
<summary>Result</summary>
```
adb3b9abab80 (alpine 3.10.2)
============================
Total: 5 (UNKNOWN: 0, LOW: 1, MEDIUM: 4, HIGH: 0, CRITICAL: 0)
+---------+------------------+----------+-------------------+---------------+--------------------------------+
| LIBRARY | VULNERABILITY ID | SEVERITY | INSTALLED VERSION | FIXED VERSION | TITLE |
+---------+------------------+----------+-------------------+---------------+--------------------------------+
| openssl | CVE-2019-1549 | MEDIUM | 1.1.1c-r0 | 1.1.1d-r0 | openssl: information |
| | | | | | disclosure in fork() |
+ +------------------+ + +---------------+--------------------------------+
| | CVE-2019-1551 | | | 1.1.1d-r2 | openssl: Integer overflow in |
| | | | | | RSAZ modular exponentiation on |
| | | | | | x86_64 |
+ +------------------+ + +---------------+--------------------------------+
| | CVE-2019-1563 | | | 1.1.1d-r0 | openssl: information |
| | | | | | disclosure in PKCS7_dataDecode |
| | | | | | and CMS_decrypt_set1_pkey |
+ +------------------+ + +---------------+--------------------------------+
| | CVE-2020-1967 | | | 1.1.1g-r0 | openssl: Segmentation fault in |
| | | | | | SSL_check_chain causes denial |
| | | | | | of service |
+ +------------------+----------+ +---------------+--------------------------------+
| | CVE-2019-1547 | LOW | | 1.1.1d-r0 | openssl: side-channel weak |
| | | | | | encryption vulnerability |
+---------+------------------+----------+-------------------+---------------+--------------------------------+
```
</details>
### Scan a project including a lock file
```
$ trivy fs ~/src/github.com/aquasecurity/trivy-ci-test
```
<details>
<summary>Result</summary>
```
2020-06-01T17:06:58.652+0300 WARN OS is not detected and vulnerabilities in OS packages are not detected.
2020-06-01T17:06:58.652+0300 INFO Detecting pipenv vulnerabilities...
2020-06-01T17:06:58.691+0300 INFO Detecting cargo vulnerabilities...
Pipfile.lock
============
Total: 10 (UNKNOWN: 2, LOW: 0, MEDIUM: 6, HIGH: 2, CRITICAL: 0)
+---------------------+------------------+----------+-------------------+------------------------+------------------------------------+
| LIBRARY | VULNERABILITY ID | SEVERITY | INSTALLED VERSION | FIXED VERSION | TITLE |
+---------------------+------------------+----------+-------------------+------------------------+------------------------------------+
| django | CVE-2020-7471 | HIGH | 2.0.9 | 3.0.3, 2.2.10, 1.11.28 | django: potential |
| | | | | | SQL injection via |
| | | | | | StringAgg(delimiter) |
+ +------------------+----------+ +------------------------+------------------------------------+
| | CVE-2019-19844 | MEDIUM | | 3.0.1, 2.2.9, 1.11.27 | Django: crafted email address |
| | | | | | allows account takeover |
+ +------------------+ + +------------------------+------------------------------------+
| | CVE-2019-3498 | | | 2.1.5, 2.0.10, 1.11.18 | python-django: Content |
| | | | | | spoofing via URL path in |
| | | | | | default 404 page |
+ +------------------+ + +------------------------+------------------------------------+
| | CVE-2019-6975 | | | 2.1.6, 2.0.11, 1.11.19 | python-django: |
| | | | | | memory exhaustion in |
| | | | | | django.utils.numberformat.format() |
+---------------------+------------------+----------+-------------------+------------------------+------------------------------------+
...
```
</details>
### Embed in Dockerfile
```
$ cat Dockerfile
FROM alpine:3.7
RUN apk add curl \
&& curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/master/contrib/install.sh | sh -s -- -b /usr/local/bin \
&& trivy filesystem --exit-code 1 --no-progress /
$ docker build -t vulnerable-image .
```
<details>
<summary>Result</summary>
```
Sending build context to Docker daemon 31.14MB
Step 1/2 : FROM alpine:3.7
---> 6d1ef012b567
Step 2/2 : RUN curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/master/contrib/install.sh | sh -s -- -b /usr/local/bin && trivy filesystem --exit-code 1 --no-progress /
---> Running in 27b004205da0
2020-06-01T14:10:41.261Z INFO Need to update DB
2020-06-01T14:10:41.262Z INFO Downloading DB...
2020-06-01T14:10:56.188Z INFO Detecting Alpine vulnerabilities...
2020-06-01T14:10:56.188Z WARN This OS version is no longer supported by the distribution: alpine 3.7.3
2020-06-01T14:10:56.188Z WARN The vulnerability detection may be insufficient because security updates are not provided
27b004205da0 (alpine 3.7.3)
===========================
Total: 1 (UNKNOWN: 0, LOW: 0, MEDIUM: 0, HIGH: 1, CRITICAL: 0)
+---------+------------------+----------+-------------------+---------------+--------------------------------+
| LIBRARY | VULNERABILITY ID | SEVERITY | INSTALLED VERSION | FIXED VERSION | TITLE |
+---------+------------------+----------+-------------------+---------------+--------------------------------+
| musl | CVE-2019-14697 | HIGH | 1.1.18-r3 | 1.1.18-r4 | musl libc through 1.1.23 |
| | | | | | has an x87 floating-point |
| | | | | | stack adjustment imbalance, |
| | | | | | related... |
+---------+------------------+----------+-------------------+---------------+--------------------------------+
The command '/bin/sh -c trivy filesystem --exit-code 1 --no-progress /' returned a non-zero code: 1
```
</details>
### Save the results as JSON
@@ -700,6 +888,11 @@ You can load templates from a file prefixing the template path with an @.
$ trivy image --format template --template "@/path/to/template" golang:1.12-alpine
```
In the following example using the template `junit.tpl` XML can be generated.
```
$ trivy image --format template --template "@contrib/junit.tpl" -o junit-report.xml golang:1.12-alpine
```
### Filter the vulnerabilities by severities
```
@@ -1058,9 +1251,9 @@ Total: 0 (UNKNOWN: 0, LOW: 0, MEDIUM: 0, HIGH: 0, CRITICAL: 0)
$ trivy --cache-dir /tmp/trivy/ image python:3.4-alpine3.9
```
### Clear image caches
### Clear caches
The `--clear-cache` option removes image caches. This option is useful if the image which has the same tag is updated (such as when using `latest` tag).
The `--clear-cache` option removes caches. This option is useful if the image which has the same tag is updated (such as when using `latest` tag).
**The scan is not performed.**
@@ -1194,9 +1387,15 @@ $ trivy client --remote http://localhost:8080 --token dummy alpine:3.10
# Continuous Integration (CI)
Scan your image built in Travis CI/CircleCI. The test will fail if a vulnerability is found. When you don't want to fail the test, specify `--exit-code 0` .
Scan your image automatically as part of your CI workflow, failing the workflow if a vulnerability is found. When you don't want to fail the test, specify `--exit-code 0`.
Since in automated scenarios such as CI/CD you only interested in the end result, and not the full report, use the `--light` flag to optimize for this scenario and get fast results.
Since in automated scenarios such as CI/CD you are only interested in the end result, and not the full report, use the `--light` flag to optimize for this scenario and get fast results.
## GitHub Actions
- Here is the [Trivy Github Action](https://github.com/aquasecurity/trivy-action) (currently Experimental)
- The Microsoft Azure team have written a [container-scan action](https://github.com/Azure/container-scan) that uses Trivy and Dockle
- For full control over the options specified to Trivy, this [blog post](https://blog.aquasec.com/devsecops-with-trivy-github-actions) describes adding Trivy into your own GitHub action workflows
## Travis CI
@@ -1310,6 +1509,10 @@ trivy:
container_scanning: gl-container-scanning-report.json
```
## AWS CodePipeline
See [this blog post](https://aws.amazon.com/blogs/containers/scanning-images-with-trivy-in-an-aws-codepipeline/) for an example of using Trivy within AWS CodePipeline.
## Authorization for Private Docker Registry
Trivy can download images from a private registry, without installing `Docker` or any other 3rd party tools.
@@ -1364,7 +1567,7 @@ The unfixed/unfixable vulnerabilities mean that the patch has not yet been provi
| OS | Supported Versions | Target Packages | Detection of unfixed vulnerabilities |
| ---------------------------- | ---------------------------------------- | ----------------------------- | :----------------------------------: |
| Alpine Linux | 2.2 - 2.7, 3.0 - 3.11 | Installed by apk | NO |
| Alpine Linux | 2.2 - 2.7, 3.0 - 3.12 | Installed by apk | NO |
| Red Hat Universal Base Image | 7, 8 | Installed by yum/rpm | YES |
| Red Hat Enterprise Linux | 6, 7, 8 | Installed by yum/rpm | YES |
| CentOS | 6, 7 | Installed by yum/rpm | YES |
@@ -1385,13 +1588,18 @@ Distroless: https://github.com/GoogleContainerTools/distroless
`Trivy` automatically detects the following files in the container and scans vulnerabilities in the application dependencies.
- Gemfile.lock
- Pipfile.lock
- poetry.lock
- composer.lock
- package-lock.json
- yarn.lock
- Cargo.lock
- Ruby
- Gemfile.lock
- Python
- Pipfile.lock
- poetry.lock
- PHP
- composer.lock
- Node.js
- package-lock.json
- yarn.lock
- Rust
- Cargo.lock
The path of these files does not matter.
@@ -1408,7 +1616,7 @@ Trivy scans a tar image with the following format.
- Kaniko (https://github.com/GoogleContainerTools/kaniko)
### Data source
## Data sources
- PHP
- https://github.com/FriendsOfPHP/security-advisories
- https://github.com/advisories?query=ecosystem%3Acomposer
@@ -1425,25 +1633,37 @@ Trivy scans a tar image with the following format.
- https://github.com/RustSec/advisory-db
# Usage
## Standalone
Trivy has several sub commands, image, fs, repo, client and server.
```
NAME:
trivy - A simple and comprehensive vulnerability scanner for containers
USAGE:
trivy image [options] image_name
VERSION:
v0.7.0
OPTIONS:
--quiet suppress progress bar and log output (default: false) [$TRIVY_QUIET]
--debug debug mode (default: false) [$TRIVY_DEBUG]
--cache-dir value cache directory (default: "/Users/simar/Library/Caches/trivy") [$TRIVY_CACHE_DIR]
USAGE:
trivy [global options] command [command options] image_name
VERSION:
v0.9.0
COMMANDS:
image, i scan an image
filesystem, fs scan local filesystem
repository, repo scan remote repository
client, c client mode
server, s server mode
help, h Shows a list of commands or help for one command
GLOBAL OPTIONS:
--quiet, -q suppress progress bar and log output (default: false) [$TRIVY_QUIET]
--debug, -d debug mode (default: false) [$TRIVY_DEBUG]
--cache-dir value cache directory (default: "/Users/teppei/Library/Caches/trivy") [$TRIVY_CACHE_DIR]
--help, -h show help (default: false)
--version, -v print the version (default: false)
```
## Sub commands
Trivy has three sub commands, image, client and server.
## Image
`fs` and `repo` have the same options as `image`.
```
NAME:
@@ -1473,6 +1693,8 @@ OPTIONS:
--help, -h show help (default: false)
```
## Client
```
NAME:
trivy client - client mode
@@ -1499,6 +1721,8 @@ OPTIONS:
--remote value server address (default: "http://localhost:4954") [$TRIVY_REMOTE]
```
## Server
```
NAME:
trivy server - server mode
@@ -1517,6 +1741,9 @@ OPTIONS:
--listen value listen address (default: "localhost:4954") [$TRIVY_LISTEN]
```
# Air-gapped environment
See [here](docs/air-gap.md)
# Comparison with other scanners
## Overview
@@ -1531,6 +1758,10 @@ OPTIONS:
| Docker Hub | ◯ | × | ◯ | × | × |
| GCR | ◯ | × | ◯ | ◯ | × |
## Blogs
- [Open Source CVE Scanner Round-Up: Clair vs Anchore vs Trivy](https://boxboat.com/2020/04/24/image-scanning-tech-compared/)
- [Docker Image Security: Static Analysis Tool Comparison Anchore Engine vs Clair vs Trivy](https://www.a10o.net/devsecops/docker-image-security-static-analysis-tool-comparison-anchore-engine-vs-clair-vs-trivy/)
## vs Clair
[Clair](https://github.com/coreos/clair) uses [alpine-secdb](https://github.com/alpinelinux/alpine-secdb/).
@@ -1681,11 +1912,6 @@ Try again with `--reset` option:
```
$ trivy image --reset
```
# Related Projects
- [Remic](https://github.com/knqyf263/remic)
- Vulnerability Scanner for Detecting Publicly Disclosed Vulnerabilities in Application Dependencies
---
# Credits

18
contrib/junit.tpl Normal file
View File

@@ -0,0 +1,18 @@
<?xml version="1.0" ?>
<testsuites>
{{- range . -}}
{{- $failures := len .Vulnerabilities }}
<testsuite tests="1" failures="{{ $failures }}" time="" name="{{ .Target }}">
{{- if not (eq .Type "") }}
<properties>
<property name="type" value="{{ .Type }}"></property>
</properties>
{{- end -}}
{{ range .Vulnerabilities }}
<testcase classname="{{ .PkgName }}-{{ .InstalledVersion }}" name="[{{ .Vulnerability.Severity }}] {{ .VulnerabilityID }}" time="">
<failure message={{escapeXML .Title | printf "%q" }} type="description">{{escapeXML .Description | printf "%q" }}</failure>
</testcase>
{{- end }}
</testsuite>
{{- end }}
</testsuites>

55
docs/air-gap.md Normal file
View File

@@ -0,0 +1,55 @@
# Air-gapped environment
Trivy can be used in air-gapped environments.
## Download the vulnerability database
At first, you need to download the vulnerability database for use in air-gapped environments.
Go to [trivy-db](https://github.com/aquasecurity/trivy-db/releases) and download `trivy-offline.db.tgz` in the latest release.
If you download `trivy-light-offline.db.tgz`, you have to run Trivy with `--light` option.
```
$ wget https://github.com/aquasecurity/trivy-db/releases/latest/download/trivy-offline.db.tgz
```
## Transfer the DB file into the air-gapped environment
The way of transfer depends on the environment.
```
$ rsync -av -e ssh /path/to/trivy-offline.db.tgz [user]@[host]:dst
```
## Put the DB file in Trivy's cache directory
You have to know where to put the DB file. The following command shows the default cache directory.
```
$ ssh user@host
$ trivy -h | grep cache
--cache-dir value cache directory (default: "/home/myuser/.cache/trivy") [$TRIVY_CACHE_DIR]
```
Put the DB file in the cache directory + `/db`.
```
$ mkdir -p /home/myuser/.cache/trivy/db
$ cd /home/myuser/.cache/trivy/db
$ mv /path/to/trivy-offline.db.tgz .
```
Then, decompress it.
`trivy-offline.db.tgz` file includes two files, `trivy.db` and `metadata.json`.
```
$ tar xvf trivy-offline.db.tgz
x trivy.db
x metadata.json
$ rm trivy-offline.db.tgz
```
In an air-gapped environment it is your responsibility to update the Trivy database on a regular basis, so that the scanner can detect recently-identified vulnerabilities.
## Run Trivy with --skip-update option
In an air-gapped environment, specify `--skip-update` so that Trivy doesn't attempt to download the latest database file.
```
$ trivy image --skip-update alpine:3.12
```

5
go.mod
View File

@@ -5,7 +5,7 @@ go 1.13
require (
github.com/aquasecurity/fanal v0.0.0-20200528202907-79693bf4a058
github.com/aquasecurity/go-dep-parser v0.0.0-20190819075924-ea223f0ef24b
github.com/aquasecurity/trivy-db v0.0.0-20200514134639-7e57e3e02470
github.com/aquasecurity/trivy-db v0.0.0-20200702223044-f0f6ca684644
github.com/caarlos0/env/v6 v6.0.0
github.com/cenkalti/backoff v2.2.1+incompatible
github.com/cheggaaa/pb/v3 v3.0.3
@@ -15,6 +15,7 @@ require (
github.com/google/go-containerregistry v0.0.0-20200331213917-3d03ed9b1ca2
github.com/google/go-github/v28 v28.1.1
github.com/google/wire v0.3.0
github.com/knqyf263/go-apk-version v0.0.0-20200609155635-041fdbb8563f
github.com/knqyf263/go-deb-version v0.0.0-20190517075300-09fca494f03d
github.com/knqyf263/go-rpm-version v0.0.0-20170716094938-74609b86c936
github.com/knqyf263/go-version v1.1.1
@@ -22,7 +23,7 @@ require (
github.com/mattn/go-colorable v0.1.4 // indirect
github.com/olekukonko/tablewriter v0.0.2-0.20190607075207-195002e6e56a
github.com/spf13/afero v1.2.2
github.com/stretchr/testify v1.4.0
github.com/stretchr/testify v1.6.1
github.com/testcontainers/testcontainers-go v0.3.1
github.com/twitchtv/twirp v5.10.1+incompatible
github.com/urfave/cli/v2 v2.2.0

14
go.sum
View File

@@ -52,8 +52,8 @@ github.com/aquasecurity/go-dep-parser v0.0.0-20190819075924-ea223f0ef24b h1:55Ul
github.com/aquasecurity/go-dep-parser v0.0.0-20190819075924-ea223f0ef24b/go.mod h1:BpNTD9vHfrejKsED9rx04ldM1WIbeyXGYxUrqTVwxVQ=
github.com/aquasecurity/testdocker v0.0.0-20200426142840-5f05bce6f12a h1:hsw7PpiymXP64evn/K7gsj3hWzMqLrdoeE6JkqDocVg=
github.com/aquasecurity/testdocker v0.0.0-20200426142840-5f05bce6f12a/go.mod h1:psfu0MVaiTDLpNxCoNsTeILSKY2EICBwv345f3M+Ffs=
github.com/aquasecurity/trivy-db v0.0.0-20200514134639-7e57e3e02470 h1:6VE+g4AK2uivPqZtVk/QtcCBb2rUjAvKqDNexSgqMC0=
github.com/aquasecurity/trivy-db v0.0.0-20200514134639-7e57e3e02470/go.mod h1:F77bF2nRbcH4EIhhcNEP585MoAKdLpEP3dihF9V1Hbw=
github.com/aquasecurity/trivy-db v0.0.0-20200702223044-f0f6ca684644 h1:cqYzeXGz/K0kCIIFa2uYe1vrc3ImoA45kDarAo5dz3Y=
github.com/aquasecurity/trivy-db v0.0.0-20200702223044-f0f6ca684644/go.mod h1:EiFA908RL0ACrbYo/9HfT7f9QcdC2bZoIO5XAAcvz9A=
github.com/aquasecurity/vuln-list-update v0.0.0-20191016075347-3d158c2bf9a2 h1:xbdUfr2KE4THsFx9CFWtWpU91lF+YhgP46moV94nYTA=
github.com/aquasecurity/vuln-list-update v0.0.0-20191016075347-3d158c2bf9a2/go.mod h1:6NhOP0CjZJL27bZZcaHECtzWdwDDm2g6yCY0QgXEGQQ=
github.com/araddon/dateparse v0.0.0-20190426192744-0d74ffceef83/go.mod h1:SLqhdZcd+dF3TEVL2RMoob5bBP5R1P1qkox+HtCBgGI=
@@ -272,6 +272,8 @@ github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvW
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/knqyf263/berkeleydb v0.0.0-20190501065933-fafe01fb9662/go.mod h1:bu1CcN4tUtoRcI/B/RFHhxMNKFHVq/c3SV+UTyduoXg=
github.com/knqyf263/go-apk-version v0.0.0-20200609155635-041fdbb8563f h1:GvCU5GXhHq+7LeOzx/haG7HSIZokl3/0GkoUFzsRJjg=
github.com/knqyf263/go-apk-version v0.0.0-20200609155635-041fdbb8563f/go.mod h1:q59u9px8b7UTj0nIjEjvmTWekazka6xIt6Uogz5Dm+8=
github.com/knqyf263/go-deb-version v0.0.0-20190517075300-09fca494f03d h1:X4cedH4Kn3JPupAwwWuo4AzYp16P0OyLO9d7OnMZc/c=
github.com/knqyf263/go-deb-version v0.0.0-20190517075300-09fca494f03d/go.mod h1:o8sgWoz3JADecfc/cTYD92/Et1yMqMy0utV1z+VaZao=
github.com/knqyf263/go-rpm-version v0.0.0-20170716094938-74609b86c936 h1:HDjRqotkViMNcGMGicb7cgxklx8OwnjtCBmyWEqrRvM=
@@ -427,6 +429,9 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/testcontainers/testcontainers-go v0.3.1 h1:KZkEKNfnlsipJblzGCz6fmzd+0DzJ3djulYrislG3Zw=
github.com/testcontainers/testcontainers-go v0.3.1/go.mod h1:br7bkzIukhPSIjy07Ma3OuXjjFvl2jm7CDU0LQNsqLw=
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
@@ -468,7 +473,6 @@ golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnf
golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190404164418-38d8ce5564a5/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
@@ -508,6 +512,7 @@ golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200301022130-244492dfa37a h1:GuSPYbZzB5/dcLNCwLQLsg3obCJtX9IJhpXkvY7kzk0=
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
@@ -533,7 +538,6 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -644,6 +648,8 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gotest.tools v0.0.0-20181223230014-1083505acf35/go.mod h1:R//lfYlUuTOTfblYI3lGoAAAebUdzjvbmQsuB7Ykd90=
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=

View File

@@ -94,3 +94,4 @@ dockers:
- "--label=org.label-schema.vcs-ref={{ .FullCommit }}"
extra_files:
- contrib/gitlab.tpl
- contrib/junit.tpl

View File

@@ -5,6 +5,7 @@ package integration
import (
"compress/gzip"
"context"
"encoding/json"
"flag"
"io"
"io/ioutil"
@@ -13,8 +14,6 @@ import (
"path/filepath"
"time"
dbFile "github.com/aquasecurity/trivy/pkg/db"
"github.com/aquasecurity/trivy-db/pkg/db"
"github.com/spf13/afero"
)
@@ -53,7 +52,9 @@ func gunzipDB() (string, error) {
return "", err
}
err = dbFile.NewMetadata(afero.NewOsFs(), tmpDir).Store(db.Metadata{
fs := afero.NewOsFs()
metadataFile := filepath.Join(dbDir, "metadata.json")
b, err := json.Marshal(db.Metadata{
Version: 1,
Type: 1,
NextUpdate: time.Time{},
@@ -62,6 +63,10 @@ func gunzipDB() (string, error) {
if err != nil {
return "", err
}
err = afero.WriteFile(fs, metadataFile, b, 0600)
if err != nil {
return "", err
}
return tmpDir, nil
}

View File

@@ -2,6 +2,7 @@ package internal
import (
"bytes"
"encoding/json"
"io/ioutil"
"os"
"path/filepath"
@@ -10,7 +11,6 @@ import (
"github.com/stretchr/testify/require"
dbFile "github.com/aquasecurity/trivy/pkg/db"
"github.com/spf13/afero"
"github.com/aquasecurity/trivy-db/pkg/db"
@@ -87,17 +87,20 @@ Vulnerability DB:
}
if tt.createDB {
m := dbFile.NewMetadata(afero.NewOsFs(), cacheDir)
fs := afero.NewOsFs()
err := os.MkdirAll(filepath.Join(cacheDir, "db"), os.ModePerm)
require.NoError(t, err)
metadataFile := filepath.Join(cacheDir, "db", "metadata.json")
err = m.Store(db.Metadata{
b, err := json.Marshal(db.Metadata{
Version: 42,
Type: 1,
NextUpdate: time.Unix(1584403020, 0),
UpdatedAt: time.Unix(1584402020, 0),
})
require.NoError(t, err)
err = afero.WriteFile(fs, metadataFile, b, 0600)
require.NoError(t, err)
}
fw := new(bytes.Buffer)

View File

@@ -21,7 +21,7 @@ type GlobalConfig struct {
func NewGlobalConfig(c *cli.Context) (GlobalConfig, error) {
quiet := c.Bool("quiet")
debug := c.Bool("debug")
logger, err := log.NewLogger(quiet, debug)
logger, err := log.NewLogger(debug, quiet)
if err != nil {
return GlobalConfig{}, xerrors.New("failed to create a logger")
}

View File

@@ -59,6 +59,7 @@ type Operation interface {
type dbOperation interface {
GetMetadata() (metadata db.Metadata, err error)
StoreMetadata(metadata db.Metadata, dir string) (err error)
}
type Client struct {
@@ -181,17 +182,17 @@ func (c Client) UpdateMetadata(cacheDir string) error {
metadata, err := c.dbc.GetMetadata()
if err != nil {
return xerrors.Errorf("unable to get a metadata: %w", err)
return xerrors.Errorf("unable to get metadata: %w", err)
}
if err = c.metadata.Store(metadata); err != nil {
if err = c.dbc.StoreMetadata(metadata, filepath.Join(cacheDir, "db")); err != nil {
return xerrors.Errorf("failed to store metadata: %w", err)
}
return nil
}
type Metadata struct {
type Metadata struct { // TODO: Move all Metadata things to trivy-db repo
fs afero.Fs
filePath string
}
@@ -210,20 +211,6 @@ func MetadataPath(cacheDir string) string {
return filepath.Join(dbDir, metadataFile)
}
// StoreMetadata stores database metadata as a file
func (m Metadata) Store(metadata db.Metadata) error {
f, err := m.fs.Create(m.filePath)
if err != nil {
return xerrors.Errorf("unable to create a metadata file: %w", err)
}
defer f.Close()
if err = json.NewEncoder(f).Encode(metadata); err != nil {
return xerrors.Errorf("unable to encode metadata: %w", err)
}
return nil
}
// DeleteMetadata deletes the file of database metadata
func (m Metadata) Delete() error {
if err := m.fs.Remove(m.filePath); err != nil {

View File

@@ -2,6 +2,8 @@ package db
import (
"context"
"encoding/json"
"errors"
"io/ioutil"
"os"
"testing"
@@ -142,11 +144,13 @@ func TestClient_NeedsUpdate(t *testing.T) {
fs := afero.NewMemMapFs()
metadata := NewMetadata(fs, "/cache")
if tc.metadata != (db.Metadata{}) {
metadata.Store(tc.metadata)
b, err := json.Marshal(tc.metadata)
require.NoError(t, err)
err = afero.WriteFile(fs, metadata.filePath, b, 0600)
require.NoError(t, err)
}
client := Client{
//dbc: mockConfig,
clock: tc.clock,
metadata: metadata,
}
@@ -161,22 +165,15 @@ func TestClient_NeedsUpdate(t *testing.T) {
}
assert.Equal(t, tc.expected, needsUpdate)
//mockConfig.AssertExpectations(t)
})
}
}
func TestClient_Download(t *testing.T) {
type getMetadataOutput struct {
metadata db.Metadata
err error
}
testCases := []struct {
name string
light bool
downloadDB []github.DownloadDBExpectation
getMetadata dbOperationGetMetadataExpectation
expectedContent []byte
expectedError error
}{
@@ -191,15 +188,6 @@ func TestClient_Download(t *testing.T) {
},
},
},
getMetadata: dbOperationGetMetadataExpectation{
Returns: dbOperationGetMetadataReturns{
Metadata: db.Metadata{
Version: 1,
Type: db.TypeFull,
NextUpdate: time.Date(2019, 9, 1, 0, 0, 0, 0, time.UTC),
},
},
},
},
{
name: "DownloadDB returns an error",
@@ -235,7 +223,6 @@ func TestClient_Download(t *testing.T) {
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
mockConfig := new(mockDbOperation)
mockConfig.ApplyGetMetadataExpectation(tc.getMetadata)
mockGitHubClient, err := github.NewMockClient(tc.downloadDB)
require.NoError(t, err, tc.name)
@@ -263,3 +250,99 @@ func TestClient_Download(t *testing.T) {
})
}
}
func TestClient_UpdateMetadata(t *testing.T) {
testCases := []struct {
name string
getMetadataExpectation dbOperationGetMetadataExpectation
storeMetadataExpectation dbOperationStoreMetadataExpectation
expectedError error
}{
{
name: "happy path",
getMetadataExpectation: dbOperationGetMetadataExpectation{
Returns: dbOperationGetMetadataReturns{
Metadata: db.Metadata{
Version: 1,
Type: 1,
NextUpdate: time.Date(2020, 4, 30, 23, 59, 59, 0, time.UTC),
UpdatedAt: time.Date(2006, 4, 30, 23, 59, 59, 0, time.UTC),
},
Err: nil,
},
},
storeMetadataExpectation: dbOperationStoreMetadataExpectation{
Metadata: db.Metadata{
Version: 1,
Type: 1,
NextUpdate: time.Date(2020, 4, 30, 23, 59, 59, 0, time.UTC),
UpdatedAt: time.Date(2006, 4, 30, 23, 59, 59, 0, time.UTC),
},
},
},
{
name: "sad path, get metadata fails",
getMetadataExpectation: dbOperationGetMetadataExpectation{
Returns: dbOperationGetMetadataReturns{
Err: errors.New("get metadata failed"),
},
},
expectedError: errors.New("unable to get metadata: get metadata failed"),
},
{
name: "sad path, store metadata fails",
getMetadataExpectation: dbOperationGetMetadataExpectation{
Returns: dbOperationGetMetadataReturns{
Metadata: db.Metadata{
Version: 1,
Type: 1,
NextUpdate: time.Date(2020, 4, 30, 23, 59, 59, 0, time.UTC),
UpdatedAt: time.Date(2006, 4, 30, 23, 59, 59, 0, time.UTC),
},
Err: nil,
},
},
storeMetadataExpectation: dbOperationStoreMetadataExpectation{
Metadata: db.Metadata{
Version: 1,
Type: 1,
NextUpdate: time.Date(2020, 4, 30, 23, 59, 59, 0, time.UTC),
UpdatedAt: time.Date(2006, 4, 30, 23, 59, 59, 0, time.UTC),
},
Returns: dbOperationStoreMetadataReturns{
Err: errors.New("store metadata failed"),
},
},
expectedError: errors.New("failed to store metadata: store metadata failed"),
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
mockConfig := new(mockDbOperation)
err := log.InitLogger(false, true)
require.NoError(t, err, "failed to init logger")
mockConfig.ApplyGetMetadataExpectation(tc.getMetadataExpectation)
mockConfig.ApplyStoreMetadataExpectation(tc.storeMetadataExpectation)
fs := afero.NewMemMapFs()
metadata := NewMetadata(fs, "/cache")
dir, err := ioutil.TempDir("", "db")
require.NoError(t, err, tc.name)
defer os.RemoveAll(dir)
pb := indicator.NewProgressBar(true)
client := NewClient(mockConfig, nil, pb, nil, metadata)
err = client.UpdateMetadata(dir)
switch {
case tc.expectedError != nil:
assert.EqualError(t, err, tc.expectedError.Error(), tc.name)
default:
assert.NoError(t, err, tc.name)
}
})
}
}

View File

@@ -3,7 +3,7 @@
package db
import (
pkgdb "github.com/aquasecurity/trivy-db/pkg/db"
"github.com/aquasecurity/trivy-db/pkg/db"
mock "github.com/stretchr/testify/mock"
)
@@ -13,7 +13,7 @@ type mockDbOperation struct {
}
type dbOperationGetMetadataReturns struct {
Metadata pkgdb.Metadata
Metadata db.Metadata
Err error
}
@@ -33,14 +33,14 @@ func (_m *mockDbOperation) ApplyGetMetadataExpectations(expectations []dbOperati
}
// GetMetadata provides a mock function with given fields:
func (_m *mockDbOperation) GetMetadata() (pkgdb.Metadata, error) {
func (_m *mockDbOperation) GetMetadata() (db.Metadata, error) {
ret := _m.Called()
var r0 pkgdb.Metadata
if rf, ok := ret.Get(0).(func() pkgdb.Metadata); ok {
var r0 db.Metadata
if rf, ok := ret.Get(0).(func() db.Metadata); ok {
r0 = rf()
} else {
r0 = ret.Get(0).(pkgdb.Metadata)
r0 = ret.Get(0).(db.Metadata)
}
var r1 error
@@ -52,3 +52,37 @@ func (_m *mockDbOperation) GetMetadata() (pkgdb.Metadata, error) {
return r0, r1
}
type dbOperationStoreMetadataReturns struct {
Err error
}
type dbOperationStoreMetadataExpectation struct {
Metadata db.Metadata
Dir string
Returns dbOperationStoreMetadataReturns
}
func (_m *mockDbOperation) ApplyStoreMetadataExpectation(e dbOperationStoreMetadataExpectation) {
_m.On("StoreMetadata", e.Metadata, mock.Anything).Return(e.Returns.Err)
}
func (_m *mockDbOperation) ApplyStoreMetadataExpectations(expectations []dbOperationStoreMetadataExpectation) {
for _, e := range expectations {
_m.ApplyStoreMetadataExpectation(e)
}
}
// StoreMetadata provides a mock function with given fields: metadata, dir
func (_m *mockDbOperation) StoreMetadata(metadata db.Metadata, dir string) error {
ret := _m.Called(metadata, dir)
var r0 error
if rf, ok := ret.Get(0).(func(db.Metadata, string) error); ok {
r0 = rf(metadata, dir)
} else {
r0 = ret.Error(0)
}
return r0
}

View File

@@ -4,7 +4,7 @@ import (
"strings"
"time"
version "github.com/knqyf263/go-deb-version"
version "github.com/knqyf263/go-apk-version"
"golang.org/x/xerrors"
ftypes "github.com/aquasecurity/fanal/types"
@@ -37,6 +37,7 @@ var (
"3.9": time.Date(2020, 11, 1, 23, 59, 59, 0, time.UTC),
"3.10": time.Date(2021, 5, 1, 23, 59, 59, 0, time.UTC),
"3.11": time.Date(2021, 11, 1, 23, 59, 59, 0, time.UTC),
"3.12": time.Date(2022, 5, 1, 23, 59, 59, 0, time.UTC),
}
)

View File

@@ -153,6 +153,54 @@ func TestScanner_Detect(t *testing.T) {
},
},
},
{
name: "contain pre",
args: args{
osVer: "3.12",
pkgs: []ftypes.Package{
{
Name: "test",
Version: "0.1.0_alpha",
Layer: ftypes.Layer{
DiffID: "sha256:932da51564135c98a49a34a193d6cd363d8fa4184d957fde16c9d8527b3f3b02",
},
},
},
},
mocks: mocks{
get: []get{
{
input: getInput{
osVer: "3.12",
pkgName: "test",
},
output: getOutput{
advisories: []dbTypes.Advisory{
{
VulnerabilityID: "CVE-2030-0001",
FixedVersion: "0.1.0_alpha_pre2",
},
{
VulnerabilityID: "CVE-2030-0002",
FixedVersion: "0.1.0_alpha2",
},
},
},
},
},
},
want: []types.DetectedVulnerability{
{
VulnerabilityID: "CVE-2030-0002",
PkgName: "test",
InstalledVersion: "0.1.0_alpha",
FixedVersion: "0.1.0_alpha2",
Layer: ftypes.Layer{
DiffID: "sha256:932da51564135c98a49a34a193d6cd363d8fa4184d957fde16c9d8527b3f3b02",
},
},
},
},
{
name: "Get returns an error",
args: args{

View File

@@ -24,43 +24,56 @@ func InitLogger(debug, disable bool) (err error) {
}
func NewLogger(debug, disable bool) (*zap.SugaredLogger, error) {
level := zap.NewAtomicLevel()
if debug {
level.SetLevel(zapcore.DebugLevel)
} else {
level.SetLevel(zapcore.InfoLevel)
// First, define our level-handling logic.
errorPriority := zap.LevelEnablerFunc(func(lvl zapcore.Level) bool {
return lvl >= zapcore.ErrorLevel
})
logPriority := zap.LevelEnablerFunc(func(lvl zapcore.Level) bool {
if debug {
return lvl < zapcore.ErrorLevel
}
// Not enable debug level
return zapcore.DebugLevel < lvl && lvl < zapcore.ErrorLevel
})
encoderConfig := zapcore.EncoderConfig{
TimeKey: "Time",
LevelKey: "Level",
NameKey: "Name",
CallerKey: "Caller",
MessageKey: "Msg",
StacktraceKey: "St",
EncodeLevel: zapcore.CapitalColorLevelEncoder,
EncodeTime: zapcore.ISO8601TimeEncoder,
EncodeDuration: zapcore.StringDurationEncoder,
EncodeCaller: zapcore.ShortCallerEncoder,
}
myConfig := zap.Config{
Level: level,
Encoding: "console",
Development: debug,
DisableStacktrace: true,
DisableCaller: true,
EncoderConfig: zapcore.EncoderConfig{
TimeKey: "Time",
LevelKey: "Level",
NameKey: "Name",
CallerKey: "Caller",
MessageKey: "Msg",
StacktraceKey: "St",
EncodeLevel: zapcore.CapitalColorLevelEncoder,
EncodeTime: zapcore.ISO8601TimeEncoder,
EncodeDuration: zapcore.StringDurationEncoder,
EncodeCaller: zapcore.ShortCallerEncoder,
},
OutputPaths: []string{"stdout"},
ErrorOutputPaths: []string{"stderr"},
}
consoleEncoder := zapcore.NewConsoleEncoder(encoderConfig)
// High-priority output should also go to standard error, and low-priority
// output should also go to standard out.
consoleLogs := zapcore.Lock(os.Stdout)
consoleErrors := zapcore.Lock(os.Stderr)
if disable {
myConfig.OutputPaths = []string{os.DevNull}
myConfig.ErrorOutputPaths = []string{os.DevNull}
devNull, err := os.Create(os.DevNull)
if err != nil {
return nil, err
}
// Discard low-priority output
consoleLogs = zapcore.Lock(devNull)
}
logger, err := myConfig.Build()
if err != nil {
return nil, xerrors.Errorf("failed to build zap config: %w", err)
core := zapcore.NewTee(
zapcore.NewCore(consoleEncoder, consoleErrors, errorPriority),
zapcore.NewCore(consoleEncoder, consoleLogs, logPriority),
)
opts := []zap.Option{zap.ErrorOutput(zapcore.Lock(os.Stderr))}
if debug {
opts = append(opts, zap.Development())
}
logger := zap.New(core, opts...)
return logger.Sugar(), nil
}

View File

@@ -1,7 +1,9 @@
package report
import (
"bytes"
"encoding/json"
"encoding/xml"
"fmt"
"io"
"io/ioutil"
@@ -26,14 +28,6 @@ type Result struct {
}
func WriteResults(format string, output io.Writer, results Results, outputTemplate string, light bool) error {
if strings.HasPrefix(outputTemplate, "@") {
buf, err := ioutil.ReadFile(strings.TrimPrefix(outputTemplate, "@"))
if err != nil {
return xerrors.Errorf("Error retrieving template from path: %w", err)
}
outputTemplate = string(buf)
}
var writer Writer
switch format {
case "table":
@@ -41,7 +35,23 @@ func WriteResults(format string, output io.Writer, results Results, outputTempla
case "json":
writer = &JsonWriter{Output: output}
case "template":
tmpl, err := template.New("output template").Parse(outputTemplate)
if strings.HasPrefix(outputTemplate, "@") {
buf, err := ioutil.ReadFile(strings.TrimPrefix(outputTemplate, "@"))
if err != nil {
return xerrors.Errorf("Error retrieving template from path: %w", err)
}
outputTemplate = string(buf)
}
tmpl, err := template.New("output template").Funcs(template.FuncMap{
"escapeXML": func(input string) string {
escaped := &bytes.Buffer{}
if err := xml.EscapeText(escaped, []byte(input)); err != nil {
fmt.Printf("error while escapeString to XML: %v", err.Error())
return input
}
return escaped.String()
},
}).Parse(outputTemplate)
if err != nil {
return xerrors.Errorf("error parsing template: %w", err)
}

View File

@@ -230,13 +230,59 @@ func TestReportWriter_Template(t *testing.T) {
template: "{{ range . }}{{ range .Vulnerabilities}}{{ println .VulnerabilityID .Severity }}{{ end }}{{ end }}",
expected: "CVE-2019-0000 HIGH\nCVE-2019-0000 HIGH\nCVE-2019-0001 CRITICAL\n",
},
{
name: "happy path",
detectedVulns: []types.DetectedVulnerability{
{
VulnerabilityID: "123",
PkgName: "foo",
InstalledVersion: "1.2.3",
FixedVersion: "3.4.5",
Vulnerability: dbTypes.Vulnerability{
Title: `gcc: POWER9 "DARN" RNG intrinsic produces repeated output`,
Description: `curl version curl 7.20.0 to and including curl 7.59.0 contains a CWE-126: Buffer Over-read vulnerability in denial of service that can result in curl can be tricked into reading data beyond the end of a heap based buffer used to store downloaded RTSP content.. This vulnerability appears to have been fixed in curl < 7.20.0 and curl >= 7.60.0.`,
Severity: "HIGH",
},
},
},
template: `<testsuites>
{{- range . -}}
{{- $failures := len .Vulnerabilities }}
<testsuite tests="1" failures="{{ $failures }}" time="" name="{{ .Target }}">
{{- if not (eq .Type "") }}
<properties>
<property name="type" value="{{ .Type }}"></property>
</properties>
{{- end -}}
{{ range .Vulnerabilities }}
<testcase classname="{{ .PkgName }}-{{ .InstalledVersion }}" name="[{{ .Vulnerability.Severity }}] {{ .VulnerabilityID }}" time="">
<failure message={{escapeXML .Title | printf "%q" }} type="description">{{escapeXML .Description | printf "%q" }}</failure>
</testcase>
{{- end }}
</testsuite>
{{- end }}
</testsuites>`,
expected: `<testsuites>
<testsuite tests="1" failures="1" time="" name="foojunit">
<properties>
<property name="type" value="test"></property>
</properties>
<testcase classname="foo-1.2.3" name="[HIGH] 123" time="">
<failure message="gcc: POWER9 &#34;DARN&#34; RNG intrinsic produces repeated output" type="description">"curl version curl 7.20.0 to and including curl 7.59.0 contains a CWE-126: Buffer Over-read vulnerability in denial of service that can result in curl can be tricked into reading data beyond the end of a heap based buffer used to store downloaded RTSP content.. This vulnerability appears to have been fixed in curl &lt; 7.20.0 and curl &gt;= 7.60.0."</failure>
</testcase>
</testsuite>
</testsuites>`,
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
tmplWritten := bytes.Buffer{}
inputResults := report.Results{
{
Target: "foojson",
Target: "foojunit",
Type: "test",
Vulnerabilities: tc.detectedVulns,
},
}

View File

@@ -8,7 +8,6 @@ import (
"golang.org/x/xerrors"
"github.com/aquasecurity/fanal/cache"
ftypes "github.com/aquasecurity/fanal/types"
"github.com/aquasecurity/trivy/pkg/rpc"
"github.com/aquasecurity/trivy/pkg/scanner"
"github.com/aquasecurity/trivy/pkg/scanner/local"
@@ -78,17 +77,9 @@ func (s *CacheServer) PutBlob(_ context.Context, in *rpcCache.PutBlobRequest) (*
}
func (s *CacheServer) MissingBlobs(_ context.Context, in *rpcCache.MissingBlobsRequest) (*rpcCache.MissingBlobsResponse, error) {
var layerIDs []string
for _, blobID := range in.BlobIds {
l, err := s.cache.GetBlob(blobID)
if err != nil || l.SchemaVersion != ftypes.BlobJSONSchemaVersion {
layerIDs = append(layerIDs, blobID)
}
missingArtifact, blobIDs, err := s.cache.MissingBlobs(in.ArtifactId, in.BlobIds)
if err != nil {
return nil, xerrors.Errorf("failed to get missing blobs: %w", err)
}
var missingImage bool
img, err := s.cache.GetArtifact(in.ArtifactId)
if err != nil || img.SchemaVersion != ftypes.ArtifactJSONSchemaVersion {
missingImage = true
}
return &rpcCache.MissingBlobsResponse{MissingArtifact: missingImage, MissingBlobIds: layerIDs}, nil
return &rpcCache.MissingBlobsResponse{MissingArtifact: missingArtifact, MissingBlobIds: blobIDs}, nil
}

View File

@@ -473,12 +473,11 @@ func TestCacheServer_MissingBlobs(t *testing.T) {
in *rpcCache.MissingBlobsRequest
}
tests := []struct {
name string
args args
getLayerExpectations []cache.LocalArtifactCacheGetBlobExpectation
getImageExpectations []cache.LocalArtifactCacheGetArtifactExpectation
want *rpcCache.MissingBlobsResponse
wantErr string
name string
args args
getArtifactCacheMissingBlobsExpectations []cache.ArtifactCacheMissingBlobsExpectation
want *rpcCache.MissingBlobsResponse
wantErr string
}{
{
name: "happy path",
@@ -491,100 +490,24 @@ func TestCacheServer_MissingBlobs(t *testing.T) {
},
},
},
getLayerExpectations: []cache.LocalArtifactCacheGetBlobExpectation{
getArtifactCacheMissingBlobsExpectations: []cache.ArtifactCacheMissingBlobsExpectation{
{
Args: cache.LocalArtifactCacheGetBlobArgs{
BlobID: "sha256:932da51564135c98a49a34a193d6cd363d8fa4184d957fde16c9d8527b3f3b02",
},
Returns: cache.LocalArtifactCacheGetBlobReturns{
BlobInfo: ftypes.BlobInfo{},
},
},
{
Args: cache.LocalArtifactCacheGetBlobArgs{
BlobID: "sha256:dffd9992ca398466a663c87c92cfea2a2db0ae0cf33fcb99da60eec52addbfc5",
},
Returns: cache.LocalArtifactCacheGetBlobReturns{
BlobInfo: ftypes.BlobInfo{
SchemaVersion: 1,
},
},
},
},
getImageExpectations: []cache.LocalArtifactCacheGetArtifactExpectation{
{
Args: cache.LocalArtifactCacheGetArtifactArgs{
ArtifactID: "sha256:e7d92cdc71feacf90708cb59182d0df1b911f8ae022d29e8e95d75ca6a99776a",
},
Returns: cache.LocalArtifactCacheGetArtifactReturns{
ArtifactInfo: ftypes.ArtifactInfo{
SchemaVersion: 1,
},
},
Args: cache.ArtifactCacheMissingBlobsArgs{ArtifactID: "sha256:e7d92cdc71feacf90708cb59182d0df1b911f8ae022d29e8e95d75ca6a99776a",
BlobIDs: []string{"sha256:932da51564135c98a49a34a193d6cd363d8fa4184d957fde16c9d8527b3f3b02", "sha256:dffd9992ca398466a663c87c92cfea2a2db0ae0cf33fcb99da60eec52addbfc5"}},
Returns: cache.ArtifactCacheMissingBlobsReturns{
MissingArtifact: false, MissingBlobIDs: []string{"sha256:dffd9992ca398466a663c87c92cfea2a2db0ae0cf33fcb99da60eec52addbfc5"}, Err: nil},
},
},
want: &rpcCache.MissingBlobsResponse{
MissingArtifact: false,
MissingBlobIds: []string{"sha256:932da51564135c98a49a34a193d6cd363d8fa4184d957fde16c9d8527b3f3b02"},
},
},
{
name: "schema version doesn't match",
args: args{
in: &rpcCache.MissingBlobsRequest{
ArtifactId: "sha256:e7d92cdc71feacf90708cb59182d0df1b911f8ae022d29e8e95d75ca6a99776a",
BlobIds: []string{
"sha256:932da51564135c98a49a34a193d6cd363d8fa4184d957fde16c9d8527b3f3b02",
"sha256:dffd9992ca398466a663c87c92cfea2a2db0ae0cf33fcb99da60eec52addbfc5",
},
},
},
getLayerExpectations: []cache.LocalArtifactCacheGetBlobExpectation{
{
Args: cache.LocalArtifactCacheGetBlobArgs{
BlobID: "sha256:932da51564135c98a49a34a193d6cd363d8fa4184d957fde16c9d8527b3f3b02",
},
Returns: cache.LocalArtifactCacheGetBlobReturns{
BlobInfo: ftypes.BlobInfo{
SchemaVersion: 0,
},
},
},
{
Args: cache.LocalArtifactCacheGetBlobArgs{
BlobID: "sha256:dffd9992ca398466a663c87c92cfea2a2db0ae0cf33fcb99da60eec52addbfc5",
},
Returns: cache.LocalArtifactCacheGetBlobReturns{
BlobInfo: ftypes.BlobInfo{
SchemaVersion: -1,
},
},
},
},
getImageExpectations: []cache.LocalArtifactCacheGetArtifactExpectation{
{
Args: cache.LocalArtifactCacheGetArtifactArgs{
ArtifactID: "sha256:e7d92cdc71feacf90708cb59182d0df1b911f8ae022d29e8e95d75ca6a99776a",
},
Returns: cache.LocalArtifactCacheGetArtifactReturns{
ArtifactInfo: ftypes.ArtifactInfo{},
},
},
},
want: &rpcCache.MissingBlobsResponse{
MissingArtifact: true,
MissingBlobIds: []string{
"sha256:932da51564135c98a49a34a193d6cd363d8fa4184d957fde16c9d8527b3f3b02",
"sha256:dffd9992ca398466a663c87c92cfea2a2db0ae0cf33fcb99da60eec52addbfc5",
},
MissingBlobIds: []string{"sha256:dffd9992ca398466a663c87c92cfea2a2db0ae0cf33fcb99da60eec52addbfc5"},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
mockCache := new(mockCache)
mockCache.ApplyGetBlobExpectations(tt.getLayerExpectations)
mockCache.ApplyGetArtifactExpectations(tt.getImageExpectations)
mockCache.ApplyMissingBlobsExpectations(tt.getArtifactCacheMissingBlobsExpectations)
s := NewCacheServer(mockCache)
got, err := s.MissingBlobs(tt.args.ctx, tt.args.in)
@@ -597,7 +520,7 @@ func TestCacheServer_MissingBlobs(t *testing.T) {
}
assert.Equal(t, tt.want, got)
mockCache.MockLocalArtifactCache.AssertExpectations(t)
mockCache.MockArtifactCache.AssertExpectations(t)
})
}
}

View File

@@ -146,7 +146,74 @@ func TestClient_FillInfo(t *testing.T) {
},
},
{
name: "happy path, with only OS vulnerability, yes vendor severity, with both NVD and vendor vectors",
name: "happy path, with only OS vulnerability, yes vendor severity, with both NVD and CVSS info",
getVulnerability: []db.GetVulnerabilityExpectation{
{
Args: db.GetVulnerabilityArgs{
VulnerabilityID: "CVE-2019-0001",
},
Returns: db.GetVulnerabilityReturns{
Vulnerability: dbTypes.Vulnerability{
Title: "dos",
Description: "dos vulnerability",
Severity: dbTypes.SeverityMedium.String(),
VendorSeverity: dbTypes.VendorSeverity{
vulnerability.RedHat: dbTypes.SeverityLow, // CentOS uses RedHat
},
CVSS: map[string]dbTypes.CVSS{
vulnerability.Nvd: {
V2Vector: "(AV:N/AC:L/Au:N/C:P/I:P/A:P)",
V2Score: 4.5,
V3Vector: "CVSS:3.0/PR:N/UI:N/S:U/C:H/I:H/A:H",
V3Score: 5.6,
},
vulnerability.RedHat: {
V2Vector: "AV:N/AC:M/Au:N/C:N/I:P/A:N",
V2Score: 7.8,
V3Vector: "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
V3Score: 9.8,
},
},
References: []string{"http://example.com"},
},
},
},
},
args: args{
vulns: []types.DetectedVulnerability{
{VulnerabilityID: "CVE-2019-0001"},
},
reportType: vulnerability.CentOS,
},
expectedVulnerabilities: []types.DetectedVulnerability{
{
VulnerabilityID: "CVE-2019-0001",
Vulnerability: dbTypes.Vulnerability{
Title: "dos",
Description: "dos vulnerability",
Severity: dbTypes.SeverityLow.String(),
References: []string{"http://example.com"},
CVSS: map[string]dbTypes.CVSS{
vulnerability.Nvd: {
V2Vector: "(AV:N/AC:L/Au:N/C:P/I:P/A:P)",
V2Score: 4.5,
V3Vector: "CVSS:3.0/PR:N/UI:N/S:U/C:H/I:H/A:H",
V3Score: 5.6,
},
vulnerability.RedHat: {
V2Vector: "AV:N/AC:M/Au:N/C:N/I:P/A:N",
V2Score: 7.8,
V3Vector: "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
V3Score: 9.8,
},
},
},
SeveritySource: vulnerability.RedHat,
},
},
},
{
name: "happy path, with only OS vulnerability, yes vendor severity, with both NVD and deprecated vendor vectors",
getVulnerability: []db.GetVulnerabilityExpectation{
{
Args: db.GetVulnerabilityArgs{