mirror of
https://github.com/aquasecurity/trivy.git
synced 2025-12-09 14:20:47 -08:00
Compare commits
22 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a9ff0b5243 | ||
|
|
0a271a04cc | ||
|
|
6fa78df282 | ||
|
|
b62536fcdc | ||
|
|
9741d4ae94 | ||
|
|
68f326d9e1 | ||
|
|
76ee7291d6 | ||
|
|
d31f09035e | ||
|
|
8d7c2e6d2a | ||
|
|
9269a305fb | ||
|
|
073b315737 | ||
|
|
47c46fbe17 | ||
|
|
39572968bb | ||
|
|
4383764cae | ||
|
|
e0ef0563ce | ||
|
|
d9cf2c487d | ||
|
|
58bf4b21e7 | ||
|
|
e95c619eaa | ||
|
|
cd04c0bdb2 | ||
|
|
fd74926e76 | ||
|
|
f82ff5a4fd | ||
|
|
fa72bef8d4 |
@@ -1 +1,2 @@
|
||||
.circleci
|
||||
imgs
|
||||
|
||||
45
.github/ISSUE_TEMPLATE.md
vendored
Normal file
45
.github/ISSUE_TEMPLATE.md
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
<!--
|
||||
|
||||
---------------------------------------------------
|
||||
FEATURE REQUEST
|
||||
---------------------------------------------------
|
||||
|
||||
If this is a FEATURE REQUEST, request format does not matter
|
||||
|
||||
|
||||
---------------------------------------------------
|
||||
BUG REPORT INFORMATION
|
||||
---------------------------------------------------
|
||||
|
||||
You do NOT have to include this information if this is a FEATURE REQUEST
|
||||
|
||||
If this is a BUG REPORT, provide key information from your environment:
|
||||
|
||||
-->
|
||||
|
||||
**Description**
|
||||
|
||||
<!--
|
||||
Briefly describe the problem you are having in a few paragraphs.
|
||||
-->
|
||||
|
||||
**What did you expect to happen?**
|
||||
|
||||
|
||||
**What happened instead?**
|
||||
|
||||
|
||||
**Output of run with `-debug`:**
|
||||
|
||||
```
|
||||
(paste your output here)
|
||||
```
|
||||
|
||||
**Output of `trivy -v`:**
|
||||
|
||||
```
|
||||
(paste your output here)
|
||||
```
|
||||
|
||||
**Additional details (base image name, container registry info...):**
|
||||
|
||||
250
README.md
250
README.md
@@ -48,6 +48,7 @@ See [Comparison with other scanners](#comparison-with-other-scanners) for detail
|
||||
- [Continuous Integration (CI)](#continuous-integration-ci)
|
||||
- [Travis CI](#travis-ci)
|
||||
- [Circle CI](#circle-ci)
|
||||
- [Authorization for Private Docker Registry](#authorization-for-private-docker-registry)
|
||||
- [Vulnerability Detection](#vulnerability-detection)
|
||||
- [OS Packages](#os-packages)
|
||||
- [Application Dependencies](#application-dependencies)
|
||||
@@ -55,9 +56,9 @@ See [Comparison with other scanners](#comparison-with-other-scanners) for detail
|
||||
- [Comparison with other scanners](#comparison-with-other-scanners)
|
||||
- [Overview](#overview)
|
||||
- [Accuracy](#accuracy)
|
||||
- [vs Clair, Quay](#vs-clair)
|
||||
- [vs Clair](#vs-clair)
|
||||
- [vs Anchore Engine](#vs-anchore-engine)
|
||||
- [vs Docker Hub, GCR](#vs-quay-docker-hub-gcr)
|
||||
- [vs Quay, Docker Hub, GCR](#vs-quay-docker-hub-gcr)
|
||||
- [Q&A](#qa)
|
||||
- [Homebrew](#homebrew)
|
||||
- [Others](#others)
|
||||
@@ -75,7 +76,7 @@ See [here](#continuous-integration-ci) for details.
|
||||
|
||||
- Detect comprehensive vulnerabilities
|
||||
- OS packages (Alpine, **Red Hat Universal Base Image**, Red Hat Enterprise Linux, CentOS, Debian and Ubuntu)
|
||||
- **Application dependencies** (Bundler, Composer, Pipenv, npm, yarn and Cargo)
|
||||
- **Application dependencies** (Bundler, Composer, Pipenv, Poetry, npm, yarn and Cargo)
|
||||
- Simple
|
||||
- Specify only an image name
|
||||
- See [Quick Start](#quick-start) and [Examples](#examples)
|
||||
@@ -109,7 +110,7 @@ $ sudo yum -y install trivy
|
||||
or
|
||||
|
||||
```
|
||||
$ rpm -ivh https://github.com/knqyf263/trivy/releases/download/v0.0.13/trivy_0.0.13_Linux-64bit.rpm
|
||||
$ rpm -ivh https://github.com/knqyf263/trivy/releases/download/v0.0.15/trivy_0.0.15_Linux-64bit.rpm
|
||||
```
|
||||
|
||||
## Debian/Ubuntu
|
||||
@@ -130,22 +131,21 @@ or
|
||||
|
||||
```
|
||||
$ sudo apt-get install rpm
|
||||
$ wget https://github.com/knqyf263/trivy/releases/download/v0.0.13/trivy_0.0.13_Linux-64bit.deb
|
||||
$ sudo dpkg -i trivy_0.0.13_Linux-64bit.deb
|
||||
$ wget https://github.com/knqyf263/trivy/releases/download/v0.0.15/trivy_0.0.15_Linux-64bit.deb
|
||||
$ sudo dpkg -i trivy_0.0.15_Linux-64bit.deb
|
||||
```
|
||||
|
||||
## Mac OS X / Homebrew
|
||||
|
||||
You can use homebrew on OS X.
|
||||
You can use homebrew on Mac OS.
|
||||
|
||||
```
|
||||
$ brew tap knqyf263/trivy
|
||||
$ brew install knqyf263/trivy/trivy
|
||||
```
|
||||
|
||||
## Binary (Including Windows)
|
||||
|
||||
Go to [the releases page](https://github.com/knqyf263/trivy/releases), find the version you want, and download the zip file. Unpack the zip file, and put the binary to somewhere you want (on UNIX-y systems, /usr/local/bin or the like). Make sure it has execution bits turned on.
|
||||
Get the latest version from [this page](https://github.com/knqyf263/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.
|
||||
|
||||
You need to install `rpm` command for scanning RHEL/CentOS.
|
||||
|
||||
@@ -197,21 +197,24 @@ Total: 1 (UNKNOWN: 0, LOW: 0, MEDIUM: 1, HIGH: 0, CRITICAL: 0)
|
||||
Replace [YOUR_CACHE_DIR] with the cache directory on your machine.
|
||||
|
||||
```
|
||||
$ docker run -v [YOUR_CACHE_DIR]:/root/.cache/ knqyf263/trivy [YOUR_IMAGE_NAME]
|
||||
$ docker run --rm -v [YOUR_CACHE_DIR]:/root/.cache/ knqyf263/trivy [YOUR_IMAGE_NAME]
|
||||
```
|
||||
|
||||
Example for macOS:
|
||||
|
||||
```
|
||||
$ docker run -v $HOME/Library/Caches:/root/.cache/ knqyf263/trivy python:3.4-alpine
|
||||
$ docker run --rm -v $HOME/Library/Caches:/root/.cache/ knqyf263/trivy python:3.4-alpine
|
||||
```
|
||||
|
||||
If you would like to scan the image on your host machine, you need to mount `docker.sock`.
|
||||
|
||||
```
|
||||
$ docker run -v /var/run/docker.sock:/var/run/docker.sock -v $HOME/Library/Caches:/root/.cache/ knqyf263/trivy python:3.4-alpine
|
||||
$ docker run --rm -v /var/run/docker.sock:/var/run/docker.sock \
|
||||
-v $HOME/Library/Caches:/root/.cache/ knqyf263/trivy python:3.4-alpine
|
||||
```
|
||||
|
||||
Please re-pull latest `knqyf263/trivy` if an error occured.
|
||||
|
||||
<details>
|
||||
<summary>Result</summary>
|
||||
|
||||
@@ -516,6 +519,115 @@ $ trivy -f json -o results.json golang:1.12-alpine
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>JSON</summary>
|
||||
|
||||
```
|
||||
[
|
||||
{
|
||||
"Target": "php-app/composer.lock",
|
||||
"Vulnerabilities": null
|
||||
},
|
||||
{
|
||||
"Target": "node-app/package-lock.json",
|
||||
"Vulnerabilities": [
|
||||
{
|
||||
"VulnerabilityID": "CVE-2018-16487",
|
||||
"PkgName": "lodash",
|
||||
"InstalledVersion": "4.17.4",
|
||||
"FixedVersion": "\u003e=4.17.11",
|
||||
"Title": "lodash: Prototype pollution in utilities function",
|
||||
"Description": "A prototype pollution vulnerability was found in lodash \u003c4.17.11 where the functions merge, mergeWith, and defaultsDeep can be tricked into adding or modifying properties of Object.prototype.",
|
||||
"Severity": "HIGH",
|
||||
"References": [
|
||||
"https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-16487",
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Target": "trivy-ci-test (alpine 3.7.1)",
|
||||
"Vulnerabilities": [
|
||||
{
|
||||
"VulnerabilityID": "CVE-2018-16840",
|
||||
"PkgName": "curl",
|
||||
"InstalledVersion": "7.61.0-r0",
|
||||
"FixedVersion": "7.61.1-r1",
|
||||
"Title": "curl: Use-after-free when closing \"easy\" handle in Curl_close()",
|
||||
"Description": "A heap use-after-free flaw was found in curl versions from 7.59.0 through 7.61.1 in the code related to closing an easy handle. ",
|
||||
"Severity": "HIGH",
|
||||
"References": [
|
||||
"https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-16840",
|
||||
]
|
||||
},
|
||||
{
|
||||
"VulnerabilityID": "CVE-2019-3822",
|
||||
"PkgName": "curl",
|
||||
"InstalledVersion": "7.61.0-r0",
|
||||
"FixedVersion": "7.61.1-r2",
|
||||
"Title": "curl: NTLMv2 type-3 header stack buffer overflow",
|
||||
"Description": "libcurl versions from 7.36.0 to before 7.64.0 are vulnerable to a stack-based buffer overflow. ",
|
||||
"Severity": "HIGH",
|
||||
"References": [
|
||||
"https://curl.haxx.se/docs/CVE-2019-3822.html",
|
||||
"https://lists.apache.org/thread.html/8338a0f605bdbb3a6098bb76f666a95fc2b2f53f37fa1ecc89f1146f@%3Cdevnull.infra.apache.org%3E"
|
||||
]
|
||||
},
|
||||
{
|
||||
"VulnerabilityID": "CVE-2018-16839",
|
||||
"PkgName": "curl",
|
||||
"InstalledVersion": "7.61.0-r0",
|
||||
"FixedVersion": "7.61.1-r1",
|
||||
"Title": "curl: Integer overflow leading to heap-based buffer overflow in Curl_sasl_create_plain_message()",
|
||||
"Description": "Curl versions 7.33.0 through 7.61.1 are vulnerable to a buffer overrun in the SASL authentication code that may lead to denial of service.",
|
||||
"Severity": "HIGH",
|
||||
"References": [
|
||||
"https://github.com/curl/curl/commit/f3a24d7916b9173c69a3e0ee790102993833d6c5",
|
||||
]
|
||||
},
|
||||
{
|
||||
"VulnerabilityID": "CVE-2018-19486",
|
||||
"PkgName": "git",
|
||||
"InstalledVersion": "2.15.2-r0",
|
||||
"FixedVersion": "2.15.3-r0",
|
||||
"Title": "git: Improper handling of PATH allows for commands to be executed from the current directory",
|
||||
"Description": "Git before 2.19.2 on Linux and UNIX executes commands from the current working directory (as if '.' were at the end of $PATH) in certain cases involving the run_command() API and run-command.c, because there was a dangerous change from execvp to execv during 2017.",
|
||||
"Severity": "HIGH",
|
||||
"References": [
|
||||
"https://usn.ubuntu.com/3829-1/",
|
||||
]
|
||||
},
|
||||
{
|
||||
"VulnerabilityID": "CVE-2018-17456",
|
||||
"PkgName": "git",
|
||||
"InstalledVersion": "2.15.2-r0",
|
||||
"FixedVersion": "2.15.3-r0",
|
||||
"Title": "git: arbitrary code execution via .gitmodules",
|
||||
"Description": "Git before 2.14.5, 2.15.x before 2.15.3, 2.16.x before 2.16.5, 2.17.x before 2.17.2, 2.18.x before 2.18.1, and 2.19.x before 2.19.1 allows remote code execution during processing of a recursive \"git clone\" of a superproject if a .gitmodules file has a URL field beginning with a '-' character.",
|
||||
"Severity": "HIGH",
|
||||
"References": [
|
||||
"http://www.securitytracker.com/id/1041811",
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Target": "python-app/Pipfile.lock",
|
||||
"Vulnerabilities": null
|
||||
},
|
||||
{
|
||||
"Target": "ruby-app/Gemfile.lock",
|
||||
"Vulnerabilities": null
|
||||
},
|
||||
{
|
||||
"Target": "rust-app/Cargo.lock",
|
||||
"Vulnerabilities": null
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
### Filter the vulnerabilities by severities
|
||||
|
||||
```
|
||||
@@ -607,6 +719,37 @@ Total: 1 (UNKNOWN: 0, LOW: 0, MEDIUM: 1, HIGH: 0, CRITICAL: 0)
|
||||
|
||||
</details>
|
||||
|
||||
### Update only you are specified distributions
|
||||
|
||||
By default, `Trivy` always updates vulnerability database of all distribution. Use the `--only-update` option if you want to update only specified distributions.
|
||||
|
||||
```
|
||||
$ trivy --only-update alpine,debian python:3.4-alpine3.9
|
||||
$ trivy --only-update alpine python:3.4-alpine3.9
|
||||
```
|
||||
|
||||
<details>
|
||||
<summary>Result</summary>
|
||||
|
||||
```
|
||||
2019-05-21T19:37:06.301+0900 INFO Updating vulnerability database...
|
||||
2019-05-21T19:37:07.793+0900 INFO Updating alpine data...
|
||||
2019-05-21T19:37:08.127+0900 INFO Detecting Alpine vulnerabilities...
|
||||
|
||||
python:3.4-alpine3.9 (alpine 3.9.2)
|
||||
===================================
|
||||
Total: 1 (UNKNOWN: 0, LOW: 0, MEDIUM: 1, HIGH: 0, CRITICAL: 0)
|
||||
|
||||
+---------+------------------+----------+-------------------+---------------+--------------------------------+
|
||||
| LIBRARY | VULNERABILITY ID | SEVERITY | INSTALLED VERSION | FIXED VERSION | TITLE |
|
||||
+---------+------------------+----------+-------------------+---------------+--------------------------------+
|
||||
| openssl | CVE-2019-1543 | MEDIUM | 1.1.1a-r1 | 1.1.1b-r1 | openssl: ChaCha20-Poly1305 |
|
||||
| | | | | | with long nonces |
|
||||
+---------+------------------+----------+-------------------+---------------+--------------------------------+
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
### Ignore unfixed vulnerabilities
|
||||
|
||||
By default, `Trivy` also detects unpatched/unfixed vulnerabilities. This means you can't fix these vulnerabilities even if you update all packages.
|
||||
@@ -790,11 +933,12 @@ env:
|
||||
|
||||
before_install:
|
||||
- docker build -t trivy-ci-test:${COMMIT} .
|
||||
- wget https://github.com/knqyf263/trivy/releases/download/v0.0.13/trivy_0.0.13_Linux-64bit.tar.gz
|
||||
- tar zxvf trivy_0.0.13_Linux-64bit.tar.gz
|
||||
- export VERSION=$(curl --silent "https://api.github.com/repos/knqyf263/trivy/releases/latest" | grep '"tag_name":' | sed -E 's/.*"v([^"]+)".*/\1/')
|
||||
- wget https://github.com/knqyf263/trivy/releases/download/v${VERSION}/trivy_${VERSION}_Linux-64bit.tar.gz
|
||||
- tar zxvf trivy_${VERSION}_Linux-64bit.tar.gz
|
||||
script:
|
||||
- ./trivy --exit-code 0 --severity HIGH --quiet trivy-ci-test:${COMMIT}
|
||||
- ./trivy --exit-code 1 --severity CRITICAL --quiet trivy-ci-test:${COMMIT}
|
||||
- ./trivy --exit-code 0 --severity HIGH --quiet --auto-refresh trivy-ci-test:${COMMIT}
|
||||
- ./trivy --exit-code 1 --severity CRITICAL --quiet --auto-refresh trivy-ci-test:${COMMIT}
|
||||
cache:
|
||||
directories:
|
||||
- $HOME/.cache/trivy
|
||||
@@ -806,6 +950,7 @@ Repository: https://github.com/knqyf263/trivy-ci-test
|
||||
## CircleCI
|
||||
|
||||
```
|
||||
$ cat .circleci/config.yml
|
||||
jobs:
|
||||
build:
|
||||
docker:
|
||||
@@ -821,12 +966,19 @@ jobs:
|
||||
- run:
|
||||
name: Install trivy
|
||||
command: |
|
||||
wget https://github.com/knqyf263/trivy/releases/download/v0.0.13/trivy_0.0.13_Linux-64bit.tar.gz
|
||||
tar zxvf trivy_0.0.13_Linux-64bit.tar.gz
|
||||
apk add --update curl
|
||||
VERSION=$(
|
||||
curl --silent "https://api.github.com/repos/knqyf263/trivy/releases/latest" | \
|
||||
grep '"tag_name":' | \
|
||||
sed -E 's/.*"v([^"]+)".*/\1/'
|
||||
)
|
||||
|
||||
wget https://github.com/knqyf263/trivy/releases/download/v${VERSION}/trivy_${VERSION}_Linux-64bit.tar.gz
|
||||
tar zxvf trivy_${VERSION}_Linux-64bit.tar.gz
|
||||
mv trivy /usr/local/bin
|
||||
- run:
|
||||
name: Scan the local image with trivy
|
||||
command: trivy --exit-code 0 --quiet trivy-ci-test:${CIRCLE_SHA1}
|
||||
command: trivy --exit-code 0 --quiet --auto-refresh trivy-ci-test:${CIRCLE_SHA1}
|
||||
- save_cache:
|
||||
key: vulnerability-db
|
||||
paths:
|
||||
@@ -841,6 +993,52 @@ workflows:
|
||||
Example: https://circleci.com/gh/knqyf263/trivy-ci-test
|
||||
Repository: https://github.com/knqyf263/trivy-ci-test
|
||||
|
||||
## Authorization for Private Docker Registry
|
||||
|
||||
Trivy can download images from private registry, without installing `Docker` and any 3rd party tools.
|
||||
That's because it's easy to run in a CI process.
|
||||
|
||||
All you have to do is install `Trivy` and set ENV vars.
|
||||
But, I can't recommend using ENV vars in your local machine to you.
|
||||
|
||||
### Docker Hub
|
||||
|
||||
Docker Hub needs `TRIVY_AUTH_URL`, `TRIVY_USERNAME` and `TRIVY_PASSWORD`.
|
||||
You don't need to set ENV vars when download from public repository.
|
||||
|
||||
```bash
|
||||
export TRIVY_AUTH_URL=https://registry.hub.docker.com
|
||||
export TRIVY_USERNAME={DOCKERHUB_USERNAME}
|
||||
export TRIVY_PASSWORD={DOCKERHUB_PASSWORD}
|
||||
```
|
||||
|
||||
### Amazon ECR (Elastic Container Registry)
|
||||
|
||||
Trivy uses AWS SDK. You don't need to install `aws` CLI tool.
|
||||
You can use [AWS CLI's ENV Vars](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-envvars.html).
|
||||
|
||||
### GCR (Google Container Registry)
|
||||
|
||||
Trivy uses Google Cloud SDK. You don't need to install `gcloud` command.
|
||||
|
||||
If you want to use target project's repository, you can settle via `GOOGLE_APPLICATION_CREDENTIAL`.
|
||||
```bash
|
||||
# must set TRIVY_USERNAME empty char
|
||||
export GOOGLE_APPLICATION_CREDENTIALS=/path/to/credential.json
|
||||
```
|
||||
|
||||
### Self Hosted Registry (BasicAuth)
|
||||
|
||||
BasicAuth server needs `TRIVY_USERNAME` and `TRIVY_PASSWORD`.
|
||||
|
||||
```bash
|
||||
export TRIVY_USERNAME={USERNAME}
|
||||
export TRIVY_PASSWORD={PASSWORD}
|
||||
|
||||
# if you want to use 80 port, use NonSSL
|
||||
export TRIVY_NON_SSL=true
|
||||
```
|
||||
|
||||
# Vulnerability Detection
|
||||
|
||||
## OS Packages
|
||||
@@ -862,6 +1060,7 @@ The unfixed/unfixable vulnerabilities mean that the patch has not yet been provi
|
||||
|
||||
- Gemfile.lock
|
||||
- Pipfile.lock
|
||||
- poetry.lock
|
||||
- composer.lock
|
||||
- package-lock.json
|
||||
- yarn.lock
|
||||
@@ -879,7 +1078,7 @@ NAME:
|
||||
USAGE:
|
||||
main [options] image_name
|
||||
VERSION:
|
||||
0.0.13
|
||||
0.0.15
|
||||
OPTIONS:
|
||||
--format value, -f value format (table, json) (default: "table")
|
||||
--input value, -i value input file path instead of image name
|
||||
@@ -892,6 +1091,7 @@ OPTIONS:
|
||||
--quiet, -q suppress progress bar
|
||||
--ignore-unfixed display only fixed vulnerabilities
|
||||
--refresh refresh DB (usually used after version update of trivy)
|
||||
--auto-refresh refresh DB automatically when updating version of trivy
|
||||
--debug, -d debug mode
|
||||
--help, -h show help
|
||||
--version, -v print the version
|
||||
@@ -932,7 +1132,7 @@ The results of [composer:1.7.2](https://hub.docker.com/_/composer?tab=tags) usin
|
||||
|
||||
<img src="imgs/alpine.png" width="500">
|
||||
|
||||
`Trivy` has high accuracy and high precision, while GCR did not detect any vulnerability. Althogh Docker Hub has many True Positive, it also has many False Positive.
|
||||
`Trivy` has high accuracy and high precision, while GCR did not detect any vulnerability. Although Docker Hub has many True Positive, it also has many False Positive.
|
||||
|
||||
### RHEL/CentOS
|
||||
|
||||
@@ -958,8 +1158,8 @@ In the case of other OS, the result is similar to other container scanners.
|
||||
However, the purpose of this database is to make it possible to know what packages has backported fixes.
|
||||
As README says, it is not a complete database of all security issues in Alpine.
|
||||
|
||||
`Trivy` collects vulnerability information in Alpine Linux from [Alpine LInux Redmine](https://bugs.alpinelinux.org/projects/alpine/issues).
|
||||
Then, those vulnerabilities will be saved on [vuln-list](https://github.com/knqyf263/vuln-list/tree/master/alpine)
|
||||
`Trivy` collects vulnerability information in Alpine Linux from [Alpine Linux Redmine](https://bugs.alpinelinux.org/projects/alpine/issues).
|
||||
Then, those vulnerabilities will be saved on [vuln-list](https://github.com/knqyf263/vuln-list/tree/master/alpine).
|
||||
|
||||
`alpine-secdb` has 6959 vulnerabilities (as of 2019/05/12).
|
||||
`vuln-list` has 11101 vulnerabilities related with Alpine Linux (as of 2019/05/12).
|
||||
@@ -967,7 +1167,7 @@ There is a difference in detection accuracy because the number of vulnerabilitie
|
||||
|
||||
In addition, `Trivy` analyzes the middle layer as well and find out which version of the library was used for static linking.
|
||||
|
||||
`Clair` can not handle the following cases because it analyzes the image after applying the all layers.
|
||||
`Clair` can not handle the following cases because it analyzes the image after applying all layers.
|
||||
|
||||
```
|
||||
RUN apk add --no-cache sqlite-dev \
|
||||
@@ -991,7 +1191,7 @@ Also, `Anchore Engine` needs some steps to start scanning.
|
||||
|
||||
## vs Quay, Docker Hub, GCR
|
||||
|
||||
As `Quay` seems to use `Clair` internally, it has the same accuracy with `Clair`. `Docker Hub` can scan only official images. `GCR` hardly detects vulnerability on Alpine Linux. Also, it is locked to a specific registry.
|
||||
As `Quay` seems to use `Clair` internally, it has the same accuracy than `Clair`. `Docker Hub` can scan only official images. `GCR` hardly detects vulnerabilities on Alpine Linux. Also, it is locked to a specific registry.
|
||||
|
||||
`Trivy` can be used regardless of the registry. In addition, it is easy to be integrated with CI/CD services.
|
||||
|
||||
|
||||
@@ -69,6 +69,10 @@ OPTIONS:
|
||||
Name: "skip-update",
|
||||
Usage: "skip db update",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "only-update",
|
||||
Usage: "update db only specified distribution (comma separated)",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "reset",
|
||||
Usage: "remove all caches and database",
|
||||
@@ -89,24 +93,26 @@ OPTIONS:
|
||||
Name: "refresh",
|
||||
Usage: "refresh DB (usually used after version update of trivy)",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "auto-refresh",
|
||||
Usage: "refresh DB automatically when updating version of trivy",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "debug, d",
|
||||
Usage: "debug mode",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "cache-dir",
|
||||
Name: "cache-dir",
|
||||
Usage: "cache directory",
|
||||
},
|
||||
}
|
||||
|
||||
app.Action = func(c *cli.Context) error {
|
||||
return pkg.Run(c)
|
||||
}
|
||||
app.Action = pkg.Run
|
||||
|
||||
err := app.Run(os.Args)
|
||||
if err != nil {
|
||||
if log.Logger != nil {
|
||||
log.Logger.Fatal(err)
|
||||
log.Fatal(err)
|
||||
}
|
||||
l.Fatal(err)
|
||||
}
|
||||
|
||||
6
go.mod
6
go.mod
@@ -5,22 +5,22 @@ go 1.12
|
||||
require (
|
||||
github.com/BurntSushi/toml v0.3.1
|
||||
github.com/briandowns/spinner v0.0.0-20190319032542-ac46072a5a91
|
||||
github.com/caarlos0/env/v6 v6.0.0
|
||||
github.com/emirpasic/gods v1.12.0 // indirect
|
||||
github.com/etcd-io/bbolt v1.3.2
|
||||
github.com/fatih/color v1.7.0
|
||||
github.com/genuinetools/reg v0.16.0
|
||||
github.com/gliderlabs/ssh v0.1.3 // indirect
|
||||
github.com/golang/protobuf v1.3.1 // indirect
|
||||
github.com/knqyf263/fanal v0.0.0-20190517090627-af48380166ef
|
||||
github.com/knqyf263/fanal v0.0.0-20190521154631-a2dde7e171c6
|
||||
github.com/knqyf263/go-deb-version v0.0.0-20190517075300-09fca494f03d
|
||||
github.com/knqyf263/go-dep-parser v0.0.0-20190515172517-b8305876c9c2
|
||||
github.com/knqyf263/go-dep-parser v0.0.0-20190521150559-1ef8521d17a0
|
||||
github.com/knqyf263/go-rpm-version v0.0.0-20170716094938-74609b86c936
|
||||
github.com/knqyf263/go-version v1.1.1
|
||||
github.com/mattn/go-colorable v0.1.1 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.4 // indirect
|
||||
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||
github.com/olekukonko/tablewriter v0.0.1
|
||||
github.com/stretchr/testify v1.3.0 // indirect
|
||||
github.com/urfave/cli v1.20.0
|
||||
github.com/xanzy/ssh-agent v0.2.1 // indirect
|
||||
go.etcd.io/bbolt v1.3.2 // indirect
|
||||
|
||||
10
go.sum
10
go.sum
@@ -27,6 +27,8 @@ github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLM
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/briandowns/spinner v0.0.0-20190319032542-ac46072a5a91 h1:GMmnK0dvr0Sf0gx3DvTbln0c8DE07B7sPVD9dgHOqo4=
|
||||
github.com/briandowns/spinner v0.0.0-20190319032542-ac46072a5a91/go.mod h1:hw/JEQBIE+c/BLI4aKM8UU8v+ZqrD3h7HC27kKt8JQU=
|
||||
github.com/caarlos0/env/v6 v6.0.0 h1:NZt6FAoB8ieKO5lEwRdwCzYxWFx7ZYF2R7UcoyaWtyc=
|
||||
github.com/caarlos0/env/v6 v6.0.0/go.mod h1:+wdyOmtjoZIW2GJOc2OYa5NoOFuWD/bIpWqm30NgtRk=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/containerd/continuity v0.0.0-20180921161001-7f53d412b9eb h1:qSMRxG547z/BgQmyVyADxaMADQXVAD9uleP2sQeClbo=
|
||||
github.com/containerd/continuity v0.0.0-20180921161001-7f53d412b9eb/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
|
||||
@@ -114,12 +116,12 @@ github.com/kevinburke/ssh_config v0.0.0-20180830205328-81db2a75821e h1:RgQk53JHp
|
||||
github.com/kevinburke/ssh_config v0.0.0-20180830205328-81db2a75821e/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
|
||||
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/fanal v0.0.0-20190517090627-af48380166ef h1:mxKy5exy/vKIhV86Ar7E1AzNS/NCjfyrcRKcoblgZd8=
|
||||
github.com/knqyf263/fanal v0.0.0-20190517090627-af48380166ef/go.mod h1:bycEQTZsPG1IOBXWwTNxruhtNN0KYDgux0CMgu9UGoQ=
|
||||
github.com/knqyf263/fanal v0.0.0-20190521154631-a2dde7e171c6 h1:qfIU7I6yo7zWpqqj0Zxt3iWY51N5D3BFUXdMjKjrAXU=
|
||||
github.com/knqyf263/fanal v0.0.0-20190521154631-a2dde7e171c6/go.mod h1:guPOH3Sfj5M4j/LvCOoWmuYCXnjReDIwJO+S89Fje1E=
|
||||
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-dep-parser v0.0.0-20190515172517-b8305876c9c2 h1:bQGj8WH6X4czC2FlkgUKKFq2xPnJovzf61T4Yl9sVZs=
|
||||
github.com/knqyf263/go-dep-parser v0.0.0-20190515172517-b8305876c9c2/go.mod h1:gSiqSkOFPstUZu/qZ4wnNJS69PtQQnPl397vxKHJ5mQ=
|
||||
github.com/knqyf263/go-dep-parser v0.0.0-20190521150559-1ef8521d17a0 h1:DOQ2UbTciy48dV9vpZ25BOiShrWIWZwBdMOy7SD1Wow=
|
||||
github.com/knqyf263/go-dep-parser v0.0.0-20190521150559-1ef8521d17a0/go.mod h1:gSiqSkOFPstUZu/qZ4wnNJS69PtQQnPl397vxKHJ5mQ=
|
||||
github.com/knqyf263/go-rpm-version v0.0.0-20170716094938-74609b86c936 h1:HDjRqotkViMNcGMGicb7cgxklx8OwnjtCBmyWEqrRvM=
|
||||
github.com/knqyf263/go-rpm-version v0.0.0-20170716094938-74609b86c936/go.mod h1:i4sF0l1fFnY1aiw08QQSwVAFxHEm311Me3WsU/X7nL0=
|
||||
github.com/knqyf263/go-rpmdb v0.0.0-20190501070121-10a1c42a10dc/go.mod h1:MrSSvdMpTSymaQWk1yFr9sxFSyQmKMj6jkbvGrchBV8=
|
||||
|
||||
21
pkg/db/db.go
21
pkg/db/db.go
@@ -15,7 +15,7 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
db *bolt.DB
|
||||
db *bolt.DB
|
||||
)
|
||||
|
||||
func Init() (err error) {
|
||||
@@ -33,11 +33,26 @@ func Init() (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
func Close() error {
|
||||
if err := db.Close(); err != nil {
|
||||
return xerrors.Errorf("failed to close DB: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func Reset() error {
|
||||
if err := Close(); err != nil {
|
||||
return xerrors.Errorf("failed to reset DB: %w", err)
|
||||
}
|
||||
|
||||
dbDir := filepath.Join(utils.CacheDir(), "db")
|
||||
if err := os.RemoveAll(dbDir); err != nil {
|
||||
return xerrors.Errorf("failed to reset DB: %w", err)
|
||||
}
|
||||
|
||||
if err := Init(); err != nil {
|
||||
return xerrors.Errorf("failed to reset DB: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -90,9 +105,7 @@ func Put(root *bolt.Bucket, nestedBucket, key string, value interface{}) error {
|
||||
return nested.Put([]byte(key), v)
|
||||
}
|
||||
func BatchUpdate(fn func(tx *bolt.Tx) error) error {
|
||||
err := db.Batch(func(tx *bolt.Tx) error {
|
||||
return fn(tx)
|
||||
})
|
||||
err := db.Batch(fn)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("error in batch update: %w", err)
|
||||
}
|
||||
|
||||
@@ -92,7 +92,7 @@ func clone(url, repoPath string) error {
|
||||
}
|
||||
|
||||
func cloneByOSCommand(url, repoPath string) error {
|
||||
commandAndArgs := []string{"clone", url, repoPath}
|
||||
commandAndArgs := []string{"clone", "--depth=1", url, repoPath}
|
||||
_, err := utils.Exec("git", commandAndArgs)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("error in git clone: %w", err)
|
||||
|
||||
@@ -6,9 +6,13 @@ import (
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
var Logger *zap.SugaredLogger
|
||||
var (
|
||||
Logger *zap.SugaredLogger
|
||||
debugOption bool
|
||||
)
|
||||
|
||||
func InitLogger(debug bool) (err error) {
|
||||
debugOption = debug
|
||||
Logger, err = newLogger(debug)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("error in new logger: %w", err)
|
||||
@@ -29,8 +33,8 @@ func newLogger(debug bool) (*zap.SugaredLogger, error) {
|
||||
Level: level,
|
||||
Encoding: "console",
|
||||
Development: debug,
|
||||
DisableStacktrace: !debug,
|
||||
DisableCaller: !debug,
|
||||
DisableStacktrace: true,
|
||||
DisableCaller: true,
|
||||
EncoderConfig: zapcore.EncoderConfig{
|
||||
TimeKey: "Time",
|
||||
LevelKey: "Level",
|
||||
@@ -53,3 +57,10 @@ func newLogger(debug bool) (*zap.SugaredLogger, error) {
|
||||
|
||||
return logger.Sugar(), nil
|
||||
}
|
||||
|
||||
func Fatal(err error) {
|
||||
if debugOption {
|
||||
Logger.Fatalf("%+v", err)
|
||||
}
|
||||
Logger.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -17,8 +17,8 @@ import (
|
||||
type Results []Result
|
||||
|
||||
type Result struct {
|
||||
FileName string `json:"file"`
|
||||
Vulnerabilities []vulnerability.DetectedVulnerability
|
||||
FileName string `json:"Target"`
|
||||
Vulnerabilities []vulnerability.DetectedVulnerability `json:"Vulnerabilities"`
|
||||
}
|
||||
|
||||
type Writer interface {
|
||||
@@ -84,11 +84,7 @@ type JsonWriter struct {
|
||||
}
|
||||
|
||||
func (jw JsonWriter) Write(results Results) error {
|
||||
out := map[string][]vulnerability.DetectedVulnerability{}
|
||||
for _, result := range results {
|
||||
out[result.FileName] = result.Vulnerabilities
|
||||
}
|
||||
output, err := json.MarshalIndent(out, "", " ")
|
||||
output, err := json.MarshalIndent(results, "", " ")
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to marshal json: %w", err)
|
||||
}
|
||||
|
||||
78
pkg/run.go
78
pkg/run.go
@@ -7,25 +7,21 @@ import (
|
||||
|
||||
"github.com/genuinetools/reg/registry"
|
||||
"github.com/knqyf263/fanal/cache"
|
||||
|
||||
"github.com/knqyf263/trivy/pkg/utils"
|
||||
|
||||
"github.com/knqyf263/trivy/pkg/vulnsrc/vulnerability"
|
||||
|
||||
"github.com/knqyf263/trivy/pkg/report"
|
||||
"github.com/knqyf263/trivy/pkg/scanner"
|
||||
"github.com/knqyf263/trivy/pkg/vulnsrc"
|
||||
|
||||
"github.com/urfave/cli"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/knqyf263/trivy/pkg/db"
|
||||
"github.com/knqyf263/trivy/pkg/log"
|
||||
"github.com/knqyf263/trivy/pkg/report"
|
||||
"github.com/knqyf263/trivy/pkg/scanner"
|
||||
"github.com/knqyf263/trivy/pkg/utils"
|
||||
"github.com/knqyf263/trivy/pkg/vulnsrc"
|
||||
"github.com/knqyf263/trivy/pkg/vulnsrc/vulnerability"
|
||||
"github.com/urfave/cli"
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
func Run(c *cli.Context) (err error) {
|
||||
cliVersion := c.App.Version
|
||||
|
||||
utils.Quiet = c.Bool("quiet")
|
||||
debug := c.Bool("debug")
|
||||
if err = log.InitLogger(debug); err != nil {
|
||||
l.Fatal(err)
|
||||
@@ -59,13 +55,6 @@ func Run(c *cli.Context) (err error) {
|
||||
}
|
||||
|
||||
refresh := c.Bool("refresh")
|
||||
if refresh {
|
||||
log.Logger.Info("Refreshing DB...")
|
||||
if err = db.Reset(); err != nil {
|
||||
return xerrors.Errorf("error in refresh DB: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
args := c.Args()
|
||||
var noTarget bool
|
||||
filePath := c.String("input")
|
||||
@@ -77,19 +66,54 @@ func Run(c *cli.Context) (err error) {
|
||||
}
|
||||
}
|
||||
|
||||
autoRefresh := c.Bool("auto-refresh")
|
||||
skipUpdate := c.Bool("skip-update")
|
||||
onlyUpdate := c.String("only-update")
|
||||
if refresh || autoRefresh {
|
||||
if skipUpdate {
|
||||
return xerrors.New("The --skip-update option can not be specified with the --refresh or --auto-refresh option")
|
||||
}
|
||||
if onlyUpdate != "" {
|
||||
return xerrors.New("The --only-update option can not be specified with the --refresh or --auto-refresh option")
|
||||
}
|
||||
}
|
||||
if skipUpdate && onlyUpdate != "" {
|
||||
return xerrors.New("The --skip-update and --only-update option can not be specified both")
|
||||
}
|
||||
|
||||
if err = db.Init(); err != nil {
|
||||
return xerrors.Errorf("error in vulnerability DB initialize: %w", err)
|
||||
}
|
||||
|
||||
needRefresh := false
|
||||
dbVersion := db.GetVersion()
|
||||
if dbVersion != "" && dbVersion != cliVersion {
|
||||
log.Logger.Fatal("Detected version update of trivy. Please try again with --refresh option")
|
||||
if !refresh && !autoRefresh {
|
||||
return xerrors.New("Detected version update of trivy. Please try again with --refresh or --auto-refresh option")
|
||||
}
|
||||
needRefresh = true
|
||||
}
|
||||
|
||||
if !c.Bool("skip-update") {
|
||||
if err = vulnsrc.Update(); err != nil {
|
||||
if refresh || needRefresh {
|
||||
log.Logger.Info("Refreshing DB...")
|
||||
if err = db.Reset(); err != nil {
|
||||
return xerrors.Errorf("error in refresh DB: %w", err)
|
||||
}
|
||||
}
|
||||
// this condition is already validated by skipUpdate && onlyUpdate != ""
|
||||
if onlyUpdate != "" {
|
||||
log.Logger.Warn("The --update-only option may cause the vulnerability details such as severity and title not to be displayed")
|
||||
if err = vulnsrc.Update(strings.Split(onlyUpdate, ",")); err != nil {
|
||||
return xerrors.Errorf("error in vulnerability DB update: %w", err)
|
||||
}
|
||||
} else {
|
||||
if err = vulnsrc.Update(vulnsrc.UpdateList); err != nil {
|
||||
return xerrors.Errorf("error in vulnerability DB update: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
if err = db.SetVersion(cliVersion); err != nil {
|
||||
return xerrors.Errorf("unexpected error: %w", err)
|
||||
}
|
||||
|
||||
// When specifying no image name and file name
|
||||
@@ -97,8 +121,6 @@ func Run(c *cli.Context) (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
utils.Quiet = c.Bool("quiet")
|
||||
|
||||
o := c.String("output")
|
||||
output := os.Stdout
|
||||
if o != "" {
|
||||
@@ -148,23 +170,19 @@ func Run(c *cli.Context) (err error) {
|
||||
}
|
||||
|
||||
var writer report.Writer
|
||||
switch c.String("format") {
|
||||
switch format := c.String("format"); format {
|
||||
case "table":
|
||||
writer = &report.TableWriter{Output: output}
|
||||
case "json":
|
||||
writer = &report.JsonWriter{Output: output}
|
||||
default:
|
||||
xerrors.New("unknown format")
|
||||
return xerrors.Errorf("unknown format: %v", format)
|
||||
}
|
||||
|
||||
if err = writer.Write(results); err != nil {
|
||||
return xerrors.Errorf("failed to write results: %w", err)
|
||||
}
|
||||
|
||||
if err = db.SetVersion(cliVersion); err != nil {
|
||||
return xerrors.Errorf("unexpected error: %w", err)
|
||||
}
|
||||
|
||||
exitCode := c.Int("exit-code")
|
||||
if exitCode != 0 {
|
||||
for _, result := range results {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package pipenv
|
||||
package python
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
@@ -1,4 +1,4 @@
|
||||
package pipenv
|
||||
package python
|
||||
|
||||
import (
|
||||
"os"
|
||||
@@ -9,21 +9,24 @@ import (
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/knqyf263/go-dep-parser/pkg/pipenv"
|
||||
"github.com/knqyf263/go-dep-parser/pkg/poetry"
|
||||
ptypes "github.com/knqyf263/go-dep-parser/pkg/types"
|
||||
"github.com/knqyf263/go-version"
|
||||
"github.com/knqyf263/trivy/pkg/scanner/utils"
|
||||
)
|
||||
|
||||
const (
|
||||
scannerType = "pipenv"
|
||||
ScannerTypePipenv = "pipenv"
|
||||
ScannerTypePoetry = "poetry"
|
||||
)
|
||||
|
||||
type Scanner struct {
|
||||
db AdvisoryDB
|
||||
db AdvisoryDB
|
||||
scannerType string
|
||||
}
|
||||
|
||||
func NewScanner() *Scanner {
|
||||
return &Scanner{}
|
||||
func NewScanner(scannerType string) *Scanner {
|
||||
return &Scanner{scannerType: scannerType}
|
||||
}
|
||||
|
||||
func (s *Scanner) Detect(pkgName string, pkgVer *version.Version) ([]vulnerability.DetectedVulnerability, error) {
|
||||
@@ -63,12 +66,28 @@ func createFixedVersions(specs []string) string {
|
||||
}
|
||||
|
||||
func (s *Scanner) ParseLockfile(f *os.File) ([]ptypes.Library, error) {
|
||||
if s.Type() == ScannerTypePipenv {
|
||||
return s.parsePipenv(f)
|
||||
}
|
||||
return s.parsePoetry(f)
|
||||
}
|
||||
|
||||
func (s *Scanner) parsePipenv(f *os.File) ([]ptypes.Library, error) {
|
||||
libs, err := pipenv.Parse(f)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("invalid Pipfile.lock format: %w", err)
|
||||
}
|
||||
return libs, nil
|
||||
}
|
||||
func (s *Scanner) Type() string {
|
||||
return scannerType
|
||||
|
||||
func (s *Scanner) parsePoetry(f *os.File) ([]ptypes.Library, error) {
|
||||
libs, err := poetry.Parse(f)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("invalid poetry.lock format: %w", err)
|
||||
}
|
||||
return libs, nil
|
||||
}
|
||||
|
||||
func (s *Scanner) Type() string {
|
||||
return s.scannerType
|
||||
}
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
_ "github.com/knqyf263/fanal/analyzer/library/composer"
|
||||
_ "github.com/knqyf263/fanal/analyzer/library/npm"
|
||||
_ "github.com/knqyf263/fanal/analyzer/library/pipenv"
|
||||
_ "github.com/knqyf263/fanal/analyzer/library/poetry"
|
||||
_ "github.com/knqyf263/fanal/analyzer/library/yarn"
|
||||
"github.com/knqyf263/fanal/extractor"
|
||||
ptypes "github.com/knqyf263/go-dep-parser/pkg/types"
|
||||
@@ -21,7 +22,7 @@ import (
|
||||
"github.com/knqyf263/trivy/pkg/scanner/library/cargo"
|
||||
"github.com/knqyf263/trivy/pkg/scanner/library/composer"
|
||||
"github.com/knqyf263/trivy/pkg/scanner/library/node"
|
||||
"github.com/knqyf263/trivy/pkg/scanner/library/pipenv"
|
||||
"github.com/knqyf263/trivy/pkg/scanner/library/python"
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
@@ -46,7 +47,9 @@ func NewScanner(filename string) Scanner {
|
||||
case "yarn.lock":
|
||||
scanner = node.NewScanner(node.ScannerTypeYarn)
|
||||
case "Pipfile.lock":
|
||||
scanner = pipenv.NewScanner()
|
||||
scanner = python.NewScanner(python.ScannerTypePipenv)
|
||||
case "poetry.lock":
|
||||
scanner = python.NewScanner(python.ScannerTypePoetry)
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
@@ -72,9 +75,7 @@ func Scan(files extractor.FileMap) (map[string][]vulnerability.DetectedVulnerabi
|
||||
return nil, xerrors.Errorf("failed to scan %s vulnerabilities: %w", scanner.Type(), err)
|
||||
}
|
||||
|
||||
if len(vulns) != 0 {
|
||||
vulnerabilities[string(path)] = vulns
|
||||
}
|
||||
vulnerabilities[string(path)] = vulns
|
||||
}
|
||||
return vulnerabilities, nil
|
||||
}
|
||||
|
||||
@@ -3,17 +3,13 @@ package alpine
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/knqyf263/trivy/pkg/vulnsrc/vulnerability"
|
||||
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
version "github.com/knqyf263/go-rpm-version"
|
||||
"github.com/knqyf263/trivy/pkg/scanner/utils"
|
||||
|
||||
"github.com/knqyf263/trivy/pkg/vulnsrc/alpine"
|
||||
|
||||
"github.com/knqyf263/fanal/analyzer"
|
||||
version "github.com/knqyf263/go-rpm-version"
|
||||
"github.com/knqyf263/trivy/pkg/log"
|
||||
"github.com/knqyf263/trivy/pkg/scanner/utils"
|
||||
"github.com/knqyf263/trivy/pkg/vulnsrc/alpine"
|
||||
"github.com/knqyf263/trivy/pkg/vulnsrc/vulnerability"
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
type Scanner struct{}
|
||||
|
||||
@@ -5,7 +5,9 @@ import (
|
||||
_ "github.com/knqyf263/fanal/analyzer/command/apk"
|
||||
fos "github.com/knqyf263/fanal/analyzer/os"
|
||||
_ "github.com/knqyf263/fanal/analyzer/os/alpine"
|
||||
_ "github.com/knqyf263/fanal/analyzer/os/amazonlinux"
|
||||
_ "github.com/knqyf263/fanal/analyzer/os/debianbase"
|
||||
_ "github.com/knqyf263/fanal/analyzer/os/opensuse"
|
||||
_ "github.com/knqyf263/fanal/analyzer/os/redhatbase"
|
||||
_ "github.com/knqyf263/fanal/analyzer/pkg/apk"
|
||||
_ "github.com/knqyf263/fanal/analyzer/pkg/dpkg"
|
||||
@@ -41,7 +43,8 @@ func Scan(files extractor.FileMap) (string, string, []vulnerability.DetectedVuln
|
||||
case fos.RedHat, fos.CentOS:
|
||||
s = redhat.NewScanner()
|
||||
default:
|
||||
return "", "", nil, xerrors.Errorf("unsupported os : %s", os.Family)
|
||||
log.Logger.Warnf("unsupported os : %s", os.Family)
|
||||
return "", "", nil, nil
|
||||
}
|
||||
pkgs, err := analyzer.GetPackages(files)
|
||||
if err != nil {
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"github.com/knqyf263/fanal/extractor"
|
||||
"github.com/knqyf263/trivy/pkg/scanner/library"
|
||||
"github.com/knqyf263/trivy/pkg/scanner/ospkg"
|
||||
"github.com/knqyf263/trivy/pkg/types"
|
||||
"github.com/knqyf263/trivy/pkg/vulnsrc/vulnerability"
|
||||
"golang.org/x/crypto/ssh/terminal"
|
||||
"golang.org/x/xerrors"
|
||||
@@ -24,7 +25,11 @@ func ScanImage(imageName, filePath string) (map[string][]vulnerability.DetectedV
|
||||
var files extractor.FileMap
|
||||
if imageName != "" {
|
||||
target = imageName
|
||||
files, err = analyzer.Analyze(ctx, imageName)
|
||||
dockerOption, err := types.GetDockerOption()
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to get docker option: %w", err)
|
||||
}
|
||||
files, err = analyzer.Analyze(ctx, imageName, dockerOption)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to analyze image: %w", err)
|
||||
}
|
||||
@@ -48,8 +53,10 @@ func ScanImage(imageName, filePath string) (map[string][]vulnerability.DetectedV
|
||||
return nil, xerrors.Errorf("failed to scan image: %w", err)
|
||||
|
||||
}
|
||||
imageDetail := fmt.Sprintf("%s (%s %s)", target, osFamily, osVersion)
|
||||
results[imageDetail] = osVulns
|
||||
if osFamily != "" {
|
||||
imageDetail := fmt.Sprintf("%s (%s %s)", target, osFamily, osVersion)
|
||||
results[imageDetail] = osVulns
|
||||
}
|
||||
|
||||
libVulns, err := library.Scan(files)
|
||||
if err != nil {
|
||||
|
||||
32
pkg/types/dockerConf.go
Normal file
32
pkg/types/dockerConf.go
Normal file
@@ -0,0 +1,32 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/caarlos0/env/v6"
|
||||
"github.com/knqyf263/fanal/types"
|
||||
)
|
||||
|
||||
type DockerConfig struct {
|
||||
AuthURL string `env:"TRIVY_AUTH_URL"`
|
||||
UserName string `env:"TRIVY_USERNAME"`
|
||||
Password string `env:"TRIVY_PASSWORD"`
|
||||
Timeout time.Duration `env:"TRIVY_TIMEOUT_SEC" envDefault:"60s"`
|
||||
Insecure bool `env:"TRIVY_INSECURE" envDefault:"true"`
|
||||
NonSSL bool `env:"TRIVY_NON_SSL" envDefault:"false"`
|
||||
}
|
||||
|
||||
func GetDockerOption() (types.DockerOption, error) {
|
||||
cfg := DockerConfig{}
|
||||
if err := env.Parse(&cfg); err != nil {
|
||||
return types.DockerOption{}, err
|
||||
}
|
||||
return types.DockerOption{
|
||||
AuthURL: cfg.AuthURL,
|
||||
UserName: cfg.UserName,
|
||||
Password: cfg.Password,
|
||||
Timeout: cfg.Timeout,
|
||||
Insecure: cfg.Insecure,
|
||||
NonSSL: cfg.NonSSL,
|
||||
}, nil
|
||||
}
|
||||
@@ -89,17 +89,16 @@ func getDetail(vulnID string) (Severity, string, string, []string) {
|
||||
|
||||
func getSeverity(details map[string]Vulnerability) Severity {
|
||||
for _, source := range sources {
|
||||
d, ok := details[source]
|
||||
if !ok {
|
||||
switch d, ok := details[source]; {
|
||||
case !ok:
|
||||
continue
|
||||
}
|
||||
if d.CvssScore > 0 {
|
||||
case d.CvssScore > 0:
|
||||
return scoreToSeverity(d.CvssScore)
|
||||
} else if d.CvssScoreV3 > 0 {
|
||||
case d.CvssScoreV3 > 0:
|
||||
return scoreToSeverity(d.CvssScoreV3)
|
||||
} else if d.Severity != 0 {
|
||||
case d.Severity != 0:
|
||||
return d.Severity
|
||||
} else if d.SeverityV3 != 0 {
|
||||
case d.SeverityV3 != 0:
|
||||
return d.SeverityV3
|
||||
}
|
||||
}
|
||||
@@ -151,14 +150,16 @@ func getReferences(details map[string]Vulnerability) []string {
|
||||
}
|
||||
|
||||
func scoreToSeverity(score float64) Severity {
|
||||
if score >= 9.0 {
|
||||
switch {
|
||||
case score >= 9.0:
|
||||
return SeverityCritical
|
||||
} else if score >= 7.0 {
|
||||
case score >= 7.0:
|
||||
return SeverityHigh
|
||||
} else if score >= 4.0 {
|
||||
case score >= 4.0:
|
||||
return SeverityMedium
|
||||
} else if score > 0.0 {
|
||||
case score > 0.0:
|
||||
return SeverityLow
|
||||
default:
|
||||
return SeverityUnknown
|
||||
}
|
||||
return SeverityUnknown
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
"github.com/knqyf263/trivy/pkg/vulnsrc/nvd"
|
||||
"github.com/knqyf263/trivy/pkg/vulnsrc/redhat"
|
||||
"github.com/knqyf263/trivy/pkg/vulnsrc/ubuntu"
|
||||
"github.com/knqyf263/trivy/pkg/vulnsrc/vulnerability"
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
@@ -19,7 +20,29 @@ const (
|
||||
repoURL = "https://github.com/knqyf263/vuln-list.git"
|
||||
)
|
||||
|
||||
func Update() (err error) {
|
||||
type updateFunc func(dir string, updatedFiles map[string]struct{}) error
|
||||
|
||||
var (
|
||||
// UpdateList has list of update distributions
|
||||
UpdateList []string
|
||||
updateMap = map[string]updateFunc{
|
||||
vulnerability.Nvd: nvd.Update,
|
||||
vulnerability.Alpine: alpine.Update,
|
||||
vulnerability.RedHat: redhat.Update,
|
||||
vulnerability.Debian: debian.Update,
|
||||
vulnerability.DebianOVAL: debianoval.Update,
|
||||
vulnerability.Ubuntu: ubuntu.Update,
|
||||
}
|
||||
)
|
||||
|
||||
func init() {
|
||||
UpdateList = make([]string, 0, len(updateMap))
|
||||
for distribution := range updateMap {
|
||||
UpdateList = append(UpdateList, distribution)
|
||||
}
|
||||
}
|
||||
|
||||
func Update(names []string) error {
|
||||
log.Logger.Info("Updating vulnerability database...")
|
||||
|
||||
// Clone vuln-list repository
|
||||
@@ -35,41 +58,15 @@ func Update() (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Update NVD
|
||||
log.Logger.Info("Updating NVD data...")
|
||||
if err = nvd.Update(dir, updatedFiles); err != nil {
|
||||
return xerrors.Errorf("error in NVD update: %w", err)
|
||||
for _, distribution := range names {
|
||||
updateFunc, ok := updateMap[distribution]
|
||||
if !ok {
|
||||
return xerrors.Errorf("%s does not supported yet", distribution)
|
||||
}
|
||||
log.Logger.Infof("Updating %s data...", distribution)
|
||||
if err := updateFunc(dir, updatedFiles); err != nil {
|
||||
return xerrors.Errorf("error in %s update: %w", distribution, err)
|
||||
}
|
||||
}
|
||||
|
||||
// Update Alpine OVAL
|
||||
log.Logger.Info("Updating Alpine data...")
|
||||
if err = alpine.Update(dir, updatedFiles); err != nil {
|
||||
return xerrors.Errorf("error in Alpine OVAL update: %w", err)
|
||||
}
|
||||
|
||||
//Update RedHat
|
||||
log.Logger.Info("Updating RedHat data...")
|
||||
if err = redhat.Update(dir, updatedFiles); err != nil {
|
||||
return xerrors.Errorf("error in RedHat update: %w", err)
|
||||
}
|
||||
|
||||
// Update Debian
|
||||
log.Logger.Info("Updating Debian data...")
|
||||
if err = debian.Update(dir, updatedFiles); err != nil {
|
||||
return xerrors.Errorf("error in Debian update: %w", err)
|
||||
}
|
||||
|
||||
// Update Debian OVAL
|
||||
log.Logger.Info("Updating Debian OVAL data...")
|
||||
if err = debianoval.Update(dir, updatedFiles); err != nil {
|
||||
return xerrors.Errorf("error in Debian OVAL update: %w", err)
|
||||
}
|
||||
|
||||
//Update Ubuntu
|
||||
log.Logger.Info("Updating Ubuntu data...")
|
||||
if err = ubuntu.Update(dir, updatedFiles); err != nil {
|
||||
return xerrors.Errorf("error in Ubuntu update: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user