Compare commits

..

38 Commits

Author SHA1 Message Date
Teppei Fukuda
42043a0888 fix(client): add image name and build time (#402)
* WIP: Add imageName and BuildTime for Remote detector

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

* wip

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

* change name from build_time to created

* remove an unused function

* fix(library): add image_name and created_at

* fix(ospkg): add image_name and created_at

* fix(scan): add image_name and created_at

* fix(library): remove unused param

Co-authored-by: Simarpreet Singh <simar@linux.com>
2020-02-16 10:35:53 +02:00
Teppei Fukuda
246793e873 fix(redhat): use binary package name for OVAL (#393)
* fix(redhat): use binary package name for OVAL

* test(redhat): add a test

* test(imtegration): update golden files
2020-01-28 15:59:47 +02:00
Takuya N
692b0f1410 cli: append warning when --template option is ignored (#391)
* test: cli: append warning when --template option is ignored

to avoid --template is silently ignored when --format <table|json>
or no --format is passed.

Signed-off-by: Takuya Noguchi <takninnovationresearch@gmail.com>

* cli: append warning when --template option is ignored

to avoid --template is silently ignored when --format <table|json>
or no --format is passed.

Signed-off-by: Takuya Noguchi <takninnovationresearch@gmail.com>

* test: cli: append warning when --format template is ignored

when --template is not specified

Signed-off-by: Takuya Noguchi <takninnovationresearch@gmail.com>

* cli: append warning when --format template is ignored

when --template is not specified

Signed-off-by: Takuya Noguchi <takninnovationresearch@gmail.com>

Co-authored-by: Teppei Fukuda <knqyf263@gmail.com>
2020-01-28 13:32:57 +02:00
Teppei Fukuda
0629e1d731 fix(cli): reject multiple images (#392) 2020-01-28 12:02:34 +02:00
Takuya N
9707c7bcb1 Initial GitLab CI template to deeply integrated with GitLab Container Scanning (#376)
Signed-off-by: Takuya Noguchi <takninnovationresearch@gmail.com>
2020-01-26 16:08:44 +02:00
Davin Kevin
194fbef73c feat(): include GitLab template inside the docker container (#388)
Co-authored-by: Teppei Fukuda <knqyf263@gmail.com>
2020-01-26 11:09:07 +02:00
Takuya N
f7db00c1eb Modify template for GitLab Container Scanning (#387)
Signed-off-by: Takuya Noguchi <takninnovationresearch@gmail.com>
2020-01-26 10:04:27 +02:00
Teppei Fukuda
2f4b31ecc6 chore(goreleaser): bump up to 0.124.1 (#383) 2020-01-23 14:13:01 +02:00
Takuya N
9289624688 doc: Update GitLab CI example documentation (#375)
Signed-off-by: Takuya Noguchi <takninnovationresearch@gmail.com>

Co-authored-by: Teppei Fukuda <knqyf263@gmail.com>
2020-01-23 12:08:18 +02:00
Teppei Fukuda
5a8749cd5b chore: add install script (#370)
* chore: add install script

* installer: change perms to include +x

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

Co-authored-by: Simarpreet Singh <simar@linux.com>
2020-01-19 09:13:36 +02:00
Aruneko
4a7fb525d7 fix typo in example of .gitlab-ci.yml (#373) 2020-01-17 12:16:00 +02:00
Teppei Fukuda
8888fcafa7 chore(goreleaser): change name_template to file_name_template (#369) 2020-01-14 12:30:53 +02:00
Manuel Rüger
63a8c6d26b Integrate with Gitlab Container Scanning (#367)
This PR integrates trivy with Gitlab Container Scanning and provides a
similar report. It adds the required template to the release tarball for easy
consumption.

https://docs.gitlab.com/ee/user/application_security/container_scanning/
https://gitlab.com/gitlab-org/gitlab/issues/11947
2020-01-14 11:46:14 +02:00
Teppei Fukuda
fc222bed7c chore: change a licence in goreleaser.yml (#365) 2020-01-13 12:58:22 +02:00
Manuel Rüger
6132ff93a2 template: Load template from paths (#202)
Signed-off-by: Manuel Rüger <manuel@rueg.eu>

Co-authored-by: Teppei Fukuda <knqyf263@gmail.com>
2020-01-13 11:39:02 +02:00
Manuel Rüger
87556aa741 Dockerfile: Update to alpine 3.11 (#361)
Co-authored-by: Teppei Fukuda <knqyf263@gmail.com>
2020-01-13 10:45:55 +02:00
Masahiro Fujimura
43362b2832 Fix inifinite loop when resolving dependencies of packages in Alpine (#364)
* Change fanal ref

* Fix Inifinite loop when resolving dependencies of packages in Alpine
2020-01-12 18:39:21 +02:00
Simarpreet Singh
db2d0c2e9b docker_engine_test: Add more OSes (#358)
* docker_engine_test: Add more OSes

Fixes: https://github.com/aquasecurity/trivy/issues/356

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

* integration: Add all OSes for docker mode.

Signed-off-by: Simarpreet Singh <simar@linux.com>
2020-01-10 21:25:43 +02:00
Huang Huang
922d493159 Add EOL Date for alpine 3.11 (#359)
Ref: https://endoflife.date/alpine
2020-01-08 10:33:17 +02:00
Teppei Fukuda
c4811c3104 chore(dep): update (#357) 2020-01-05 22:53:06 +02:00
Teppei Fukuda
0ec840b3b4 feat(client): retry HTTP request when getting an unavailable error (#350)
* feat(client): retry HTTP request when getting an unavailable error

* fix(integration-test): use a snapshot database for Docker mode (#352)

* fix(integration): add a binary name

The first argument is used for the program name. --skip-update was
ignored.

* fix(integration): use a snapshot database

After a new vulnerability is found, this test fails

* chore(integration): add t.Run

* refactor(client): functionalize common processes

* refactor(client): remove unused const
2020-01-05 10:21:18 +02:00
Teppei Fukuda
0b96d08877 fix(integration-test): use a snapshot database for Docker mode (#352)
* fix(integration): add a binary name

The first argument is used for the program name. --skip-update was
ignored.

* fix(integration): use a snapshot database

After a new vulnerability is found, this test fails

* chore(integration): add t.Run
2019-12-30 17:48:15 +02:00
Masahiro Fujimura
7abd41609f Delete requires for release (#345) 2019-12-27 11:24:23 +02:00
Masahiro Fujimura
fcc193b7d1 Support Photon OS (#340)
* Add photon

* test(vulnerability): use generated structs and mock

* test(photon): add integration tests

* test(photon): comment in

* test(integration): add vulnerability details to trivy.db

* chore(mod): update dependencies

* chore(README): add Photon OS

Co-authored-by: Teppei Fukuda <knqyf263@gmail.com>
2019-12-27 10:30:53 +02:00
Teppei Fukuda
44d74a7d8a chore(README): add 0.0.0.0 to the server example (#342) 2019-12-26 16:19:48 +02:00
Teppei Fukuda
4189855fc1 fix(cache): specify a directory to store image cache (#341)
* chore(mod): update dependencies

* fix(scanner): make scanner take a cache client as the argument

* refactor: sort imports

* refactor(cache): create a struct to clear cache

* fix(cache): use a struct to clear cache

* fix(wire): update constructor to take cache struct

* fix(cache): use the constructor generated by wire

* docs(cli): update the option description

* fix(cache): use the cache struct

* fix(cache): split Reset into ClearDB and ClearImages
2019-12-26 16:08:08 +02:00
Simarpreet Singh
77f1abc17d Integration tests for docker mode (#335)
* wip: run trivy after adding image

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

* integration: Add an integration test for docker mode

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

* integration: Add error checks for docker_engine_test

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

* circleci: add specific docker version

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

* circleci: add specific docker version

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

* docker_engine_test: Add a sad path

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

* circleci: Add docker_version by param

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

* circleci: Add more docker versions

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

* test(integration): remove old docker versions

* chore(ci): add requires

Co-authored-by: Teppei Fukuda <knqyf263@gmail.com>
2019-12-26 12:48:17 +02:00
Teppei Fukuda
96d58ccd1b fix(client): clear cache (#339) 2019-12-25 13:47:56 +02:00
Teppei Fukuda
823374b578 feat(client/server): add --token-headers option (#326)
* feat(option): add token-header

* feat(client): add token header

* feat(server): add token header

* test(token): fix tests

* test(token): add integration tests

* feat(client): add --custom-headers
2019-12-24 16:49:56 +02:00
Masahiro Fujimura
b127c1c8a7 Support SUSE (#337)
* Add suse support

* Add suse support

* Add OpenSUSETumbleweed

* mv suse to detector

* Add trivy-db

* Fix suse test

* Add integration test

* Change README.md

* change go.mod

* Fix bug

* Fix integration

* Fix golden file

* update go.mod

Co-authored-by: Teppei Fukuda <knqyf263@gmail.com>
2019-12-23 21:27:25 +02:00
Liz Rice
b1ea09d901 Merge pull request #272 from aquasecurity/lizrice-patch-1
docs: note that some sources are non-commercial
2019-12-17 21:01:30 +00:00
jerbia
8c1c3df232 Merge branch 'master' into lizrice-patch-1 2019-12-17 22:55:51 +02:00
Teppei Fukuda
cee08c38f4 feat(db): show progress when downloading the DB (#317)
* fix(github): return db size

* fix(github_mock): add size

* feat(indicator): add progress bar

* refactor(config): remove global Quiet

* fix(db): take progress bar as an argument

* fix(progress): inject progress bar
2019-12-16 19:23:08 +02:00
Manuel Rüger
bc8f613ba6 fix(writer): Refactor results struct (#327) 2019-12-16 16:15:47 +02:00
Teppei Fukuda
af584a8517 Revert "change mod genuinetools/reg to vanilla (#297)" (#321)
This reverts commit 1e9dcdb7d1.
2019-12-16 10:18:24 +02:00
jabielecki
1805a956a3 refactor for newest fanal (#305)
Changes for compatilibity with PR aquasecurity/fanal#47

Signed-off-by: Jakub Bielecki <jakub.bielecki@codilime.com>
2019-12-15 10:22:48 +02:00
Liz Rice
b9eddafe71 Merge branch 'master' into lizrice-patch-1 2019-11-25 11:59:40 +00:00
Liz Rice
bdd1266087 docs: note that some sources are non-commercial 2019-11-15 07:47:29 +00:00
86 changed files with 3359 additions and 775 deletions

View File

@@ -1,3 +1,5 @@
version: 2.1
defaults: &defaults
docker :
- image: aquasec/trivy-ci:latest
@@ -5,7 +7,7 @@ defaults: &defaults
CGO_ENABLED: "0"
jobs:
test:
unit-test:
<<: *defaults
steps:
- checkout
@@ -22,6 +24,15 @@ jobs:
- run:
name: Test
command: make test
integration-test:
<<: *defaults
parameters:
docker_version:
type: string
steps:
- checkout
- setup_remote_docker:
version: << parameters.docker_version >>
- run:
name: Integration Test
command: make test-integration
@@ -54,12 +65,14 @@ jobs:
- run:
name: Create deb repository
command: ci/deploy-deb.sh
workflows:
version: 2
release:
jobs:
- test
jobs:
- unit-test
- integration-test:
docker_version: 18.09.3
- release:
filters:
branches:

View File

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

View File

@@ -32,6 +32,7 @@ A Simple and Comprehensive Vulnerability Scanner for Containers, Suitable for CI
- [Scan an image](#scan-an-image)
- [Scan an image file](#scan-an-image-file)
- [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)
@@ -44,10 +45,11 @@ A Simple and Comprehensive Vulnerability Scanner for Containers, Suitable for CI
- [Client/Server](#client--server)
- [Server](#server)
- [Client](#client)
- [Authentication](#authentication)
- [Continuous Integration (CI)](#continuous-integration-ci)
- [Travis CI](#travis-ci)
- [CircleCI](#circleci)
- [GitLab CI](#gitlab)
- [GitLab CI](#gitlab-ci)
- [Authorization for Private Docker Registry](#authorization-for-private-docker-registry)
- [Vulnerability Detection](#vulnerability-detection)
- [OS Packages](#os-packages)
@@ -76,7 +78,7 @@ See [here](#continuous-integration-ci) for details.
# Features
- Detect comprehensive vulnerabilities
- OS packages (Alpine, **Red Hat Universal Base Image**, Red Hat Enterprise Linux, CentOS, Oracle Linux, Debian, Ubuntu, Amazon Linux and Distroless)
- 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
@@ -94,6 +96,8 @@ See [here](#continuous-integration-ci) for details.
- **Suitable for CI** such as Travis CI, CircleCI, Jenkins, etc.
- See [CI Example](#continuous-integration-ci)
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.
# Installation
## RHEL/CentOS
@@ -651,6 +655,25 @@ $ trivy -f json -o results.json golang:1.12-alpine
</details>
### Save the results using a template
```
$ trivy --format template --template "{{ range . }} {{ .Target }} {{ end }}" golang:1.12-alpine
```
<details>
<summary>Result</summary>
```
2020-01-02T18:02:32.856+0100 INFO Detecting Alpine vulnerabilities...
golang:1.12-alpine (alpine 3.10.2)
```
</details>
You can load templates from a file prefixing the template path with an @.
```
$ trivy --format template --template "@/path/to/template" golang:1.12-alpine
```
### Filter the vulnerabilities by severities
```
@@ -1098,6 +1121,12 @@ $ trivy server --listen localhost:8080
2019-12-12T15:17:56.707+0200 INFO Listening localhost:8080...
```
If you want to accept a connection from outside, you have to specify `0.0.0.0` or your ip address, not `localhost`.
```
$ trivy server --listen 0.0.0.0:8080
```
### Client
Then, specify the remote address.
```
@@ -1124,6 +1153,15 @@ Total: 3 (UNKNOWN: 0, LOW: 1, MEDIUM: 2, HIGH: 0, CRITICAL: 0)
```
</details>
### Authentication
```
$ trivy server --listen localhost:8080 --token dummy
```
```
$ trivy client --remote http://localhost:8080 --token dummy alpine:3.10
```
### Deprecated options
@@ -1201,7 +1239,7 @@ workflows:
Example: https://circleci.com/gh/aquasecurity/trivy-ci-test
Repository: https://github.com/aquasecurity/trivy-ci-test
## GitLab
## GitLab CI
```
$ cat .gitlab-ci.yml
@@ -1210,7 +1248,7 @@ stages:
trivy:
stage: test
image: docker:19.03.1
image: docker:stable
services:
- name: docker:dind
entrypoint: ["env", "-u", "DOCKER_HOST"]
@@ -1220,6 +1258,7 @@ trivy:
DOCKER_DRIVER: overlay2
# See https://github.com/docker-library/docker/pull/166
DOCKER_TLS_CERTDIR: ""
IMAGE: trivy-ci-test:$CI_COMMIT_SHA
before_script:
- apk add --no-cache curl
- export VERSION=$(curl --silent "https://api.github.com/repos/aquasecurity/trivy/releases/latest" | grep '"tag_name":' | sed -E 's/.*"v([^"]+)".*/\1/')
@@ -1228,13 +1267,22 @@ trivy:
- tar zxvf trivy_${VERSION}_Linux-64bit.tar.gz
allow_failure: true
script:
- docker build -t trivy-ci-test:$CI_COMMIT_SHA .
- ./trivy --exit-code 0 --cache-dir $CI_PROJECT_DIR/.trivycache/ --no-progress --severity HIGH trivy-ci-test:$CI_COMMIT_SHA
- ./trivy --exit-code 1 --severity CRITICAL --no-progress trivy-ci-test:$CI_COMMIT_SHA
# Build image
- docker build -t $IMAGE .
# Build report
- ./trivy --exit-code 0 --cache-dir .trivycache/ --no-progress --format template --template "@contrib/gitlab.tpl" -o gl-container-scanning-report.json $IMAGE
# Print report
- ./trivy --exit-code 0 --cache-dir .trivycache/ --no-progress --severity HIGH $IMAGE
# Fail on high and critical vulnerabilities
- ./trivy --exit-code 1 --cache-dir .trivycache/ --severity CRITICAL --no-progress $IMAGE
cache:
paths:
- $CI_PROJECT_DIR/.trivycache/
```
- .trivycache/
# Enables https://docs.gitlab.com/ee/user/application_security/container_scanning/ (Container Scanning report is available on GitLab EE Ultimate or GitLab.com Gold)
artifacts:
reports:
container_scanning: gl-container-scanning-report.json
```
## Authorization for Private Docker Registry
@@ -1296,11 +1344,14 @@ The unfixed/unfixable vulnerabilities mean that the patch has not yet been provi
| CentOS | 6, 7 | Installed by yum/rpm | YES |
| Oracle Linux | 5, 6, 7, 8 | Installed by yum/rpm | NO |
| Amazon Linux | 1, 2 | Installed by yum/rpm | NO |
| openSUSE Leap | 42, 15 | Installed by zypper/rpm | NO |
| SUSE Enterprise Linux | 11, 12, 15 | Installed by zypper/rpm | NO |
| Photon OS | 1.0, 2.0, 3.0 | Installed by tdnf/yum/rpm | NO |
| Debian GNU/Linux | wheezy, jessie, stretch, buster | Installed by apt/apt-get/dpkg | YES |
| Ubuntu | 12.04, 14.04, 16.04, 18.04, 18.10, 19.04 | Installed by apt/apt-get/dpkg | YES |
| Distroless | Any | Installed by apt/apt-get/dpkg | YES |
RHEL, CentOS, Oracle Linux and Amazon Linux package information is stored in a binary format, and Trivy uses the `rpm` executable to parse this information when scanning an image based on RHEL or CentOS. The Trivy container image includes `rpm`, and the installers include it as a dependency. If you installed the `trivy` binary using `wget` or `curl`, or if you build it from source, you will also need to ensure that `rpm` is available.
RHEL, CentOS, Oracle Linux, SUSE, Amazon Linux and Photon OS package information is stored in a binary format, and Trivy uses the `rpm` executable to parse this information when scanning an image based on RHEL or CentOS. The Trivy container image includes `rpm`, and the installers include it as a dependency. If you installed the `trivy` binary using `wget` or `curl`, or if you build it from source, you will also need to ensure that `rpm` is available.
Distroless: https://github.com/GoogleContainerTools/distroless

View File

@@ -3,7 +3,7 @@ FROM circleci/golang:1.13-buster
RUN sudo apt-get -y update \
&& sudo apt-get -y install rpm reprepro createrepo
ARG GORELEASER_VERSION=0.110.0
ARG GORELEASER_VERSION=0.124.1
ARG GORELEASER_ARTIFACT=goreleaser_Linux_x86_64.tar.gz
RUN wget https://github.com/goreleaser/goreleaser/releases/download/v${GORELEASER_VERSION}/${GORELEASER_ARTIFACT} \
&& sudo tar -xzf ${GORELEASER_ARTIFACT} -C /usr/bin/ goreleaser \

View File

@@ -0,0 +1,29 @@
Trivy_container_scanning:
stage: test
image:
name: alpine:3.11
variables:
# Override the GIT_STRATEGY variable in your `.gitlab-ci.yml` file and set it to `fetch` if you want to provide a `clair-whitelist.yml`
# file. See https://docs.gitlab.com/ee/user/application_security/container_scanning/index.html#overriding-the-container-scanning-template
# for details
GIT_STRATEGY: none
IMAGE: "$CI_REGISTRY_IMAGE:$CI_COMMIT_SHA"
allow_failure: true
before_script:
- export TRIVY_VERSION=${TRIVY_VERSION:-v0.4.3}
- apk add --no-cache curl docker-cli
- docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY
- curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/master/contrib/install.sh | sh -s -- -b /usr/local/bin ${TRIVY_VERSION}
- curl -sSL -o /tmp/trivy-gitlab.tpl https://github.com/aquasecurity/trivy/raw/${TRIVY_VERSION}/contrib/gitlab.tpl
script:
- trivy --exit-code 0 --cache-dir .trivycache/ --no-progress --format template --template "@/tmp/trivy-gitlab.tpl" -o gl-container-scanning-report.json $IMAGE
cache:
paths:
- .trivycache/
artifacts:
reports:
container_scanning: gl-container-scanning-report.json
dependencies: []
only:
refs:
- branches

80
contrib/gitlab.tpl Normal file
View File

@@ -0,0 +1,80 @@
{{- /* Template based on https://docs.gitlab.com/ee/user/application_security/container_scanning/#reports-json-format */ -}}
{
"version": "2.3",
"vulnerabilities": [
{{- $first := true }}
{{- range . }}
{{- $target := .Target }}
{{- range .Vulnerabilities -}}
{{- if $first -}}
{{- $first = false -}}
{{ else -}}
,
{{- end }}
{
"category": "container_scanning",
"message": {{ .Title | printf "%q" }},
"description": {{ .Description | printf "%q" }},
"cve": "{{ .VulnerabilityID }}",
"severity": {{ if eq .Severity "UNKNOWN" -}}
"Unknown"
{{- else if eq .Severity "LOW" -}}
"Low"
{{- else if eq .Severity "MEDIUM" -}}
"Medium"
{{- else if eq .Severity "HIGH" -}}
"High"
{{- else if eq .Severity "CRITICAL" -}}
"Critical"
{{- else -}}
"{{ .Severity }}"
{{- end }},
"confidence": "Unknown",
"solution": {{ if .FixedVersion -}}
"Upgrade {{ .PkgName }} to {{ .FixedVersion }}"
{{- else -}}
"No solution provided"
{{- end }},
"scanner": {
"id": "trivy",
"name": "trivy"
},
"location": {
"dependency": {
"package": {
"name": "{{ .PkgName }}"
},
"version": "{{ .InstalledVersion }}"
},
{{- /* TODO: No mapping available - https://github.com/aquasecurity/trivy/issues/332 */}}
"operating_system": "Unknown",
"image": "{{ $target }}"
},
"identifiers": [
{
{{- /* TODO: Type not extractable - https://github.com/aquasecurity/trivy-db/pull/24 */}}
"type": "cve",
"name": "{{ .VulnerabilityID }}",
"value": "{{ .VulnerabilityID }}",
"url": ""
}
],
"links": [
{{- $first := true -}}
{{- range .References -}}
{{- if $first -}}
{{- $first = false }}
{{- else -}}
,
{{- end -}}
{
"url": "{{ . }}"
}
{{- end }}
]
}
{{- end -}}
{{- end }}
],
"remediations": []
}

409
contrib/install.sh Executable file
View File

@@ -0,0 +1,409 @@
#!/bin/sh
set -e
# Code generated by godownloader on 2020-01-14T10:03:29Z. DO NOT EDIT.
#
usage() {
this=$1
cat <<EOF
$this: download go binaries for aquasecurity/trivy
Usage: $this [-b] bindir [-d] [tag]
-b sets bindir or installation directory, Defaults to ./bin
-d turns on debug logging
[tag] is a tag from
https://github.com/aquasecurity/trivy/releases
If tag is missing, then the latest will be used.
Generated by godownloader
https://github.com/goreleaser/godownloader
EOF
exit 2
}
parse_args() {
#BINDIR is ./bin unless set be ENV
# over-ridden by flag below
BINDIR=${BINDIR:-./bin}
while getopts "b:dh?x" arg; do
case "$arg" in
b) BINDIR="$OPTARG" ;;
d) log_set_priority 10 ;;
h | \?) usage "$0" ;;
x) set -x ;;
esac
done
shift $((OPTIND - 1))
TAG=$1
}
# this function wraps all the destructive operations
# if a curl|bash cuts off the end of the script due to
# network, either nothing will happen or will syntax error
# out preventing half-done work
execute() {
tmpdir=$(mktemp -d)
log_debug "downloading files into ${tmpdir}"
http_download "${tmpdir}/${TARBALL}" "${TARBALL_URL}"
http_download "${tmpdir}/${CHECKSUM}" "${CHECKSUM_URL}"
hash_sha256_verify "${tmpdir}/${TARBALL}" "${tmpdir}/${CHECKSUM}"
srcdir="${tmpdir}"
(cd "${tmpdir}" && untar "${TARBALL}")
test ! -d "${BINDIR}" && install -d "${BINDIR}"
for binexe in $BINARIES; do
if [ "$OS" = "windows" ]; then
binexe="${binexe}.exe"
fi
install "${srcdir}/${binexe}" "${BINDIR}/"
log_info "installed ${BINDIR}/${binexe}"
done
rm -rf "${tmpdir}"
}
get_binaries() {
case "$PLATFORM" in
darwin/386) BINARIES="trivy" ;;
darwin/amd64) BINARIES="trivy" ;;
darwin/arm64) BINARIES="trivy" ;;
darwin/armv7) BINARIES="trivy" ;;
freebsd/386) BINARIES="trivy" ;;
freebsd/amd64) BINARIES="trivy" ;;
freebsd/arm64) BINARIES="trivy" ;;
freebsd/armv7) BINARIES="trivy" ;;
linux/386) BINARIES="trivy" ;;
linux/amd64) BINARIES="trivy" ;;
linux/arm64) BINARIES="trivy" ;;
linux/armv7) BINARIES="trivy" ;;
openbsd/386) BINARIES="trivy" ;;
openbsd/amd64) BINARIES="trivy" ;;
openbsd/arm64) BINARIES="trivy" ;;
openbsd/armv7) BINARIES="trivy" ;;
*)
log_crit "platform $PLATFORM is not supported. Make sure this script is up-to-date and file request at https://github.com/${PREFIX}/issues/new"
exit 1
;;
esac
}
tag_to_version() {
if [ -z "${TAG}" ]; then
log_info "checking GitHub for latest tag"
else
log_info "checking GitHub for tag '${TAG}'"
fi
REALTAG=$(github_release "$OWNER/$REPO" "${TAG}") && true
if test -z "$REALTAG"; then
log_crit "unable to find '${TAG}' - use 'latest' or see https://github.com/${PREFIX}/releases for details"
exit 1
fi
# if version starts with 'v', remove it
TAG="$REALTAG"
VERSION=${TAG#v}
}
adjust_format() {
# change format (tar.gz or zip) based on OS
true
}
adjust_os() {
# adjust archive name based on OS
case ${OS} in
386) OS=32bit ;;
amd64) OS=64bit ;;
arm) OS=ARM ;;
arm64) OS=ARM64 ;;
darwin) OS=macOS ;;
dragonfly) OS=DragonFlyBSD ;;
freebsd) OS=FreeBSD ;;
linux) OS=Linux ;;
netbsd) OS=NetBSD ;;
openbsd) OS=OpenBSD ;;
esac
true
}
adjust_arch() {
# adjust archive name based on ARCH
case ${ARCH} in
386) ARCH=32bit ;;
amd64) ARCH=64bit ;;
arm) ARCH=ARM ;;
arm64) ARCH=ARM64 ;;
darwin) ARCH=macOS ;;
dragonfly) ARCH=DragonFlyBSD ;;
freebsd) ARCH=FreeBSD ;;
linux) ARCH=Linux ;;
netbsd) ARCH=NetBSD ;;
openbsd) ARCH=OpenBSD ;;
esac
true
}
cat /dev/null <<EOF
------------------------------------------------------------------------
https://github.com/client9/shlib - portable posix shell functions
Public domain - http://unlicense.org
https://github.com/client9/shlib/blob/master/LICENSE.md
but credit (and pull requests) appreciated.
------------------------------------------------------------------------
EOF
is_command() {
command -v "$1" >/dev/null
}
echoerr() {
echo "$@" 1>&2
}
log_prefix() {
echo "$0"
}
_logp=6
log_set_priority() {
_logp="$1"
}
log_priority() {
if test -z "$1"; then
echo "$_logp"
return
fi
[ "$1" -le "$_logp" ]
}
log_tag() {
case $1 in
0) echo "emerg" ;;
1) echo "alert" ;;
2) echo "crit" ;;
3) echo "err" ;;
4) echo "warning" ;;
5) echo "notice" ;;
6) echo "info" ;;
7) echo "debug" ;;
*) echo "$1" ;;
esac
}
log_debug() {
log_priority 7 || return 0
echoerr "$(log_prefix)" "$(log_tag 7)" "$@"
}
log_info() {
log_priority 6 || return 0
echoerr "$(log_prefix)" "$(log_tag 6)" "$@"
}
log_err() {
log_priority 3 || return 0
echoerr "$(log_prefix)" "$(log_tag 3)" "$@"
}
log_crit() {
log_priority 2 || return 0
echoerr "$(log_prefix)" "$(log_tag 2)" "$@"
}
uname_os() {
os=$(uname -s | tr '[:upper:]' '[:lower:]')
case "$os" in
cygwin_nt*) os="windows" ;;
mingw*) os="windows" ;;
msys_nt*) os="windows" ;;
esac
echo "$os"
}
uname_arch() {
arch=$(uname -m)
case $arch in
x86_64) arch="amd64" ;;
x86) arch="386" ;;
i686) arch="386" ;;
i386) arch="386" ;;
aarch64) arch="arm64" ;;
armv5*) arch="armv5" ;;
armv6*) arch="armv6" ;;
armv7*) arch="armv7" ;;
esac
echo ${arch}
}
uname_os_check() {
os=$(uname_os)
case "$os" in
darwin) return 0 ;;
dragonfly) return 0 ;;
freebsd) return 0 ;;
linux) return 0 ;;
android) return 0 ;;
nacl) return 0 ;;
netbsd) return 0 ;;
openbsd) return 0 ;;
plan9) return 0 ;;
solaris) return 0 ;;
windows) return 0 ;;
esac
log_crit "uname_os_check '$(uname -s)' got converted to '$os' which is not a GOOS value. Please file bug at https://github.com/client9/shlib"
return 1
}
uname_arch_check() {
arch=$(uname_arch)
case "$arch" in
386) return 0 ;;
amd64) return 0 ;;
arm64) return 0 ;;
armv5) return 0 ;;
armv6) return 0 ;;
armv7) return 0 ;;
ppc64) return 0 ;;
ppc64le) return 0 ;;
mips) return 0 ;;
mipsle) return 0 ;;
mips64) return 0 ;;
mips64le) return 0 ;;
s390x) return 0 ;;
amd64p32) return 0 ;;
esac
log_crit "uname_arch_check '$(uname -m)' got converted to '$arch' which is not a GOARCH value. Please file bug report at https://github.com/client9/shlib"
return 1
}
untar() {
tarball=$1
case "${tarball}" in
*.tar.gz | *.tgz) tar --no-same-owner -xzf "${tarball}" ;;
*.tar) tar --no-same-owner -xf "${tarball}" ;;
*.zip) unzip "${tarball}" ;;
*)
log_err "untar unknown archive format for ${tarball}"
return 1
;;
esac
}
http_download_curl() {
local_file=$1
source_url=$2
header=$3
if [ -z "$header" ]; then
code=$(curl -w '%{http_code}' -sL -o "$local_file" "$source_url")
else
code=$(curl -w '%{http_code}' -sL -H "$header" -o "$local_file" "$source_url")
fi
if [ "$code" != "200" ]; then
log_debug "http_download_curl received HTTP status $code"
return 1
fi
return 0
}
http_download_wget() {
local_file=$1
source_url=$2
header=$3
if [ -z "$header" ]; then
wget -q -O "$local_file" "$source_url"
else
wget -q --header "$header" -O "$local_file" "$source_url"
fi
}
http_download() {
log_debug "http_download $2"
if is_command curl; then
http_download_curl "$@"
return
elif is_command wget; then
http_download_wget "$@"
return
fi
log_crit "http_download unable to find wget or curl"
return 1
}
http_copy() {
tmp=$(mktemp)
http_download "${tmp}" "$1" "$2" || return 1
body=$(cat "$tmp")
rm -f "${tmp}"
echo "$body"
}
github_release() {
owner_repo=$1
version=$2
test -z "$version" && version="latest"
giturl="https://github.com/${owner_repo}/releases/${version}"
json=$(http_copy "$giturl" "Accept:application/json")
test -z "$json" && return 1
version=$(echo "$json" | tr -s '\n' ' ' | sed 's/.*"tag_name":"//' | sed 's/".*//')
test -z "$version" && return 1
echo "$version"
}
hash_sha256() {
TARGET=${1:-/dev/stdin}
if is_command gsha256sum; then
hash=$(gsha256sum "$TARGET") || return 1
echo "$hash" | cut -d ' ' -f 1
elif is_command sha256sum; then
hash=$(sha256sum "$TARGET") || return 1
echo "$hash" | cut -d ' ' -f 1
elif is_command shasum; then
hash=$(shasum -a 256 "$TARGET" 2>/dev/null) || return 1
echo "$hash" | cut -d ' ' -f 1
elif is_command openssl; then
hash=$(openssl -dst openssl dgst -sha256 "$TARGET") || return 1
echo "$hash" | cut -d ' ' -f a
else
log_crit "hash_sha256 unable to find command to compute sha-256 hash"
return 1
fi
}
hash_sha256_verify() {
TARGET=$1
checksums=$2
if [ -z "$checksums" ]; then
log_err "hash_sha256_verify checksum file not specified in arg2"
return 1
fi
BASENAME=${TARGET##*/}
want=$(grep "${BASENAME}" "${checksums}" 2>/dev/null | tr '\t' ' ' | cut -d ' ' -f 1)
if [ -z "$want" ]; then
log_err "hash_sha256_verify unable to find checksum for '${TARGET}' in '${checksums}'"
return 1
fi
got=$(hash_sha256 "$TARGET")
if [ "$want" != "$got" ]; then
log_err "hash_sha256_verify checksum for '$TARGET' did not verify ${want} vs $got"
return 1
fi
}
cat /dev/null <<EOF
------------------------------------------------------------------------
End of functions from https://github.com/client9/shlib
------------------------------------------------------------------------
EOF
PROJECT_NAME="trivy"
OWNER=aquasecurity
REPO="trivy"
BINARY=trivy
FORMAT=tar.gz
OS=$(uname_os)
ARCH=$(uname_arch)
PREFIX="$OWNER/$REPO"
# use in logging routines
log_prefix() {
echo "$PREFIX"
}
PLATFORM="${OS}/${ARCH}"
GITHUB_DOWNLOAD=https://github.com/${OWNER}/${REPO}/releases/download
uname_os_check "$OS"
uname_arch_check "$ARCH"
parse_args "$@"
get_binaries
tag_to_version
adjust_format
adjust_os
adjust_arch
log_info "found version: ${VERSION} for ${TAG}/${OS}/${ARCH}"
NAME=${PROJECT_NAME}_${VERSION}_${OS}-${ARCH}
TARBALL=${NAME}.${FORMAT}
TARBALL_URL=${GITHUB_DOWNLOAD}/${TAG}/${TARBALL}
CHECKSUM=${PROJECT_NAME}_${VERSION}_checksums.txt
CHECKSUM_URL=${GITHUB_DOWNLOAD}/${TAG}/${CHECKSUM}
execute

23
go.mod
View File

@@ -3,13 +3,17 @@ module github.com/aquasecurity/trivy
go 1.13
require (
github.com/aquasecurity/fanal v0.0.0-20191104115841-1a8ced6845b7
github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5 // indirect
github.com/aquasecurity/fanal v0.0.0-20200112144021-9a35ce3bd793
github.com/aquasecurity/go-dep-parser v0.0.0-20190819075924-ea223f0ef24b
github.com/aquasecurity/trivy-db v0.0.0-20191120190201-a6645984b409
github.com/briandowns/spinner v0.0.0-20190319032542-ac46072a5a91
github.com/aquasecurity/trivy-db v0.0.0-20191226181755-d6cabf5bc5d1
github.com/caarlos0/env/v6 v6.0.0
github.com/genuinetools/reg v0.16.1
github.com/golang/protobuf v1.3.1
github.com/cenkalti/backoff v2.2.1+incompatible
github.com/cheggaaa/pb/v3 v3.0.3
github.com/docker/docker v0.0.0-20180924202107-a9c061deec0f
github.com/genuinetools/reg v0.16.0
github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d // indirect
github.com/golang/protobuf v1.3.2
github.com/google/go-github/v28 v28.1.1
github.com/google/wire v0.3.0
github.com/knqyf263/go-deb-version v0.0.0-20190517075300-09fca494f03d
@@ -17,20 +21,19 @@ require (
github.com/knqyf263/go-version v1.1.1
github.com/kylelemons/godebug v1.1.0
github.com/olekukonko/tablewriter v0.0.2-0.20190607075207-195002e6e56a
github.com/prometheus/procfs v0.0.5 // indirect
github.com/stretchr/testify v1.4.0
github.com/twitchtv/twirp v5.9.0+incompatible
github.com/twitchtv/twirp v5.10.1+incompatible
github.com/urfave/cli v1.20.0
go.etcd.io/bbolt v1.3.3 // indirect
go.uber.org/atomic v1.5.1 // indirect
go.uber.org/multierr v1.4.0 // indirect
go.uber.org/zap v1.13.0
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529
golang.org/x/net v0.0.0-20191014212845-da9a3fd4c582 // indirect
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421
golang.org/x/sys v0.0.0-20191020152052-9984515f0562 // indirect
golang.org/x/tools v0.0.0-20191121040551-947d4aa89328 // indirect
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898
gopkg.in/cheggaaa/pb.v1 v1.0.28
gopkg.in/yaml.v2 v2.2.4 // indirect
k8s.io/utils v0.0.0-20191010214722-8d271d903fe4
)
replace github.com/genuinetools/reg => github.com/tomoyamachi/reg v0.16.1-0.20190706172545-2a2250fd7c00

168
go.sum
View File

@@ -8,15 +8,17 @@ github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/GoogleCloudPlatform/docker-credential-gcr v1.5.0 h1:wykTgKwhVr2t2qs+xI020s6W5dt614QqCHV+7W9dg64=
github.com/GoogleCloudPlatform/docker-credential-gcr v1.5.0/go.mod h1:BB1eHdMLYEFuFdBlRMb0N7YGVdM5s6Pt0njxgvfbGGs=
github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA=
github.com/Microsoft/go-winio v0.4.14 h1:+hMXMk01us9KgxGb7ftKQt2Xpf5hH/yky+TDA+qxleU=
github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
github.com/Microsoft/hcsshim v0.8.6 h1:ZfF0+zZeYdzMIVMZHKtDKJvLHj76XCuVae/jNkjj0IA=
github.com/Microsoft/hcsshim v0.8.6/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg=
github.com/Microsoft/go-winio v0.4.12 h1:xAfWHN1IrQ0NJ9TBC0KBZoqLjzDTr1ML+4MywiUOryc=
github.com/Microsoft/go-winio v0.4.12/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA=
github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5 h1:ygIc8M6trr62pF5DucadTWGdEB4mEyvzi0e2nbcmcyA=
github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw=
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw=
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
github.com/VividCortex/ewma v1.1.1 h1:MnEK4VOv6n0RSY4vtRe3h11qjxL3+t0B8yOL8iMXdcM=
github.com/VividCortex/ewma v1.1.1/go.mod h1:2Tkkvm3sRDVXaiyucHiACn4cqf7DpdyLvmxzcbUokwA=
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 h1:uSoVVbwJiQipAclBbw+8quDsfcvFjOpI5iCf4p/cqCs=
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc h1:cAKDfWh5VpdgMhJosfJnn5/FoN2SRZ4p7fJNX58YPaU=
@@ -27,59 +29,58 @@ github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
github.com/aquasecurity/fanal v0.0.0-20190819081512-f04452b627c6/go.mod h1:enEz4FFetw4XAbkffaYgyCVq1556R9Ry+noqT4rq9BE=
github.com/aquasecurity/fanal v0.0.0-20191104115841-1a8ced6845b7 h1:CbCusMPZOgrbqiCWEFbWcmBBonllFpMJhtXp9WkyNVQ=
github.com/aquasecurity/fanal v0.0.0-20191104115841-1a8ced6845b7/go.mod h1:dD1Ny21eY5FSDyERfUIMwdgYhg6Lnw611VOwDHmTSoQ=
github.com/aquasecurity/fanal v0.0.0-20200112144021-9a35ce3bd793 h1:wPGD5cu66RvwRkNULAqOAMbNWFjmYSCJ/mqHJ5rYBN0=
github.com/aquasecurity/fanal v0.0.0-20200112144021-9a35ce3bd793/go.mod h1:S2D937GMywJzh6KiLQEyt/0yqmfAngUFvuQ9UmkIZSw=
github.com/aquasecurity/go-dep-parser v0.0.0-20190819075924-ea223f0ef24b h1:55Ulc/gvfWm4ylhVaR7MxOwujRjA6et7KhmUbSgUFf4=
github.com/aquasecurity/go-dep-parser v0.0.0-20190819075924-ea223f0ef24b/go.mod h1:BpNTD9vHfrejKsED9rx04ldM1WIbeyXGYxUrqTVwxVQ=
github.com/aquasecurity/trivy v0.1.6/go.mod h1:5hobyhxLzDtxruHzPxpND2PUKOssvGUdE9BocpJUwo4=
github.com/aquasecurity/trivy-db v0.0.0-20191120190201-a6645984b409 h1:RrFBrw3qZXH/AIEtEYF1WgYhXae3VPPaaPIJic5p1gw=
github.com/aquasecurity/trivy-db v0.0.0-20191120190201-a6645984b409/go.mod h1:vYzX1UhX0o29E+/nuFJTgUJBM5UA7I/NftnbBcYyYRE=
github.com/aquasecurity/trivy-db v0.0.0-20191226181755-d6cabf5bc5d1 h1:IVXoVH8ejJuBdxgH/+er2WjBxc0tqIGuBCqI5aWW3A0=
github.com/aquasecurity/trivy-db v0.0.0-20191226181755-d6cabf5bc5d1/go.mod h1:Uf9bXd50zTHtWTP7+7u5+OFCPtUVrmsS4v0RXd7E5lw=
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 h1:ukTLOeMC0aVxbJWVg6hOsVJ0VPIo8w++PbNsze/pqF8=
github.com/araddon/dateparse v0.0.0-20190426192744-0d74ffceef83/go.mod h1:SLqhdZcd+dF3TEVL2RMoob5bBP5R1P1qkox+HtCBgGI=
github.com/aws/aws-sdk-go v1.19.11 h1:tqaTGER6Byw3QvsjGW0p018U2UOqaJPeJuzoaF7jjoQ=
github.com/aws/aws-sdk-go v1.19.11/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/aws/aws-sdk-go v1.25.31 h1:14mdh3HsTgRekePPkYcCbAaEXJknc3mN7f4XfsiMMDA=
github.com/aws/aws-sdk-go v1.25.31/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0 h1:HWo1m869IqiPhD389kmkxeTalrjNbbJTC8LXupb+sl0=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
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/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4=
github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/cheggaaa/pb/v3 v3.0.3 h1:8WApbyUmgMOz7WIxJVNK0IRDcRfAmTxcEdi0TuxjdP4=
github.com/cheggaaa/pb/v3 v3.0.3/go.mod h1:Pp35CDuiEpHa/ZLGCtBbM6CBwMstv1bJlG884V+73Yc=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/containerd/containerd v1.2.9 h1:6tyNjBmAMG47QuFPIT9LgiiexoVxC6qpTGR+eD0R0Z8=
github.com/containerd/containerd v1.2.9/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
github.com/containerd/continuity v0.0.0-20180921161001-7f53d412b9eb/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
github.com/containerd/continuity v0.0.0-20190827140505-75bee3e2ccb6 h1:NmTXa/uVnDyp0TY5MKi197+3HWcnYWfnHGyaFthlnGw=
github.com/containerd/continuity v0.0.0-20190827140505-75bee3e2ccb6/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
github.com/coreos/clair v0.0.0-20180919182544-44ae4bc9590a/go.mod h1:uXhHPWAoRqw0jJc2f8RrPCwRhIo9otQ8OEWUFtpCiwA=
github.com/coreos/clair v2.0.1-0.20190910143208-94150ab1f4ac+incompatible/go.mod h1:uXhHPWAoRqw0jJc2f8RrPCwRhIo9otQ8OEWUFtpCiwA=
github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc h1:TP+534wVlf61smEIq1nwLLAjQVEK2EADoW3CX9AuT+8=
github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/deckarep/golang-set v1.7.1 h1:SCQV0S6gTtp6itiFrTqI+pfmJ4LN85S1YzhDf9rTHJQ=
github.com/deckarep/golang-set v1.7.1/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ=
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/docker/cli v0.0.0-20180920165730-54c19e67f69c h1:QlAVcyoF7QQVN7zV+xYBjgwtRVlRU3WCTCpb2mcqQrM=
github.com/docker/cli v0.0.0-20180920165730-54c19e67f69c/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
github.com/docker/cli v0.0.0-20190913211141-95327f4e6241 h1:btTBgRvrdoe+b7NfX/7PnUbiXzGceLCt09QZkg1bgqA=
github.com/docker/cli v0.0.0-20190913211141-95327f4e6241/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
github.com/docker/distribution v0.0.0-20180920194744-16128bbac47f/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug=
github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/docker v0.0.0-20180924202107-a9c061deec0f h1:W4fbqg0JUwy6lLesoJaV/rE0fwAmtdtinMa64X1CEh0=
github.com/docker/docker v0.0.0-20180924202107-a9c061deec0f/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker v1.4.2-0.20190916154449-92cc603036dd h1:kDIT0qjvLHbdL86aa+VteVpVZOR7coIyIejM/o3CwOo=
github.com/docker/docker v1.4.2-0.20190916154449-92cc603036dd/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker-ce v0.0.0-20180924210327-f53bd8bb8e43 h1:gZ4lWixV821UVbYtr+oz1ZPCHkbtE+ivfmHyZRgyl2Y=
github.com/docker/docker-ce v0.0.0-20180924210327-f53bd8bb8e43/go.mod h1:l1FUGRYBvbjnZ8MS6A2xOji4aZFlY/Qmgz7p4oXH7ac=
github.com/docker/docker-credential-helpers v0.6.1/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y=
github.com/docker/docker-credential-helpers v0.6.3 h1:zI2p9+1NQYdnG6sMU26EX4aVGlqbInSQxQXLvzJ4RPQ=
github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y=
github.com/docker/docker-credential-helpers v0.6.2 h1:CrW9H1VMf3a4GrtyAi7IUJjkJVpwBBpX0+mvkvYJaus=
github.com/docker/docker-credential-helpers v0.6.2/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y=
github.com/docker/go-connections v0.0.0-20180821093606-97c2040d34df/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
github.com/docker/go-metrics v0.0.0-20180209012529-399ea8c73916/go.mod h1:/u0gXw0Gay3ceNrsHubL3BtdOL2fHf93USgMTe0W5dI=
github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/docker/go-metrics v0.0.0-20181218153428-b84716841b82 h1:X0fj836zx99zFu83v/M79DuBn84IL/Syx1SY6Y5ZEMA=
github.com/docker/go-metrics v0.0.0-20181218153428-b84716841b82/go.mod h1:/u0gXw0Gay3ceNrsHubL3BtdOL2fHf93USgMTe0W5dI=
github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw=
github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 h1:UhxFibDNY/bfvqU5CAUmr9zpesgbU6SWc8/B4mflAE4=
@@ -100,43 +101,40 @@ github.com/etcd-io/bbolt v1.3.3 h1:gSJmxrs37LgTqR/oyJBWok6k6SvXEUerFTbltIhXkBM=
github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw=
github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fernet/fernet-go v0.0.0-20180830025343-9eac43b88a5e/go.mod h1:2H9hjfbpSMHwY503FclkV/lZTBh2YlOmLLSda12uL8c=
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BHsljHzVlRcyQhjrss6TZTdY2VfCqZPbv5k3iBFa2ZQ=
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/genuinetools/pkg v0.0.0-20180910213200-1c141f661797/go.mod h1:XTcrCYlXPxnxL2UpnwuRn7tcaTn9HAhxFoFJucootk8=
github.com/genuinetools/pkg v0.0.0-20181022210355-2fcf164d37cb/go.mod h1:XTcrCYlXPxnxL2UpnwuRn7tcaTn9HAhxFoFJucootk8=
github.com/genuinetools/reg v0.16.0/go.mod h1:12Fe9EIvK3dG/qWhNk5e9O96I8SGmCKLsJ8GsXUbk+Y=
github.com/genuinetools/reg v0.16.1 h1:nZiceimcvxEVtWKSmPtRhEkl2TrxDhrbmYEAbTkKXvo=
github.com/genuinetools/reg v0.16.1/go.mod h1:EgA+w+hj3rMsn5zBV5jdWIGsLAsoFIcSy0QlxAXsm5Q=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
github.com/gliderlabs/ssh v0.1.3 h1:cBU46h1lYQk5f2Z+jZbewFKy+1zzE2aUX/ilcPDAm9M=
github.com/gliderlabs/ssh v0.1.3/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.0 h1:xU6/SpYbvkNYiptHJYEDRseDLvYE7wSqhYYNy0QSUzI=
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.3.0 h1:G8O7TerXerS4F6sx9OV7/nRfJdnXgHZu/S/7F2SN+UE=
github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE=
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d h1:3PaI8p3seN09VjbTYC/QWlUZdZ1qS1zGjy7LH2Wt07I=
github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.2.0 h1:28o5sBqPkBsMGnC6b4MvE2TzSr5/AT4c/1fLqVGIwlk=
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-github/v28 v28.1.1 h1:kORf5ekX5qwXO2mGzXXOjMe/g6ap8ahVe0sBEulhSxo=
github.com/google/go-github/v28 v28.1.1/go.mod h1:bsqJWQX05omyWVmc00nEUql9mhQyv38lDZ8kPZcQVoM=
github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk=
@@ -154,10 +152,8 @@ github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
github.com/gorilla/mux v1.6.2 h1:Pgr17XVTNXAk3q/r4CpKzC5xBM/qW1uVLV+IhRZpIIk=
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gorilla/mux v1.7.3 h1:gnP5JzjVOuiZD07fKKToCAOjS0yOpj/qPETTXCCS6hw=
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw=
github.com/grpc-ecosystem/grpc-gateway v1.11.1/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/gorilla/mux v1.7.1 h1:Dw4jY2nghMMRsh1ol8dv1axHkDwMQK2DHerMNJsIpJU=
github.com/gorilla/mux v1.7.1/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/hashicorp/go-version v1.2.0 h1:3vNe/fWF5CBgRIguda1meWhsZHy3m8gCJ5wx+dIzX/E=
github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
@@ -173,6 +169,7 @@ github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfV
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/kevinburke/ssh_config v0.0.0-20180830205328-81db2a75821e h1:RgQk53JHp/Cjunrr1WlsXSZpqXn+uREuHvUVcK82CV8=
github.com/kevinburke/ssh_config v0.0.0-20180830205328-81db2a75821e/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
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=
@@ -187,6 +184,8 @@ github.com/knqyf263/nested v0.0.1 h1:Sv26CegUMhjt19zqbBKntjwESdxe5hxVPSk0+AKjdUc
github.com/knqyf263/nested v0.0.1/go.mod h1:zwhsIhMkBg90DTOJQvxPkKIypEHPYkgWHs4gybdlUmk=
github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s=
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
@@ -205,30 +204,30 @@ github.com/mattn/go-isatty v0.0.5 h1:tHXDdz1cpzGaovsTB+TVB8q90WEokoVmfMqoVcrLUgw
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.8 h1:HLtExJ+uU2HOZ+wI0Tt5DtUDrx8yhUqDcp7fYERX4CE=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.10 h1:qxFzApOv4WsAL965uUPIsXzAKCZxN2p9UqdhFS4ZW10=
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
github.com/mattn/go-jsonpointer v0.0.0-20180225143300-37667080efed h1:fCWISZq4YN4ulCJx7x0KB15rqxLEe3mtNJL8cSOGKZU=
github.com/mattn/go-jsonpointer v0.0.0-20180225143300-37667080efed/go.mod h1:SDJ4hurDYyQ9/7nc+eCYtXqdufgK4Cq9TJlwPklqEYA=
github.com/mattn/go-runewidth v0.0.4 h1:2BvfKmzob6Bmd4YsL0zygOqfdFnK7GR4QL06Do4/p7Y=
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/mattn/go-runewidth v0.0.6 h1:V2iyH+aX9C5fsYCpK60U8BYIvmhqxuOL3JZcqc1NB7k=
github.com/mattn/go-runewidth v0.0.6/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c h1:nXxl5PrvVm2L/wCy8dQu6DMTwH4oIuGN8GJDAlqDdVE=
github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
github.com/olekukonko/tablewriter v0.0.2-0.20190607075207-195002e6e56a h1:0LD5FJGQpEyD78OdhX97W75RjYmMjfLPp1ePrk5URxs=
github.com/olekukonko/tablewriter v0.0.2-0.20190607075207-195002e6e56a/go.mod h1:rSAaSIOAGT9odnlyGlUfAJaoc5w2fSBUmeGDbRWPxyQ=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/gomega v1.4.2/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2 h1:QhPf3A2AZW3tTGvHPg0TA+CR3oHbVLlXUhlghqISp1I=
github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
github.com/opencontainers/go-digest v1.0.0-rc1 h1:WzifXhOVOEOuFYOJAW6aQqW0TooG2iki3E3Ii+WN7gQ=
github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI=
github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
github.com/opencontainers/runc v0.1.1 h1:GlxAyO6x8rfZYN9Tt0Kti5a/cP41iuiO2yYT0IJGY8Y=
@@ -246,40 +245,45 @@ github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v0.0.0-20180924113449-f69c853d21c1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829 h1:D+CiwcpGTW6pL6bv6KI3KbyEyCKyS+1JWS2h8PNDnGA=
github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
github.com/prometheus/client_golang v0.9.3 h1:9iH4JKXLzFbOAdtqv/a+j8aewx2Y8lAjAydhbaScPF8=
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f h1:BVwpUVJDADN2ufcGik7W992pyps0wZ888b/y9GXcLTU=
github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90 h1:S/YWwWx/RA8rT8tKFRuGUZhuA90OyIBpPCXkcbwU8DE=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
github.com/prometheus/common v0.2.0 h1:kUZDBDTdBVBYBj5Tmh2NZLlF60mfjA27rM34b+cVwNU=
github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/procfs v0.0.0-20180920065004-418d78d0b9a7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/common v0.4.0 h1:7etb9YClo3a6HjLzfl6rIQaU+FDfi0VSX39io3aQ+DM=
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1 h1:/K3IL0Z1quvmJ7X0A1AwNEK7CRkVK3YwfOU/QAL4WGg=
github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084 h1:sofwID9zm4tzrgykg80hfFph1mryUeLRsUfoocVVmRY=
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/procfs v0.0.5 h1:3+auTFlqw+ZaQYJARz6ArODtkaIwtvBTx3N2NehQlL8=
github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
github.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg=
github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg=
github.com/shurcooL/httpfs v0.0.0-20181222201310-74dc9339e414/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg=
github.com/simplereach/timeutils v1.2.0/go.mod h1:VVbQDfN/FHRZa1LSqcwo4kNZ62OOyqLLGQKYB3pB0Q8=
github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc=
github.com/sirupsen/logrus v1.2.0 h1:juTguoYk5qI21pwyTXY3B3Y5cOTH3ZUyZCg1v/mihuo=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.1 h1:GL2rEmy6nsikmW0r8opw9JIRScdMF5hA8cOYLH7In1k=
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a h1:pa8hGb/2YqsZKovtsgrwcDH1RZhVbTKCjLp47XpqCDs=
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
github.com/src-d/gcfg v1.4.0 h1:xXbNR5AlLSA315x2UO+fTSSAXCDf+Ar38/6oyGbDKQ4=
github.com/src-d/gcfg v1.4.0/go.mod h1:p/UMsR43ujA89BJY9duynAwIpvqEujIH/jFlfL7jWoI=
@@ -291,8 +295,10 @@ github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0
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/twitchtv/twirp v5.9.0+incompatible h1:KBCo4NYCpE9alO1HAEcgninDnw/0AhPT1rZnHkkSqi8=
github.com/twitchtv/twirp v5.9.0+incompatible/go.mod h1:RRJoFSAmTEh2weEqWtpPE3vFK5YBhA6bqp2l1kfCC5A=
github.com/tomoyamachi/reg v0.16.1-0.20190706172545-2a2250fd7c00 h1:0e4vRd9YqnQBIAIAE39jLKDWffRfJWxloyWwcaMAQho=
github.com/tomoyamachi/reg v0.16.1-0.20190706172545-2a2250fd7c00/go.mod h1:RQE7h2jyIxekQZ24/wad0c9RGP+KSq4XzHh7h83ALi8=
github.com/twitchtv/twirp v5.10.1+incompatible h1:35js8ID9rYPKkZ0qWnuZw+q+OuCWM1GIibu1F1YImjA=
github.com/twitchtv/twirp v5.10.1+incompatible/go.mod h1:RRJoFSAmTEh2weEqWtpPE3vFK5YBhA6bqp2l1kfCC5A=
github.com/urfave/cli v1.20.0 h1:fDqGv3UG/4jbVl/QkFwEdddtEDjh/5Ov6X+0B/3bPaw=
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
github.com/xanzy/ssh-agent v0.2.0/go.mod h1:0NyE30eGUDliuLEHJgYte/zncp2zdTStcOnWhgSqHD8=
@@ -300,8 +306,6 @@ github.com/xanzy/ssh-agent v0.2.1 h1:TCbipTQL2JiiCprBWx9frJ2eJlCYT00NmctrHxVAr70
github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4=
go.etcd.io/bbolt v1.3.2 h1:Z/90sZLPOeCy2PwprqkFa25PdkusRzaj9P8zm/KNyvk=
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.etcd.io/bbolt v1.3.3 h1:MUGmc65QhB3pIlaQ5bB4LwqSj6GIonVJXpZiaKNyaKk=
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
go.uber.org/atomic v1.3.2 h1:2Oa65PReHzfn29GpvgsYwloV9AVFHPDk8tYxt2c2tr4=
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
@@ -321,7 +325,6 @@ go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.13.0 h1:nR6NoDBgAf67s68NhaXbsojM+2gxp3S1hWkHDl27pVU=
go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20180910181607-0e37d006457b/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 h1:bselrhR0Or1vomJZC8ZIjWtbDmn9OYFLX5Ik9alpJpE=
@@ -329,7 +332,6 @@ golang.org/x/crypto v0.0.0-20190404164418-38d8ce5564a5/go.mod h1:WFFai1msRO1wXaE
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529 h1:iMGN4xG0cnqj3t+zOM8wUB0BiPKHEwSxEZCvzcbZuvk=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
@@ -340,17 +342,17 @@ golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKG
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180925072008-f04abc6bdfa7/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c h1:uOCk1iQW6Vc18bnC13MfzScl+wdKBmM9Y9kU7Z83/lw=
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191014212845-da9a3fd4c582 h1:p9xBe/w/OzkeYVKm234g55gMdD1nSIooTir5kV11kfA=
golang.org/x/net v0.0.0-20191014212845-da9a3fd4c582/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191108221443-4ba9e2ef068c h1:SRpq/kuj/xNci/RdvEs+RSvpfxqvLAzTKuKGlzoGdZQ=
golang.org/x/net v0.0.0-20191108221443-4ba9e2ef068c/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421 h1:Wo7BWFiOk0QRFMLYMqJGFMd9CgUAcGx7V+qEg/h5IBI=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -364,7 +366,6 @@ golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20180903190138-2b024373dcd9/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180925112736-b09afc3d579e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -373,19 +374,25 @@ golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
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=
golang.org/x/sys v0.0.0-20191020152052-9984515f0562 h1:wOweSabW7qssfcg63CEDHHA4zyoqRlGU6eYV7IUMCq0=
golang.org/x/sys v0.0.0-20191020152052-9984515f0562/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190506115046-ca7f33d4116e h1:bq5BY1tGuaK8HxuwN6pT6kWgTVLeJ5KwuyBpsl1CZL4=
golang.org/x/sys v0.0.0-20190506115046-ca7f33d4116e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191105231009-c1f44814a5cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191128015809-6d18c012aee9 h1:ZBzSG/7F4eNKz2L3GE9o300RX0Az1Bw5HF7PDraD+qU=
golang.org/x/sys v0.0.0-20191128015809-6d18c012aee9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2 h1:z99zHgr7hKfrUcX/KsoJk5FJfjTceCKIp96+biqP4To=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c h1:fqgJT0MGcGpPgpWU7VRdRjuArfcOvC4AoJmILihzhDg=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 h1:SvFZT6jyqRaOeXpc5h/JSfZenJ2O330aBsf7JfSUXmQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
@@ -393,7 +400,7 @@ golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190422233926-fe54fb35175b/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190503185657-3b6f9c0030f7/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5 h1:hKsoRgsbwY1NafxrwTs+k64bikrLBkAgPir1TNCj3Zs=
@@ -411,17 +418,16 @@ google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9Ywl
google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20180924164928-221a8d4f7494/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107 h1:xtNn7qFlagY2mQNFHMSRPjT2RkOV4OXM7P5TVy9xATo=
google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/grpc v1.15.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio=
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873 h1:nfPFGzJkUDX6uBmpN/pSw7MbOAWegH5QDQuoXFHedLg=
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
google.golang.org/grpc v1.19.0 h1:cfg4PD8YEdSFnm7qLV4++93WcmhH2nIUhMjhdCvl3j8=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.23.1 h1:q4XQuHFC6I28BKZpo6IYyb3mNO+l7lSOxRuYTCiDfXk=
google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U=
google.golang.org/grpc v1.20.1 h1:Hz2g2wirWK7H0qIIhGIqRGTuMwTE8HEKFnDZZ7lm9NU=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
@@ -430,9 +436,7 @@ gopkg.in/cheggaaa/pb.v1 v1.0.28 h1:n1tBJnnK2r7g9OW2btFH91V92STTUevLXYFb8gy9EMk=
gopkg.in/cheggaaa/pb.v1 v1.0.28/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo=
gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA=
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
gopkg.in/src-d/go-billy.v4 v4.2.1/go.mod h1:tm33zBoOwxjYHZIE+OV8bxTWFMJLrconzFMd38aARFk=
gopkg.in/src-d/go-billy.v4 v4.3.0 h1:KtlZ4c1OWbIs4jCv5ZXrTqG8EQocr0g/d4DjNg70aek=
gopkg.in/src-d/go-billy.v4 v4.3.0/go.mod h1:tm33zBoOwxjYHZIE+OV8bxTWFMJLrconzFMd38aARFk=
@@ -444,21 +448,19 @@ gopkg.in/src-d/go-git.v4 v4.10.0/go.mod h1:Vtut8izDyrM8BUVQnzJ+YvmNcem2J89EmfZYC
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gotest.tools v2.1.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
k8s.io/klog v0.3.0 h1:0VPpR+sizsiivjIfIAQH/rl8tan6jvWkS7lU+0di3lE=
k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
k8s.io/utils v0.0.0-20191010214722-8d271d903fe4 h1:Gi+/O1saihwDqnlmC8Vhv1M5Sp4+rbOmK9TbsLn8ZEA=
k8s.io/utils v0.0.0-20191010214722-8d271d903fe4/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=

View File

@@ -33,8 +33,8 @@ nfpms:
homepage: "https://github.com/aquasecurity"
maintainer: "Teppei Fukuda <knqyf263@gmail.com>"
description: "A Fast Vulnerability Scanner for Containers"
license: "MIT"
name_template: "{{.ProjectName}}_{{.Version}}_{{.Os}}-{{.Arch}}"
license: "AGPL-3.0"
file_name_template: "{{.ProjectName}}_{{.Version}}_{{.Os}}-{{.Arch}}"
replacements:
amd64: 64bit
386: 32bit
@@ -65,6 +65,7 @@ archives:
files:
- README.md
- LICENSE
- contrib/gitlab.tpl
brews:
-
@@ -93,3 +94,5 @@ dockers:
- "--label=org.label-schema.build-date={{ .Date }}"
- "--label=org.label-schema.vcs=https://github.com/aquasecurity/trivy"
- "--label=org.label-schema.vcs-ref={{ .FullCommit }}"
extra_files:
- contrib/gitlab.tpl

View File

@@ -20,13 +20,15 @@ import (
func TestClientServer(t *testing.T) {
type args struct {
Version string
IgnoreUnfixed bool
Severity []string
IgnoreIDs []string
Input string
ClientToken string
ServerToken string
Version string
IgnoreUnfixed bool
Severity []string
IgnoreIDs []string
Input string
ClientToken string
ClientTokenHeader string
ServerToken string
ServerTokenHeader string
}
cases := []struct {
name string
@@ -45,10 +47,12 @@ func TestClientServer(t *testing.T) {
{
name: "alpine 3.10 integration with token",
testArgs: args{
Version: "dev",
Input: "testdata/fixtures/alpine-310.tar.gz",
ClientToken: "token",
ServerToken: "token",
Version: "dev",
Input: "testdata/fixtures/alpine-310.tar.gz",
ClientToken: "token",
ClientTokenHeader: "Trivy-Token",
ServerToken: "token",
ServerTokenHeader: "Trivy-Token",
},
golden: "testdata/alpine-310.json.golden",
},
@@ -257,13 +261,67 @@ func TestClientServer(t *testing.T) {
},
golden: "testdata/oraclelinux-8-slim.json.golden",
},
{
name: "opensuse leap 15.1 integration",
testArgs: args{
Version: "dev",
Input: "testdata/fixtures/opensuse-leap-151.tar.gz",
},
golden: "testdata/opensuse-leap-151.json.golden",
},
{
name: "opensuse leap 42.3 integration",
testArgs: args{
Version: "dev",
Input: "testdata/fixtures/opensuse-leap-423.tar.gz",
},
golden: "testdata/opensuse-leap-423.json.golden",
},
{
name: "photon 1.0 integration",
testArgs: args{
Version: "dev",
Input: "testdata/fixtures/photon-10.tar.gz",
},
golden: "testdata/photon-10.json.golden",
},
{
name: "photon 2.0 integration",
testArgs: args{
Version: "dev",
Input: "testdata/fixtures/photon-20.tar.gz",
},
golden: "testdata/photon-20.json.golden",
},
{
name: "photon 3.0 integration",
testArgs: args{
Version: "dev",
Input: "testdata/fixtures/photon-30.tar.gz",
},
golden: "testdata/photon-30.json.golden",
},
{
name: "invalid token",
testArgs: args{
Version: "dev",
Input: "testdata/fixtures/distroless-base.tar.gz",
ClientToken: "invalidtoken",
ServerToken: "token",
Version: "dev",
Input: "testdata/fixtures/distroless-base.tar.gz",
ClientToken: "invalidtoken",
ClientTokenHeader: "Trivy-Token",
ServerToken: "token",
ServerTokenHeader: "Trivy-Token",
},
wantErr: "twirp error unauthenticated: invalid token",
},
{
name: "invalid token header",
testArgs: args{
Version: "dev",
Input: "testdata/fixtures/distroless-base.tar.gz",
ClientToken: "valid-token",
ClientTokenHeader: "Trivy-Token",
ServerToken: "valid-token",
ServerTokenHeader: "Invalid",
},
wantErr: "twirp error unauthenticated: invalid token",
},
@@ -283,7 +341,7 @@ func TestClientServer(t *testing.T) {
// Setup CLI App
app := internal.NewApp(c.testArgs.Version)
app.Writer = ioutil.Discard
osArgs := setupServer(addr, c.testArgs.ServerToken, cacheDir)
osArgs := setupServer(addr, c.testArgs.ServerToken, c.testArgs.ServerTokenHeader, cacheDir)
// Run Trivy server
require.NoError(t, app.Run(osArgs), c.name)
@@ -297,7 +355,7 @@ func TestClientServer(t *testing.T) {
app.Writer = ioutil.Discard
osArgs, outputFile, cleanup := setupClient(t, c.testArgs.IgnoreUnfixed, c.testArgs.Severity,
c.testArgs.IgnoreIDs, addr, c.testArgs.ClientToken, c.testArgs.Input, cacheDir, c.golden)
c.testArgs.IgnoreIDs, addr, c.testArgs.ClientToken, c.testArgs.ClientTokenHeader, c.testArgs.Input, cacheDir, c.golden)
defer cleanup()
// Run Trivy client
@@ -322,16 +380,16 @@ func TestClientServer(t *testing.T) {
}
}
func setupServer(addr, token, cacheDir string) []string {
func setupServer(addr, token, tokenHeader, cacheDir string) []string {
osArgs := []string{"trivy", "server", "--skip-update", "--cache-dir", cacheDir, "--listen", addr}
if token != "" {
osArgs = append(osArgs, []string{"--token", token}...)
osArgs = append(osArgs, []string{"--token", token, "--token-header", tokenHeader}...)
}
return osArgs
}
func setupClient(t *testing.T, ignoreUnfixed bool, severity, ignoreIDs []string,
addr, token, input, cacheDir, golden string) ([]string, string, func()) {
addr, token, tokenHeader, input, cacheDir, golden string) ([]string, string, func()) {
t.Helper()
osArgs := []string{"trivy", "client", "--cache-dir", cacheDir,
"--format", "json", "--remote", "http://" + addr}
@@ -355,7 +413,7 @@ func setupClient(t *testing.T, ignoreUnfixed bool, severity, ignoreIDs []string,
osArgs = append(osArgs, []string{"--ignorefile", trivyIgnore}...)
}
if token != "" {
osArgs = append(osArgs, []string{"--token", token}...)
osArgs = append(osArgs, []string{"--token", token, "--token-header", tokenHeader}...)
}
if input != "" {
osArgs = append(osArgs, []string{"--input", input}...)

View File

@@ -0,0 +1,318 @@
// +build integration
package integration
import (
"context"
"io/ioutil"
"os"
"strings"
"testing"
"github.com/stretchr/testify/require"
"github.com/aquasecurity/trivy/internal"
"github.com/docker/docker/api/types"
"github.com/docker/docker/client"
"github.com/stretchr/testify/assert"
)
func TestRun_WithDockerEngine(t *testing.T) {
testCases := []struct {
name string
imageTag string
invalidImage bool
ignoreUnfixed bool
severity []string
ignoreIDs []string
testfile string
expectedOutputFile string
expectedError string
}{
{
name: "happy path, valid image path, alpine:3.10",
imageTag: "alpine:3.10",
expectedOutputFile: "testdata/alpine-310.json.golden",
testfile: "testdata/fixtures/alpine-310.tar.gz",
},
{
name: "happy path, valid image path, alpine:3.10, ignore unfixed",
ignoreUnfixed: true,
imageTag: "alpine:3.10",
expectedOutputFile: "testdata/alpine-310-ignore-unfixed.json.golden",
testfile: "testdata/fixtures/alpine-310.tar.gz",
},
{
name: "happy path, valid image path, alpine:3.10, ignore unfixed, with medium and high severity",
ignoreUnfixed: true,
severity: []string{"MEDIUM", "HIGH"},
imageTag: "alpine:3.10",
expectedOutputFile: "testdata/alpine-310-medium-high.json.golden",
testfile: "testdata/fixtures/alpine-310.tar.gz",
},
{
name: "happy path, valid image path, alpine:3.10, with .trivyignore",
imageTag: "alpine:3.10",
ignoreIDs: []string{"CVE-2019-1549", "CVE-2019-1563"},
expectedOutputFile: "testdata/alpine-310-ignore-cveids.json.golden",
testfile: "testdata/fixtures/alpine-310.tar.gz",
},
{
name: "happy path, valid image path, alpine:3.9",
imageTag: "alpine:3.9",
expectedOutputFile: "testdata/alpine-39.json.golden",
testfile: "testdata/fixtures/alpine-39.tar.gz",
},
{
name: "happy path, valid image path, amazonlinux:1",
imageTag: "amazonlinux:1",
expectedOutputFile: "testdata/amazon-1.json.golden",
testfile: "testdata/fixtures/amazon-1.tar.gz",
},
{
name: "happy path, valid image path, amazonlinux:2",
imageTag: "amazonlinux:2",
expectedOutputFile: "testdata/amazon-2.json.golden",
testfile: "testdata/fixtures/amazon-2.tar.gz",
},
{
name: "happy path, valid image path, centos:6",
imageTag: "centos:6",
expectedOutputFile: "testdata/centos-6.json.golden",
testfile: "testdata/fixtures/centos-6.tar.gz",
},
{
name: "happy path, valid image path, centos:6",
imageTag: "centos:6",
expectedOutputFile: "testdata/centos-6.json.golden",
testfile: "testdata/fixtures/centos-6.tar.gz",
},
{
name: "happy path, valid image path, centos:7",
imageTag: "centos:7",
expectedOutputFile: "testdata/centos-7.json.golden",
testfile: "testdata/fixtures/centos-7.tar.gz",
},
{
name: "happy path, valid image path, centos:7, with --ignore-unfixed option",
imageTag: "centos:7",
ignoreUnfixed: true,
expectedOutputFile: "testdata/centos-7-ignore-unfixed.json.golden",
testfile: "testdata/fixtures/centos-7.tar.gz",
},
{
name: "happy path, valid image path, centos:7, with --ignore-unfixed option, with low and high severity",
imageTag: "centos:7",
ignoreUnfixed: true,
severity: []string{"LOW", "HIGH"},
expectedOutputFile: "testdata/centos-7-low-high.json.golden",
testfile: "testdata/fixtures/centos-7.tar.gz",
},
{
name: "happy path, valid image path, debian:buster",
imageTag: "debian:buster",
expectedOutputFile: "testdata/debian-buster.json.golden",
testfile: "testdata/fixtures/debian-buster.tar.gz",
},
{
name: "happy path, valid image path, debian:buster, with --ignore-unfixed option",
ignoreUnfixed: true,
imageTag: "debian:buster",
expectedOutputFile: "testdata/debian-buster-ignore-unfixed.json.golden",
testfile: "testdata/fixtures/debian-buster.tar.gz",
},
{
name: "happy path, valid image path, debian:stretch",
imageTag: "debian:stretch",
expectedOutputFile: "testdata/debian-stretch.json.golden",
testfile: "testdata/fixtures/debian-stretch.tar.gz",
},
{
name: "happy path, valid image path, distroless:base",
imageTag: "gcr.io/distroless/base:latest",
expectedOutputFile: "testdata/distroless-base.json.golden",
testfile: "testdata/fixtures/distroless-base.tar.gz",
},
{
name: "happy path, valid image path, distroless:base",
imageTag: "gcr.io/distroless/base:latest",
expectedOutputFile: "testdata/distroless-base.json.golden",
testfile: "testdata/fixtures/distroless-base.tar.gz",
},
{
name: "happy path, valid image path, distroless:base, with --ignore-unfixed option",
imageTag: "gcr.io/distroless/base:latest",
ignoreUnfixed: true,
expectedOutputFile: "testdata/distroless-base-ignore-unfixed.json.golden",
testfile: "testdata/fixtures/distroless-base.tar.gz",
},
{
name: "happy path, valid image path, distroless:python2.7",
imageTag: "gcr.io/distroless/python2.7:latest",
expectedOutputFile: "testdata/distroless-python27.json.golden",
testfile: "testdata/fixtures/distroless-python27.tar.gz",
},
{
name: "happy path, valid image path, oraclelinux:6-slim",
imageTag: "oraclelinux:6-slim",
expectedOutputFile: "testdata/oraclelinux-6-slim.json.golden",
testfile: "testdata/fixtures/oraclelinux-6-slim.tar.gz",
},
{
name: "happy path, valid image path, oraclelinux:7-slim",
imageTag: "oraclelinux:7-slim",
expectedOutputFile: "testdata/oraclelinux-7-slim.json.golden",
testfile: "testdata/fixtures/oraclelinux-7-slim.tar.gz",
},
{
name: "happy path, valid image path, oraclelinux:8-slim",
imageTag: "oraclelinux:8-slim",
expectedOutputFile: "testdata/oraclelinux-8-slim.json.golden",
testfile: "testdata/fixtures/oraclelinux-8-slim.tar.gz",
},
{
name: "happy path, valid image path, ubuntu:16.04",
imageTag: "ubuntu:16.04",
expectedOutputFile: "testdata/ubuntu-1604.json.golden",
testfile: "testdata/fixtures/ubuntu-1604.tar.gz",
},
{
name: "happy path, valid image path, ubuntu:18.04",
imageTag: "ubuntu:18.04",
expectedOutputFile: "testdata/ubuntu-1804.json.golden",
testfile: "testdata/fixtures/ubuntu-1804.tar.gz",
},
{
name: "happy path, valid image path, ubuntu:18.04, with --ignore-unfixed option",
imageTag: "ubuntu:18.04",
ignoreUnfixed: true,
expectedOutputFile: "testdata/ubuntu-1804-ignore-unfixed.json.golden",
testfile: "testdata/fixtures/ubuntu-1804.tar.gz",
},
{
name: "happy path, valid image path, registry.redhat.io/ubi7",
imageTag: "registry.redhat.io/ubi7",
expectedOutputFile: "testdata/ubi-7.json.golden",
testfile: "testdata/fixtures/ubi-7.tar.gz",
},
{
name: "happy path, valid image path, opensuse leap 15.1",
imageTag: "opensuse/leap:latest",
expectedOutputFile: "testdata/opensuse-leap-151.json.golden",
testfile: "testdata/fixtures/opensuse-leap-151.tar.gz",
},
{
name: "happy path, valid image path, opensuse leap 42.3",
imageTag: "opensuse/leap:42.3",
expectedOutputFile: "testdata/opensuse-leap-423.json.golden",
testfile: "testdata/fixtures/opensuse-leap-423.tar.gz",
},
{
name: "happy path, valid image path, photon 1.0",
imageTag: "photon:1.0-20190823",
expectedOutputFile: "testdata/photon-10.json.golden",
testfile: "testdata/fixtures/photon-10.tar.gz",
},
{
name: "happy path, valid image path, photon 2.0",
imageTag: "photon:2.0-20190726",
expectedOutputFile: "testdata/photon-20.json.golden",
testfile: "testdata/fixtures/photon-20.tar.gz",
},
{
name: "happy path, valid image path, photon 3.0",
imageTag: "photon:3.0-20190823",
expectedOutputFile: "testdata/photon-30.json.golden",
testfile: "testdata/fixtures/photon-30.tar.gz",
},
{
name: "sad path, invalid image",
invalidImage: true,
testfile: "badimage:latest",
expectedError: "error in image scan: failed to analyze image: failed to extract files: failed to get the v2 manifest: Get https://registry-1.docker.io/v2/library/badimage/manifests/latest: http: non-successful response (status=401 body=\"{\\\"errors\\\":[{\\\"code\\\":\\\"UNAUTHORIZED\\\",\\\"message\\\":\\\"authentication required\\\",\\\"detail\\\":[{\\\"Type\\\":\\\"repository\\\",\\\"Class\\\":\\\"\\\",\\\"Name\\\":\\\"library/badimage\\\",\\\"Action\\\":\\\"pull\\\"}]}]}\\n\")",
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
// Copy DB file
cacheDir := gunzipDB()
defer os.RemoveAll(cacheDir)
ctx := context.Background()
defer ctx.Done()
cli, err := client.NewClientWithOpts(client.FromEnv)
require.NoError(t, err, tc.name)
if !tc.invalidImage {
testfile, err := os.Open(tc.testfile)
require.NoError(t, err, tc.name)
// ensure image doesnt already exists
_, _ = cli.ImageRemove(ctx, tc.testfile, types.ImageRemoveOptions{
Force: true,
PruneChildren: true,
})
// load image into docker engine
_, err = cli.ImageLoad(ctx, testfile, true)
require.NoError(t, err, tc.name)
// tag our image to something unique
err = cli.ImageTag(ctx, tc.imageTag, tc.testfile)
require.NoError(t, err, tc.name)
}
of, err := ioutil.TempFile("", "integration-docker-engine-output-file-*")
require.NoError(t, err, tc.name)
defer os.Remove(of.Name())
// run trivy
app := internal.NewApp("dev")
trivyArgs := []string{"trivy", "--skip-update", "--cache-dir", cacheDir, "--format=json"}
if tc.ignoreUnfixed {
trivyArgs = append(trivyArgs, "--ignore-unfixed")
}
if len(tc.severity) != 0 {
trivyArgs = append(trivyArgs,
[]string{"--severity", strings.Join(tc.severity, ",")}...,
)
}
if len(tc.ignoreIDs) != 0 {
trivyIgnore := ".trivyignore"
err := ioutil.WriteFile(trivyIgnore, []byte(strings.Join(tc.ignoreIDs, "\n")), 0444)
assert.NoError(t, err, "failed to write .trivyignore")
defer os.Remove(trivyIgnore)
}
if !tc.invalidImage {
trivyArgs = append(trivyArgs, "--output", of.Name())
}
trivyArgs = append(trivyArgs, tc.testfile)
err = app.Run(trivyArgs)
switch {
case tc.expectedError != "":
assert.Equal(t, tc.expectedError, err.Error(), tc.name)
default:
assert.NoError(t, err, tc.name)
}
if !tc.invalidImage {
// check for vulnerability output info
got, err := ioutil.ReadAll(of)
assert.NoError(t, err, tc.name)
want, err := ioutil.ReadFile(tc.expectedOutputFile)
assert.NoError(t, err, tc.name)
assert.JSONEq(t, string(want), string(got), tc.name)
// cleanup
_, err = cli.ImageRemove(ctx, tc.testfile, types.ImageRemoveOptions{
Force: true,
PruneChildren: true,
})
assert.NoError(t, err, tc.name)
}
})
}
}

View File

@@ -291,6 +291,56 @@ func TestRun_WithTar(t *testing.T) {
},
golden: "testdata/oraclelinux-8-slim.json.golden",
},
{
name: "opensuse leap 15.1 integration",
testArgs: args{
Version: "dev",
SkipUpdate: true,
Format: "json",
Input: "testdata/fixtures/opensuse-leap-151.tar.gz",
},
golden: "testdata/opensuse-leap-151.json.golden",
},
{
name: "opensuse leap 42.3 integration",
testArgs: args{
Version: "dev",
SkipUpdate: true,
Format: "json",
Input: "testdata/fixtures/opensuse-leap-423.tar.gz",
},
golden: "testdata/opensuse-leap-423.json.golden",
},
{
name: "photon 1.0 integration",
testArgs: args{
Version: "dev",
SkipUpdate: true,
Format: "json",
Input: "testdata/fixtures/photon-10.tar.gz",
},
golden: "testdata/photon-10.json.golden",
},
{
name: "photon 2.0 integration",
testArgs: args{
Version: "dev",
SkipUpdate: true,
Format: "json",
Input: "testdata/fixtures/photon-20.tar.gz",
},
golden: "testdata/photon-20.json.golden",
},
{
name: "photon 3.0 integration",
testArgs: args{
Version: "dev",
SkipUpdate: true,
Format: "json",
Input: "testdata/fixtures/photon-30.tar.gz",
},
golden: "testdata/photon-30.json.golden",
},
}
for _, c := range cases {

View File

@@ -12628,6 +12628,32 @@
"https://utcc.utoronto.ca/~cks/space/blog/sysadmin/TarFindingTruncateBug"
]
},
{
"VulnerabilityID": "CVE-2019-12735",
"PkgName": "vim-minimal",
"InstalledVersion": "2:7.4.629-5.el6_8.1",
"FixedVersion": "2:7.4.629-5.el6_10.2",
"Title": "vim/neovim: ':source!' command allows arbitrary command execution via modelines",
"Description": "getchar.c in Vim before 8.1.1365 and Neovim before 0.3.6 allows remote attackers to execute arbitrary OS commands via the :source! command in a modeline, as demonstrated by execute in Vim, and assert_fails or nvim_input in Neovim.",
"Severity": "CRITICAL",
"References": [
"http://lists.opensuse.org/opensuse-security-announce/2019-06/msg00031.html",
"http://lists.opensuse.org/opensuse-security-announce/2019-06/msg00036.html",
"http://lists.opensuse.org/opensuse-security-announce/2019-06/msg00037.html",
"http://www.securityfocus.com/bid/108724",
"https://bugs.debian.org/930020",
"https://bugs.debian.org/930024",
"https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-12735",
"https://github.com/neovim/neovim/pull/10082",
"https://github.com/numirias/security/blob/master/doc/2019-06-04_ace-vim-neovim.md",
"https://github.com/vim/vim/commit/53575521406739cf20bbe4e384d88e7dca11f040",
"https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/2BMDSHTF754TITC6AQJPCS5IRIDMMIM7/",
"https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/TRIRBC2YRGKPAWVRMZS4SZTGGCVRVZPR/",
"https://usn.ubuntu.com/4016-1/",
"https://usn.ubuntu.com/4016-2/",
"https://www.debian.org/security/2019/dsa-4467"
]
},
{
"VulnerabilityID": "CVE-2017-5953",
"PkgName": "vim-minimal",

View File

@@ -112,6 +112,32 @@
"https://usn.ubuntu.com/3816-1/",
"https://www.exploit-db.com/exploits/45714/"
]
},
{
"VulnerabilityID": "CVE-2019-12735",
"PkgName": "vim-minimal",
"InstalledVersion": "2:7.4.160-5.el7",
"FixedVersion": "2:7.4.160-6.el7_6",
"Title": "vim/neovim: ':source!' command allows arbitrary command execution via modelines",
"Description": "getchar.c in Vim before 8.1.1365 and Neovim before 0.3.6 allows remote attackers to execute arbitrary OS commands via the :source! command in a modeline, as demonstrated by execute in Vim, and assert_fails or nvim_input in Neovim.",
"Severity": "CRITICAL",
"References": [
"http://lists.opensuse.org/opensuse-security-announce/2019-06/msg00031.html",
"http://lists.opensuse.org/opensuse-security-announce/2019-06/msg00036.html",
"http://lists.opensuse.org/opensuse-security-announce/2019-06/msg00037.html",
"http://www.securityfocus.com/bid/108724",
"https://bugs.debian.org/930020",
"https://bugs.debian.org/930024",
"https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-12735",
"https://github.com/neovim/neovim/pull/10082",
"https://github.com/numirias/security/blob/master/doc/2019-06-04_ace-vim-neovim.md",
"https://github.com/vim/vim/commit/53575521406739cf20bbe4e384d88e7dca11f040",
"https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/2BMDSHTF754TITC6AQJPCS5IRIDMMIM7/",
"https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/TRIRBC2YRGKPAWVRMZS4SZTGGCVRVZPR/",
"https://usn.ubuntu.com/4016-1/",
"https://usn.ubuntu.com/4016-2/",
"https://www.debian.org/security/2019/dsa-4467"
]
}
]
}

View File

@@ -1708,6 +1708,32 @@
"https://lists.apache.org/thread.html/5960a34a524848cd722fd7ab7e2227eac10107b0f90d9d1e9c3caa74@%3Cuser.cassandra.apache.org%3E",
"https://security.netapp.com/advisory/ntap-20190307-0007/"
]
},
{
"VulnerabilityID": "CVE-2019-12735",
"PkgName": "vim-minimal",
"InstalledVersion": "2:7.4.160-5.el7",
"FixedVersion": "2:7.4.160-6.el7_6",
"Title": "vim/neovim: ':source!' command allows arbitrary command execution via modelines",
"Description": "getchar.c in Vim before 8.1.1365 and Neovim before 0.3.6 allows remote attackers to execute arbitrary OS commands via the :source! command in a modeline, as demonstrated by execute in Vim, and assert_fails or nvim_input in Neovim.",
"Severity": "CRITICAL",
"References": [
"http://lists.opensuse.org/opensuse-security-announce/2019-06/msg00031.html",
"http://lists.opensuse.org/opensuse-security-announce/2019-06/msg00036.html",
"http://lists.opensuse.org/opensuse-security-announce/2019-06/msg00037.html",
"http://www.securityfocus.com/bid/108724",
"https://bugs.debian.org/930020",
"https://bugs.debian.org/930024",
"https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-12735",
"https://github.com/neovim/neovim/pull/10082",
"https://github.com/numirias/security/blob/master/doc/2019-06-04_ace-vim-neovim.md",
"https://github.com/vim/vim/commit/53575521406739cf20bbe4e384d88e7dca11f040",
"https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/2BMDSHTF754TITC6AQJPCS5IRIDMMIM7/",
"https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/TRIRBC2YRGKPAWVRMZS4SZTGGCVRVZPR/",
"https://usn.ubuntu.com/4016-1/",
"https://usn.ubuntu.com/4016-2/",
"https://www.debian.org/security/2019/dsa-4467"
]
}
]
}

View File

@@ -11849,6 +11849,32 @@
"https://www.kernel.org/pub/linux/utils/util-linux/v2.27/v2.27-ReleaseNotes"
]
},
{
"VulnerabilityID": "CVE-2019-12735",
"PkgName": "vim-minimal",
"InstalledVersion": "2:7.4.160-5.el7",
"FixedVersion": "2:7.4.160-6.el7_6",
"Title": "vim/neovim: ':source!' command allows arbitrary command execution via modelines",
"Description": "getchar.c in Vim before 8.1.1365 and Neovim before 0.3.6 allows remote attackers to execute arbitrary OS commands via the :source! command in a modeline, as demonstrated by execute in Vim, and assert_fails or nvim_input in Neovim.",
"Severity": "CRITICAL",
"References": [
"http://lists.opensuse.org/opensuse-security-announce/2019-06/msg00031.html",
"http://lists.opensuse.org/opensuse-security-announce/2019-06/msg00036.html",
"http://lists.opensuse.org/opensuse-security-announce/2019-06/msg00037.html",
"http://www.securityfocus.com/bid/108724",
"https://bugs.debian.org/930020",
"https://bugs.debian.org/930024",
"https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-12735",
"https://github.com/neovim/neovim/pull/10082",
"https://github.com/numirias/security/blob/master/doc/2019-06-04_ace-vim-neovim.md",
"https://github.com/vim/vim/commit/53575521406739cf20bbe4e384d88e7dca11f040",
"https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/2BMDSHTF754TITC6AQJPCS5IRIDMMIM7/",
"https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/TRIRBC2YRGKPAWVRMZS4SZTGGCVRVZPR/",
"https://usn.ubuntu.com/4016-1/",
"https://usn.ubuntu.com/4016-2/",
"https://www.debian.org/security/2019/dsa-4467"
]
},
{
"VulnerabilityID": "CVE-2017-5953",
"PkgName": "vim-minimal",

View File

@@ -0,0 +1,103 @@
[
{
"Target": "testdata/fixtures/opensuse-leap-151.tar.gz (opensuse.leap 15.1)",
"Vulnerabilities": [
{
"VulnerabilityID": "openSUSE-SU-2019:2596-1",
"PkgName": "cpio",
"InstalledVersion": "2.12-lp151.2.68",
"FixedVersion": "2.12-lp151.3.3.1",
"Title": "Security update for cpio",
"Severity": "MEDIUM",
"References": [
"http://lists.opensuse.org/opensuse-security-announce/2019-11/msg00076.html",
"https://www.suse.com/support/security/rating/"
]
},
{
"VulnerabilityID": "openSUSE-SU-2019:2611-1",
"PkgName": "libidn2-0",
"InstalledVersion": "2.0.4-lp151.2.3",
"FixedVersion": "2.2.0-lp151.3.3.1",
"Title": "Security update for libidn2",
"Severity": "MEDIUM",
"References": [
"http://lists.opensuse.org/opensuse-security-announce/2019-12/msg00009.html",
"https://www.suse.com/support/security/rating/"
]
},
{
"VulnerabilityID": "openSUSE-SU-2019:2551-1",
"PkgName": "libncurses6",
"InstalledVersion": "6.1-lp151.5.41",
"FixedVersion": "6.1-lp151.6.3.1",
"Title": "Security update for ncurses",
"Severity": "MEDIUM",
"References": [
"http://lists.opensuse.org/opensuse-security-announce/2019-11/msg00059.html",
"https://www.suse.com/support/security/rating/"
]
},
{
"VulnerabilityID": "openSUSE-SU-2019:2689-1",
"PkgName": "libssh4",
"InstalledVersion": "0.8.7-lp151.2.3.1",
"FixedVersion": "0.8.7-lp151.2.6.1",
"Title": "Security update for libssh",
"Severity": "MEDIUM",
"References": [
"http://lists.opensuse.org/opensuse-security-announce/2019-12/msg00033.html",
"https://www.suse.com/support/security/rating/"
]
},
{
"VulnerabilityID": "openSUSE-SU-2019:2612-1",
"PkgName": "libxml2-2",
"InstalledVersion": "2.9.7-lp151.5.3.1",
"FixedVersion": "2.9.7-lp151.5.6.1",
"Title": "Security update for libxml2",
"Severity": "UNKNOWN",
"References": [
"http://lists.opensuse.org/opensuse-security-announce/2019-12/msg00010.html",
"https://www.suse.com/support/security/rating/"
]
},
{
"VulnerabilityID": "openSUSE-SU-2019:2551-1",
"PkgName": "ncurses-utils",
"InstalledVersion": "6.1-lp151.5.41",
"FixedVersion": "6.1-lp151.6.3.1",
"Title": "Security update for ncurses",
"Severity": "MEDIUM",
"References": [
"http://lists.opensuse.org/opensuse-security-announce/2019-11/msg00059.html",
"https://www.suse.com/support/security/rating/"
]
},
{
"VulnerabilityID": "openSUSE-SU-2019:2672-1",
"PkgName": "permissions",
"InstalledVersion": "20181116-lp151.4.6.1",
"FixedVersion": "20181116-lp151.4.9.1",
"Title": "Security update for permissions",
"Severity": "MEDIUM",
"References": [
"http://lists.opensuse.org/opensuse-security-announce/2019-12/msg00024.html",
"https://www.suse.com/support/security/rating/"
]
},
{
"VulnerabilityID": "openSUSE-SU-2019:2551-1",
"PkgName": "terminfo-base",
"InstalledVersion": "6.1-lp151.5.41",
"FixedVersion": "6.1-lp151.6.3.1",
"Title": "Security update for ncurses",
"Severity": "MEDIUM",
"References": [
"http://lists.opensuse.org/opensuse-security-announce/2019-11/msg00059.html",
"https://www.suse.com/support/security/rating/"
]
}
]
}
]

View File

@@ -0,0 +1,6 @@
[
{
"Target": "testdata/fixtures/opensuse-leap-423.tar.gz (opensuse.leap 42.3)",
"Vulnerabilities": null
}
]

View File

@@ -162,5 +162,4 @@
}
]
}
]
]

View File

@@ -855,5 +855,4 @@
}
]
}
]
]

View File

@@ -3,4 +3,4 @@
"Target": "testdata/fixtures/oraclelinux-8-slim.tar.gz (oracle 8.0)",
"Vulnerabilities": null
}
]
]

View File

@@ -0,0 +1,61 @@
[
{
"Target": "testdata/fixtures/photon-10.tar.gz (photon 1.0)",
"Vulnerabilities": [
{
"VulnerabilityID": "CVE-2012-6711",
"PkgName": "bash",
"InstalledVersion": "4.3.48-3.ph1",
"FixedVersion": "4.3.48-4.ph1",
"Title": "bash: heap-based buffer overflow during echo of unsupported characters",
"Description": "A heap-based buffer overflow exists in GNU Bash before 4.3 when wide characters, not supported by the current locale set in the LC_CTYPE environment variable, are printed through the echo built-in function. A local attacker, who can provide data to print through the \"echo -e\" built-in function, may use this flaw to crash a script or execute code with the privileges of the bash process. This occurs because ansicstr() in lib/sh/strtrans.c mishandles u32cconv().",
"Severity": "MEDIUM",
"References": [
"http://git.savannah.gnu.org/cgit/bash.git/commit/?h=devel\u0026id=863d31ae775d56b785dc5b0105b6d251515d81d5",
"http://www.securityfocus.com/bid/108824",
"https://bugzilla.redhat.com/show_bug.cgi?id=1721071",
"https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2012-6711"
]
},
{
"VulnerabilityID": "CVE-2019-1563",
"PkgName": "openssl",
"InstalledVersion": "1.0.2s-1.ph1",
"FixedVersion": "1.0.2t-1.ph1",
"Title": "openssl: information disclosure in PKCS7_dataDecode and CMS_decrypt_set1_pkey",
"Description": "In situations where an attacker receives automated notification of the success or failure of a decryption attempt an attacker, after sending a very large number of messages to be decrypted, can recover a CMS/PKCS7 transported encryption key or decrypt any RSA encrypted message that was encrypted with the public RSA key, using a Bleichenbacher padding oracle attack. Applications are not affected if they use a certificate together with the private RSA key to the CMS_decrypt or PKCS7_decrypt functions to select the correct recipient info to decrypt. Fixed in OpenSSL 1.1.1d (Affected 1.1.1-1.1.1c). Fixed in OpenSSL 1.1.0l (Affected 1.1.0-1.1.0k). Fixed in OpenSSL 1.0.2t (Affected 1.0.2-1.0.2s).",
"Severity": "MEDIUM",
"References": [
"http://packetstormsecurity.com/files/154467/Slackware-Security-Advisory-openssl-Updates.html",
"https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-1563",
"https://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff;h=08229ad838c50f644d7e928e2eef147b4308ad64",
"https://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff;h=631f94db0065c78181ca9ba5546ebc8bb3884b97",
"https://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff;h=e21f8cf78a125cd3c8c0d1a1a6c8bb0b901f893f",
"https://seclists.org/bugtraq/2019/Sep/25",
"https://security.netapp.com/advisory/ntap-20190919-0002/",
"https://www.openssl.org/news/secadv/20190910.txt"
]
},
{
"VulnerabilityID": "CVE-2019-1547",
"PkgName": "openssl",
"InstalledVersion": "1.0.2s-1.ph1",
"FixedVersion": "1.0.2t-1.ph1",
"Title": "openssl: side-channel weak encryption vulnerability",
"Description": "Normally in OpenSSL EC groups always have a co-factor present and this is used in side channel resistant code paths. However, in some cases, it is possible to construct a group using explicit parameters (instead of using a named curve). In those cases it is possible that such a group does not have the cofactor present. This can occur even where all the parameters match a known named curve. If such a curve is used then OpenSSL falls back to non-side channel resistant code paths which may result in full key recovery during an ECDSA signature operation. In order to be vulnerable an attacker would have to have the ability to time the creation of a large number of signatures where explicit parameters with no co-factor present are in use by an application using libcrypto. For the avoidance of doubt libssl is not vulnerable because explicit parameters are never used. Fixed in OpenSSL 1.1.1d (Affected 1.1.1-1.1.1c). Fixed in OpenSSL 1.1.0l (Affected 1.1.0-1.1.0k). Fixed in OpenSSL 1.0.2t (Affected 1.0.2-1.0.2s).",
"Severity": "LOW",
"References": [
"http://packetstormsecurity.com/files/154467/Slackware-Security-Advisory-openssl-Updates.html",
"https://arxiv.org/abs/1909.01785",
"https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-1547",
"https://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff;h=21c856b75d81eff61aa63b4f036bb64a85bf6d46",
"https://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff;h=30c22fa8b1d840036b8e203585738df62a03cec8",
"https://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff;h=7c1709c2da5414f5b6133d00a03fc8c5bf996c7a",
"https://seclists.org/bugtraq/2019/Sep/25",
"https://security.netapp.com/advisory/ntap-20190919-0002/",
"https://www.openssl.org/news/secadv/20190910.txt"
]
}
]
}
]

View File

@@ -0,0 +1,227 @@
[
{
"Target": "testdata/fixtures/photon-20.tar.gz (photon 2.0)",
"Vulnerabilities": [
{
"VulnerabilityID": "CVE-2019-5481",
"PkgName": "curl",
"InstalledVersion": "7.59.0-7.ph2",
"FixedVersion": "7.59.0-9.ph2",
"Title": "curl: double free due to subsequent call of realloc()",
"Description": "Double-free vulnerability in the FTP-kerberos code in cURL 7.52.0 to 7.65.3.",
"Severity": "HIGH",
"References": [
"http://lists.opensuse.org/opensuse-security-announce/2019-09/msg00048.html",
"http://lists.opensuse.org/opensuse-security-announce/2019-09/msg00055.html",
"https://curl.haxx.se/docs/CVE-2019-5481.html",
"https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/RGDVKSLY5JUNJRLYRUA6CXGQ2LM63XC3/",
"https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/UA7KDM2WPM5CJDDGOEGFV6SSGD2J7RNT/"
]
},
{
"VulnerabilityID": "CVE-2019-5482",
"PkgName": "curl",
"InstalledVersion": "7.59.0-7.ph2",
"FixedVersion": "7.59.0-9.ph2",
"Title": "curl: heap buffer overflow in function tftp_receive_packet()",
"Description": "Heap buffer overflow in the TFTP protocol handler in cURL 7.19.4 to 7.65.3.",
"Severity": "HIGH",
"References": [
"http://lists.opensuse.org/opensuse-security-announce/2019-09/msg00048.html",
"http://lists.opensuse.org/opensuse-security-announce/2019-09/msg00055.html",
"https://curl.haxx.se/docs/CVE-2019-5482.html",
"https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-5482",
"https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/RGDVKSLY5JUNJRLYRUA6CXGQ2LM63XC3/",
"https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/UA7KDM2WPM5CJDDGOEGFV6SSGD2J7RNT/"
]
},
{
"VulnerabilityID": "CVE-2018-16890",
"PkgName": "curl",
"InstalledVersion": "7.59.0-7.ph2",
"FixedVersion": "7.59.0-8.ph2",
"Title": "curl: NTLM type-2 heap out-of-bounds buffer read",
"Description": "libcurl versions from 7.36.0 to before 7.64.0 is vulnerable to a heap buffer out-of-bounds read. The function handling incoming NTLM type-2 messages (`lib/vauth/ntlm.c:ntlm_decode_type2_target`) does not validate incoming data correctly and is subject to an integer overflow vulnerability. Using that overflow, a malicious or broken NTLM server could trick libcurl to accept a bad length + offset combination that would lead to a buffer read out-of-bounds.",
"Severity": "MEDIUM",
"References": [
"http://www.securityfocus.com/bid/106947",
"https://bugzilla.redhat.com/show_bug.cgi?id=CVE-2018-16890",
"https://cert-portal.siemens.com/productcert/pdf/ssa-436177.pdf",
"https://curl.haxx.se/docs/CVE-2018-16890.html",
"https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-16890",
"https://lists.apache.org/thread.html/8338a0f605bdbb3a6098bb76f666a95fc2b2f53f37fa1ecc89f1146f@%3Cdevnull.infra.apache.org%3E",
"https://security.netapp.com/advisory/ntap-20190315-0001/",
"https://usn.ubuntu.com/3882-1/",
"https://www.debian.org/security/2019/dsa-4386",
"https://www.oracle.com/technetwork/security-advisory/cpuapr2019-5072813.html",
"https://www.oracle.com/technetwork/security-advisory/cpujul2019-5072835.html"
]
},
{
"VulnerabilityID": "CVE-2019-5481",
"PkgName": "curl-libs",
"InstalledVersion": "7.59.0-7.ph2",
"FixedVersion": "7.59.0-9.ph2",
"Title": "curl: double free due to subsequent call of realloc()",
"Description": "Double-free vulnerability in the FTP-kerberos code in cURL 7.52.0 to 7.65.3.",
"Severity": "HIGH",
"References": [
"http://lists.opensuse.org/opensuse-security-announce/2019-09/msg00048.html",
"http://lists.opensuse.org/opensuse-security-announce/2019-09/msg00055.html",
"https://curl.haxx.se/docs/CVE-2019-5481.html",
"https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/RGDVKSLY5JUNJRLYRUA6CXGQ2LM63XC3/",
"https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/UA7KDM2WPM5CJDDGOEGFV6SSGD2J7RNT/"
]
},
{
"VulnerabilityID": "CVE-2019-5482",
"PkgName": "curl-libs",
"InstalledVersion": "7.59.0-7.ph2",
"FixedVersion": "7.59.0-9.ph2",
"Title": "curl: heap buffer overflow in function tftp_receive_packet()",
"Description": "Heap buffer overflow in the TFTP protocol handler in cURL 7.19.4 to 7.65.3.",
"Severity": "HIGH",
"References": [
"http://lists.opensuse.org/opensuse-security-announce/2019-09/msg00048.html",
"http://lists.opensuse.org/opensuse-security-announce/2019-09/msg00055.html",
"https://curl.haxx.se/docs/CVE-2019-5482.html",
"https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-5482",
"https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/RGDVKSLY5JUNJRLYRUA6CXGQ2LM63XC3/",
"https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/UA7KDM2WPM5CJDDGOEGFV6SSGD2J7RNT/"
]
},
{
"VulnerabilityID": "CVE-2018-16890",
"PkgName": "curl-libs",
"InstalledVersion": "7.59.0-7.ph2",
"FixedVersion": "7.59.0-8.ph2",
"Title": "curl: NTLM type-2 heap out-of-bounds buffer read",
"Description": "libcurl versions from 7.36.0 to before 7.64.0 is vulnerable to a heap buffer out-of-bounds read. The function handling incoming NTLM type-2 messages (`lib/vauth/ntlm.c:ntlm_decode_type2_target`) does not validate incoming data correctly and is subject to an integer overflow vulnerability. Using that overflow, a malicious or broken NTLM server could trick libcurl to accept a bad length + offset combination that would lead to a buffer read out-of-bounds.",
"Severity": "MEDIUM",
"References": [
"http://www.securityfocus.com/bid/106947",
"https://bugzilla.redhat.com/show_bug.cgi?id=CVE-2018-16890",
"https://cert-portal.siemens.com/productcert/pdf/ssa-436177.pdf",
"https://curl.haxx.se/docs/CVE-2018-16890.html",
"https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-16890",
"https://lists.apache.org/thread.html/8338a0f605bdbb3a6098bb76f666a95fc2b2f53f37fa1ecc89f1146f@%3Cdevnull.infra.apache.org%3E",
"https://security.netapp.com/advisory/ntap-20190315-0001/",
"https://usn.ubuntu.com/3882-1/",
"https://www.debian.org/security/2019/dsa-4386",
"https://www.oracle.com/technetwork/security-advisory/cpuapr2019-5072813.html",
"https://www.oracle.com/technetwork/security-advisory/cpujul2019-5072835.html"
]
},
{
"VulnerabilityID": "CVE-2019-5094",
"PkgName": "e2fsprogs-libs",
"InstalledVersion": "1.43.4-2.ph2",
"FixedVersion": "1.43.4-3.ph2",
"Description": "An exploitable code execution vulnerability exists in the quota file functionality of E2fsprogs 1.45.3. A specially crafted ext4 partition can cause an out-of-bounds write on the heap, resulting in code execution. An attacker can corrupt a partition to trigger this vulnerability.",
"Severity": "MEDIUM",
"References": [
"https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-5094",
"https://lists.debian.org/debian-lts-announce/2019/09/msg00029.html",
"https://seclists.org/bugtraq/2019/Sep/58",
"https://talosintelligence.com/vulnerability_reports/TALOS-2019-0887",
"https://usn.ubuntu.com/4142-2/",
"https://www.debian.org/security/2019/dsa-4535"
]
},
{
"VulnerabilityID": "CVE-2018-20843",
"PkgName": "expat-libs",
"InstalledVersion": "2.2.4-1.ph2",
"FixedVersion": "2.2.4-2.ph2",
"Title": "expat: large number of colons in input makes parser consume high amount of resources, leading to DoS",
"Description": "In libexpat in Expat before 2.2.7, XML input including XML names that contain a large number of colons could make the XML parser consume a high amount of RAM and CPU resources while processing (enough to be usable for denial-of-service attacks).",
"Severity": "HIGH",
"References": [
"https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=5226",
"https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=931031",
"https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-20843",
"https://github.com/libexpat/libexpat/blob/R_2_2_7/expat/Changes",
"https://github.com/libexpat/libexpat/issues/186",
"https://github.com/libexpat/libexpat/pull/262",
"https://github.com/libexpat/libexpat/pull/262/commits/11f8838bf99ea0a6f0b76f9760c43704d00c4ff6",
"https://lists.debian.org/debian-lts-announce/2019/06/msg00028.html",
"https://seclists.org/bugtraq/2019/Jun/39",
"https://security.netapp.com/advisory/ntap-20190703-0001/",
"https://usn.ubuntu.com/4040-1/",
"https://usn.ubuntu.com/4040-2/",
"https://www.debian.org/security/2019/dsa-4472"
]
},
{
"VulnerabilityID": "CVE-2019-13115",
"PkgName": "libssh2",
"InstalledVersion": "1.8.2-1.ph2",
"FixedVersion": "1.9.0-1.ph2",
"Title": "libssh2: integer overflow in kex_method_diffie_hellman_group_exchange_sha256_key_exchange in kex.c leads to out-of-bounds write",
"Description": "In libssh2 before 1.9.0, kex_method_diffie_hellman_group_exchange_sha256_key_exchange in kex.c has an integer overflow that could lead to an out-of-bounds read in the way packets are read from the server. A remote attacker who compromises a SSH server may be able to disclose sensitive information or cause a denial of service condition on the client system when a user connects to the server. This is related to an _libssh2_check_length mistake, and is different from the various issues fixed in 1.8.1, such as CVE-2019-3855.",
"Severity": "MEDIUM",
"References": [
"https://blog.semmle.com/libssh2-integer-overflow/",
"https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-13115",
"https://github.com/libssh2/libssh2/compare/02ecf17...42d37aa",
"https://github.com/libssh2/libssh2/pull/350",
"https://libssh2.org/changes.html",
"https://lists.debian.org/debian-lts-announce/2019/07/msg00024.html"
]
},
{
"VulnerabilityID": "CVE-2019-1563",
"PkgName": "openssl",
"InstalledVersion": "1.0.2s-1.ph2",
"FixedVersion": "1.0.2t-1.ph2",
"Title": "openssl: information disclosure in PKCS7_dataDecode and CMS_decrypt_set1_pkey",
"Description": "In situations where an attacker receives automated notification of the success or failure of a decryption attempt an attacker, after sending a very large number of messages to be decrypted, can recover a CMS/PKCS7 transported encryption key or decrypt any RSA encrypted message that was encrypted with the public RSA key, using a Bleichenbacher padding oracle attack. Applications are not affected if they use a certificate together with the private RSA key to the CMS_decrypt or PKCS7_decrypt functions to select the correct recipient info to decrypt. Fixed in OpenSSL 1.1.1d (Affected 1.1.1-1.1.1c). Fixed in OpenSSL 1.1.0l (Affected 1.1.0-1.1.0k). Fixed in OpenSSL 1.0.2t (Affected 1.0.2-1.0.2s).",
"Severity": "MEDIUM",
"References": [
"http://packetstormsecurity.com/files/154467/Slackware-Security-Advisory-openssl-Updates.html",
"https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-1563",
"https://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff;h=08229ad838c50f644d7e928e2eef147b4308ad64",
"https://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff;h=631f94db0065c78181ca9ba5546ebc8bb3884b97",
"https://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff;h=e21f8cf78a125cd3c8c0d1a1a6c8bb0b901f893f",
"https://seclists.org/bugtraq/2019/Sep/25",
"https://security.netapp.com/advisory/ntap-20190919-0002/",
"https://www.openssl.org/news/secadv/20190910.txt"
]
},
{
"VulnerabilityID": "CVE-2019-1547",
"PkgName": "openssl",
"InstalledVersion": "1.0.2s-1.ph2",
"FixedVersion": "1.0.2t-1.ph2",
"Title": "openssl: side-channel weak encryption vulnerability",
"Description": "Normally in OpenSSL EC groups always have a co-factor present and this is used in side channel resistant code paths. However, in some cases, it is possible to construct a group using explicit parameters (instead of using a named curve). In those cases it is possible that such a group does not have the cofactor present. This can occur even where all the parameters match a known named curve. If such a curve is used then OpenSSL falls back to non-side channel resistant code paths which may result in full key recovery during an ECDSA signature operation. In order to be vulnerable an attacker would have to have the ability to time the creation of a large number of signatures where explicit parameters with no co-factor present are in use by an application using libcrypto. For the avoidance of doubt libssl is not vulnerable because explicit parameters are never used. Fixed in OpenSSL 1.1.1d (Affected 1.1.1-1.1.1c). Fixed in OpenSSL 1.1.0l (Affected 1.1.0-1.1.0k). Fixed in OpenSSL 1.0.2t (Affected 1.0.2-1.0.2s).",
"Severity": "LOW",
"References": [
"http://packetstormsecurity.com/files/154467/Slackware-Security-Advisory-openssl-Updates.html",
"https://arxiv.org/abs/1909.01785",
"https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-1547",
"https://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff;h=21c856b75d81eff61aa63b4f036bb64a85bf6d46",
"https://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff;h=30c22fa8b1d840036b8e203585738df62a03cec8",
"https://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff;h=7c1709c2da5414f5b6133d00a03fc8c5bf996c7a",
"https://seclists.org/bugtraq/2019/Sep/25",
"https://security.netapp.com/advisory/ntap-20190919-0002/",
"https://www.openssl.org/news/secadv/20190910.txt"
]
},
{
"VulnerabilityID": "CVE-2019-16168",
"PkgName": "sqlite-libs",
"InstalledVersion": "3.27.2-3.ph2",
"FixedVersion": "3.27.2-5.ph2",
"Description": "In SQLite through 3.29.0, whereLoopAddBtreeIndex in sqlite3.c can crash a browser or other application because of missing validation of a sqlite_stat1 sz field, aka a \"severe division by zero in the query planner.\"",
"Severity": "MEDIUM",
"References": [
"https://security.netapp.com/advisory/ntap-20190926-0003/",
"https://www.mail-archive.com/sqlite-users@mailinglists.sqlite.org/msg116312.html",
"https://www.sqlite.org/src/info/e4598ecbdd18bd82945f6029013296690e719a62",
"https://www.sqlite.org/src/timeline?c=98357d8c1263920b"
]
}
]
}
]

View File

@@ -0,0 +1,142 @@
[
{
"Target": "testdata/fixtures/photon-30.tar.gz (photon 3.0)",
"Vulnerabilities": [
{
"VulnerabilityID": "CVE-2019-5481",
"PkgName": "curl",
"InstalledVersion": "7.61.1-4.ph3",
"FixedVersion": "7.61.1-5.ph3",
"Title": "curl: double free due to subsequent call of realloc()",
"Description": "Double-free vulnerability in the FTP-kerberos code in cURL 7.52.0 to 7.65.3.",
"Severity": "HIGH",
"References": [
"http://lists.opensuse.org/opensuse-security-announce/2019-09/msg00048.html",
"http://lists.opensuse.org/opensuse-security-announce/2019-09/msg00055.html",
"https://curl.haxx.se/docs/CVE-2019-5481.html",
"https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/RGDVKSLY5JUNJRLYRUA6CXGQ2LM63XC3/",
"https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/UA7KDM2WPM5CJDDGOEGFV6SSGD2J7RNT/"
]
},
{
"VulnerabilityID": "CVE-2019-5482",
"PkgName": "curl",
"InstalledVersion": "7.61.1-4.ph3",
"FixedVersion": "7.61.1-5.ph3",
"Title": "curl: heap buffer overflow in function tftp_receive_packet()",
"Description": "Heap buffer overflow in the TFTP protocol handler in cURL 7.19.4 to 7.65.3.",
"Severity": "HIGH",
"References": [
"http://lists.opensuse.org/opensuse-security-announce/2019-09/msg00048.html",
"http://lists.opensuse.org/opensuse-security-announce/2019-09/msg00055.html",
"https://curl.haxx.se/docs/CVE-2019-5482.html",
"https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-5482",
"https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/RGDVKSLY5JUNJRLYRUA6CXGQ2LM63XC3/",
"https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/UA7KDM2WPM5CJDDGOEGFV6SSGD2J7RNT/"
]
},
{
"VulnerabilityID": "CVE-2019-5481",
"PkgName": "curl-libs",
"InstalledVersion": "7.61.1-4.ph3",
"FixedVersion": "7.61.1-5.ph3",
"Title": "curl: double free due to subsequent call of realloc()",
"Description": "Double-free vulnerability in the FTP-kerberos code in cURL 7.52.0 to 7.65.3.",
"Severity": "HIGH",
"References": [
"http://lists.opensuse.org/opensuse-security-announce/2019-09/msg00048.html",
"http://lists.opensuse.org/opensuse-security-announce/2019-09/msg00055.html",
"https://curl.haxx.se/docs/CVE-2019-5481.html",
"https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/RGDVKSLY5JUNJRLYRUA6CXGQ2LM63XC3/",
"https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/UA7KDM2WPM5CJDDGOEGFV6SSGD2J7RNT/"
]
},
{
"VulnerabilityID": "CVE-2019-5482",
"PkgName": "curl-libs",
"InstalledVersion": "7.61.1-4.ph3",
"FixedVersion": "7.61.1-5.ph3",
"Title": "curl: heap buffer overflow in function tftp_receive_packet()",
"Description": "Heap buffer overflow in the TFTP protocol handler in cURL 7.19.4 to 7.65.3.",
"Severity": "HIGH",
"References": [
"http://lists.opensuse.org/opensuse-security-announce/2019-09/msg00048.html",
"http://lists.opensuse.org/opensuse-security-announce/2019-09/msg00055.html",
"https://curl.haxx.se/docs/CVE-2019-5482.html",
"https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-5482",
"https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/RGDVKSLY5JUNJRLYRUA6CXGQ2LM63XC3/",
"https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/UA7KDM2WPM5CJDDGOEGFV6SSGD2J7RNT/"
]
},
{
"VulnerabilityID": "CVE-2019-5094",
"PkgName": "e2fsprogs-libs",
"InstalledVersion": "1.44.3-2.ph3",
"FixedVersion": "1.44.3-3.ph3",
"Description": "An exploitable code execution vulnerability exists in the quota file functionality of E2fsprogs 1.45.3. A specially crafted ext4 partition can cause an out-of-bounds write on the heap, resulting in code execution. An attacker can corrupt a partition to trigger this vulnerability.",
"Severity": "MEDIUM",
"References": [
"https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-5094",
"https://lists.debian.org/debian-lts-announce/2019/09/msg00029.html",
"https://seclists.org/bugtraq/2019/Sep/58",
"https://talosintelligence.com/vulnerability_reports/TALOS-2019-0887",
"https://usn.ubuntu.com/4142-2/",
"https://www.debian.org/security/2019/dsa-4535"
]
},
{
"VulnerabilityID": "CVE-2019-1563",
"PkgName": "openssl",
"InstalledVersion": "1.0.2s-1.ph3",
"FixedVersion": "1.0.2t-1.ph3",
"Title": "openssl: information disclosure in PKCS7_dataDecode and CMS_decrypt_set1_pkey",
"Description": "In situations where an attacker receives automated notification of the success or failure of a decryption attempt an attacker, after sending a very large number of messages to be decrypted, can recover a CMS/PKCS7 transported encryption key or decrypt any RSA encrypted message that was encrypted with the public RSA key, using a Bleichenbacher padding oracle attack. Applications are not affected if they use a certificate together with the private RSA key to the CMS_decrypt or PKCS7_decrypt functions to select the correct recipient info to decrypt. Fixed in OpenSSL 1.1.1d (Affected 1.1.1-1.1.1c). Fixed in OpenSSL 1.1.0l (Affected 1.1.0-1.1.0k). Fixed in OpenSSL 1.0.2t (Affected 1.0.2-1.0.2s).",
"Severity": "MEDIUM",
"References": [
"http://packetstormsecurity.com/files/154467/Slackware-Security-Advisory-openssl-Updates.html",
"https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-1563",
"https://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff;h=08229ad838c50f644d7e928e2eef147b4308ad64",
"https://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff;h=631f94db0065c78181ca9ba5546ebc8bb3884b97",
"https://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff;h=e21f8cf78a125cd3c8c0d1a1a6c8bb0b901f893f",
"https://seclists.org/bugtraq/2019/Sep/25",
"https://security.netapp.com/advisory/ntap-20190919-0002/",
"https://www.openssl.org/news/secadv/20190910.txt"
]
},
{
"VulnerabilityID": "CVE-2019-1547",
"PkgName": "openssl",
"InstalledVersion": "1.0.2s-1.ph3",
"FixedVersion": "1.0.2t-1.ph3",
"Title": "openssl: side-channel weak encryption vulnerability",
"Description": "Normally in OpenSSL EC groups always have a co-factor present and this is used in side channel resistant code paths. However, in some cases, it is possible to construct a group using explicit parameters (instead of using a named curve). In those cases it is possible that such a group does not have the cofactor present. This can occur even where all the parameters match a known named curve. If such a curve is used then OpenSSL falls back to non-side channel resistant code paths which may result in full key recovery during an ECDSA signature operation. In order to be vulnerable an attacker would have to have the ability to time the creation of a large number of signatures where explicit parameters with no co-factor present are in use by an application using libcrypto. For the avoidance of doubt libssl is not vulnerable because explicit parameters are never used. Fixed in OpenSSL 1.1.1d (Affected 1.1.1-1.1.1c). Fixed in OpenSSL 1.1.0l (Affected 1.1.0-1.1.0k). Fixed in OpenSSL 1.0.2t (Affected 1.0.2-1.0.2s).",
"Severity": "LOW",
"References": [
"http://packetstormsecurity.com/files/154467/Slackware-Security-Advisory-openssl-Updates.html",
"https://arxiv.org/abs/1909.01785",
"https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-1547",
"https://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff;h=21c856b75d81eff61aa63b4f036bb64a85bf6d46",
"https://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff;h=30c22fa8b1d840036b8e203585738df62a03cec8",
"https://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff;h=7c1709c2da5414f5b6133d00a03fc8c5bf996c7a",
"https://seclists.org/bugtraq/2019/Sep/25",
"https://security.netapp.com/advisory/ntap-20190919-0002/",
"https://www.openssl.org/news/secadv/20190910.txt"
]
},
{
"VulnerabilityID": "CVE-2019-16168",
"PkgName": "sqlite-libs",
"InstalledVersion": "3.27.2-3.ph3",
"FixedVersion": "3.27.2-5.ph3",
"Description": "In SQLite through 3.29.0, whereLoopAddBtreeIndex in sqlite3.c can crash a browser or other application because of missing validation of a sqlite_stat1 sz field, aka a \"severe division by zero in the query planner.\"",
"Severity": "MEDIUM",
"References": [
"https://security.netapp.com/advisory/ntap-20190926-0003/",
"https://www.mail-archive.com/sqlite-users@mailinglists.sqlite.org/msg116312.html",
"https://www.sqlite.org/src/info/e4598ecbdd18bd82945f6029013296690e719a62",
"https://www.sqlite.org/src/timeline?c=98357d8c1263920b"
]
}
]
}
]

Binary file not shown.

View File

@@ -4,15 +4,14 @@ import (
"strings"
"time"
"github.com/aquasecurity/trivy/internal/client"
"github.com/aquasecurity/trivy/internal/server"
"github.com/aquasecurity/trivy/internal/standalone"
"github.com/aquasecurity/trivy/pkg/vulnerability"
"github.com/urfave/cli"
"github.com/aquasecurity/trivy-db/pkg/types"
"github.com/aquasecurity/trivy/internal/client"
"github.com/aquasecurity/trivy/internal/server"
"github.com/aquasecurity/trivy/internal/standalone"
"github.com/aquasecurity/trivy/pkg/utils"
"github.com/urfave/cli"
"github.com/aquasecurity/trivy/pkg/vulnerability"
)
var (
@@ -115,7 +114,7 @@ var (
cacheDirFlag = cli.StringFlag{
Name: "cache-dir",
Value: utils.DefaultCacheDir(),
Usage: "use as cache directory, but image cache is stored in /path/to/cache/fanal",
Usage: "cache directory",
EnvVar: "TRIVY_CACHE_DIR",
}
@@ -144,6 +143,13 @@ var (
Usage: "for authentication",
EnvVar: "TRIVY_TOKEN",
}
tokenHeader = cli.StringFlag{
Name: "token-header",
Value: "Trivy-Token",
Usage: "specify a header name for token",
EnvVar: "TRIVY_TOKEN_HEADER",
}
)
func NewApp(version string) *cli.App {
@@ -243,12 +249,18 @@ func NewClientCommand() cli.Command {
// original flags
token,
tokenHeader,
cli.StringFlag{
Name: "remote",
Value: "http://localhost:4954",
Usage: "server address",
EnvVar: "TRIVY_REMOTE",
},
cli.StringSliceFlag{
Name: "custom-headers",
Usage: "custom headers",
EnvVar: "TRIVY_CUSTOM_HEADERS",
},
},
}
}
@@ -269,6 +281,7 @@ func NewServerCommand() cli.Command {
// original flags
token,
tokenHeader,
cli.StringFlag{
Name: "listen",
Value: "localhost:4954",

View File

@@ -1,6 +1,7 @@
package config
import (
"net/http"
"os"
"strings"
"time"
@@ -12,7 +13,6 @@ import (
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
"github.com/aquasecurity/trivy/pkg/log"
"github.com/aquasecurity/trivy/pkg/utils"
)
type Config struct {
@@ -37,8 +37,11 @@ type Config struct {
IgnoreUnfixed bool
ExitCode int
RemoteAddr string
Token string
RemoteAddr string
token string
tokenHeader string
customHeaders []string
CustomHeaders http.Header
// these variables are generated by Init()
ImageName string
@@ -77,8 +80,10 @@ func New(c *cli.Context) (Config, error) {
IgnoreUnfixed: c.Bool("ignore-unfixed"),
ExitCode: c.Int("exit-code"),
RemoteAddr: c.String("remote"),
Token: c.String("token"),
RemoteAddr: c.String("remote"),
token: c.String("token"),
tokenHeader: c.String("token-header"),
customHeaders: c.StringSlice("custom-headers"),
}, nil
}
@@ -86,9 +91,11 @@ func (c *Config) Init() (err error) {
c.Severities = c.splitSeverity(c.severities)
c.VulnType = strings.Split(c.vulnType, ",")
c.AppVersion = c.context.App.Version
c.CustomHeaders = splitCustomHeaders(c.customHeaders)
if c.Quiet {
utils.Quiet = true
// add token to custom headers
if c.token != "" {
c.CustomHeaders.Set(c.tokenHeader, c.token)
}
// --clear-cache doesn't conduct the scan
@@ -101,6 +108,9 @@ func (c *Config) Init() (err error) {
c.logger.Error(`trivy requires at least 1 argument or --input option`)
cli.ShowAppHelp(c.context)
return xerrors.New("arguments error")
} else if len(args) > 1 {
c.logger.Error(`multiple images cannot be specified`)
return xerrors.New("arguments error")
}
c.Output = os.Stdout
@@ -140,3 +150,16 @@ func (c *Config) splitSeverity(severity string) []dbTypes.Severity {
}
return severities
}
func splitCustomHeaders(headers []string) http.Header {
result := make(http.Header)
for _, header := range headers {
// e.g. x-api-token:XXX
s := strings.SplitN(header, ":", 2)
if len(s) != 2 {
continue
}
result.Set(s[0], s[1])
}
return result
}

View File

@@ -2,7 +2,9 @@ package config
import (
"flag"
"net/http"
"os"
"reflect"
"testing"
"time"
@@ -83,6 +85,8 @@ func TestConfig_Init(t *testing.T) {
onlyUpdate string
refresh bool
autoRefresh bool
token string
tokenHeader string
}
tests := []struct {
name string
@@ -95,20 +99,27 @@ func TestConfig_Init(t *testing.T) {
{
name: "happy path",
fields: fields{
severities: "CRITICAL",
vulnType: "os",
Quiet: true,
severities: "CRITICAL",
vulnType: "os",
Quiet: true,
token: "foobar",
tokenHeader: "Trivy-Token",
},
args: []string{"alpine:3.10"},
want: Config{
AppVersion: "0.0.0",
Severities: []dbTypes.Severity{dbTypes.SeverityCritical},
severities: "CRITICAL",
ImageName: "alpine:3.10",
VulnType: []string{"os"},
vulnType: "os",
Output: os.Stdout,
Quiet: true,
AppVersion: "0.0.0",
Severities: []dbTypes.Severity{dbTypes.SeverityCritical},
severities: "CRITICAL",
ImageName: "alpine:3.10",
VulnType: []string{"os"},
vulnType: "os",
Output: os.Stdout,
Quiet: true,
token: "foobar",
tokenHeader: "Trivy-Token",
CustomHeaders: http.Header{
"Trivy-Token": []string{"foobar"},
},
},
},
{
@@ -122,13 +133,14 @@ func TestConfig_Init(t *testing.T) {
"unknown severity option: unknown severity: INVALID",
},
want: Config{
AppVersion: "0.0.0",
Severities: []dbTypes.Severity{dbTypes.SeverityCritical, dbTypes.SeverityUnknown},
severities: "CRITICAL,INVALID",
ImageName: "centos:7",
VulnType: []string{"os", "library"},
vulnType: "os,library",
Output: os.Stdout,
AppVersion: "0.0.0",
Severities: []dbTypes.Severity{dbTypes.SeverityCritical, dbTypes.SeverityUnknown},
severities: "CRITICAL,INVALID",
ImageName: "centos:7",
VulnType: []string{"os", "library"},
vulnType: "os,library",
Output: os.Stdout,
CustomHeaders: make(http.Header),
},
},
{
@@ -143,15 +155,27 @@ func TestConfig_Init(t *testing.T) {
"You should avoid using the :latest tag as it is cached. You need to specify '--clear-cache' option when :latest image is changed",
},
want: Config{
AppVersion: "0.0.0",
Severities: []dbTypes.Severity{dbTypes.SeverityLow},
severities: "LOW",
ImageName: "gcr.io/distroless/base",
VulnType: []string{"os", "library"},
vulnType: "os,library",
Output: os.Stdout,
AppVersion: "0.0.0",
Severities: []dbTypes.Severity{dbTypes.SeverityLow},
severities: "LOW",
ImageName: "gcr.io/distroless/base",
VulnType: []string{"os", "library"},
vulnType: "os,library",
Output: os.Stdout,
CustomHeaders: make(http.Header),
},
},
{
name: "sad: multiple image names",
fields: fields{
severities: "MEDIUM",
},
args: []string{"centos:7", "alpine:3.10"},
logs: []string{
"multiple images cannot be specified",
},
wantErr: "arguments error",
},
{
name: "sad: no image name",
fields: fields{
@@ -200,6 +224,8 @@ func TestConfig_Init(t *testing.T) {
ExitCode: tt.fields.ExitCode,
ImageName: tt.fields.ImageName,
Output: tt.fields.Output,
token: tt.fields.token,
tokenHeader: tt.fields.tokenHeader,
}
err := c.Init()
@@ -227,3 +253,32 @@ func TestConfig_Init(t *testing.T) {
})
}
}
func Test_splitCustomHeaders(t *testing.T) {
type args struct {
headers []string
}
tests := []struct {
name string
args args
want http.Header
}{
{
name: "happy path",
args: args{
headers: []string{"x-api-token:foo bar", "Authorization:user:password"},
},
want: http.Header{
"X-Api-Token": []string{"foo bar"},
"Authorization": []string{"user:password"},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := splitCustomHeaders(tt.args.headers); !reflect.DeepEqual(got, tt.want) {
t.Errorf("splitCustomHeaders() = %v, want %v", got, tt.want)
}
})
}
}

View File

@@ -3,6 +3,7 @@
package client
import (
"github.com/aquasecurity/fanal/cache"
"github.com/aquasecurity/trivy/pkg/rpc/client/library"
"github.com/aquasecurity/trivy/pkg/rpc/client/ospkg"
"github.com/aquasecurity/trivy/pkg/scanner"
@@ -10,7 +11,8 @@ import (
"github.com/google/wire"
)
func initializeScanner(ospkgToken ospkg.Token, libToken library.Token, ospkgURL ospkg.RemoteURL, libURL library.RemoteURL) scanner.Scanner {
func initializeScanner(cacheClient cache.Cache, ospkgCustomHeaders ospkg.CustomHeaders, libraryCustomHeaders library.CustomHeaders,
ospkgURL ospkg.RemoteURL, libURL library.RemoteURL) scanner.Scanner {
wire.Build(scanner.ClientSet)
return scanner.Scanner{}
}

View File

@@ -6,7 +6,9 @@ import (
"github.com/urfave/cli"
"golang.org/x/xerrors"
"github.com/aquasecurity/fanal/cache"
"github.com/aquasecurity/trivy/internal/client/config"
"github.com/aquasecurity/trivy/internal/operation"
"github.com/aquasecurity/trivy/pkg/log"
"github.com/aquasecurity/trivy/pkg/report"
"github.com/aquasecurity/trivy/pkg/rpc/client/library"
@@ -35,17 +37,23 @@ func run(c config.Config) (err error) {
// configure cache dir
utils.SetCacheDir(c.CacheDir)
cacheClient := cache.Initialize(c.CacheDir)
cacheOperation := operation.NewCache(cacheClient)
log.Logger.Debugf("cache dir: %s", utils.CacheDir())
if c.ClearCache {
return cacheOperation.ClearImages()
}
scanOptions := types.ScanOptions{
VulnType: c.VulnType,
Timeout: c.Timeout,
RemoteURL: c.RemoteAddr,
Token: c.Token,
}
log.Logger.Debugf("Vulnerability type: %s", scanOptions.VulnType)
scanner := initializeScanner(ospkg.Token(c.Token), library.Token(c.Token),
scanner := initializeScanner(cacheClient,
ospkg.CustomHeaders(c.CustomHeaders), library.CustomHeaders(c.CustomHeaders),
ospkg.RemoteURL(c.RemoteAddr), library.RemoteURL(c.RemoteAddr))
results, err := scanner.ScanImage(c.ImageName, c.Input, scanOptions)
if err != nil {

View File

@@ -6,6 +6,7 @@
package client
import (
"github.com/aquasecurity/fanal/cache"
"github.com/aquasecurity/trivy-db/pkg/db"
"github.com/aquasecurity/trivy/pkg/rpc/client/library"
"github.com/aquasecurity/trivy/pkg/rpc/client/ospkg"
@@ -17,14 +18,14 @@ import (
// Injectors from inject.go:
func initializeScanner(ospkgToken ospkg.Token, libToken library.Token, ospkgURL ospkg.RemoteURL, libURL library.RemoteURL) scanner.Scanner {
func initializeScanner(cacheClient cache.Cache, ospkgCustomHeaders ospkg.CustomHeaders, libraryCustomHeaders library.CustomHeaders, ospkgURL ospkg.RemoteURL, libURL library.RemoteURL) scanner.Scanner {
osDetector := ospkg.NewProtobufClient(ospkgURL)
detector := ospkg.NewDetector(ospkgToken, osDetector)
detector := ospkg.NewDetector(ospkgCustomHeaders, osDetector)
ospkgScanner := ospkg2.NewScanner(detector)
libDetector := library.NewProtobufClient(libURL)
libraryDetector := library.NewDetector(libToken, libDetector)
libraryDetector := library.NewDetector(libraryCustomHeaders, libDetector)
libraryScanner := library2.NewScanner(libraryDetector)
scannerScanner := scanner.NewScanner(ospkgScanner, libraryScanner)
scannerScanner := scanner.NewScanner(cacheClient, ospkgScanner, libraryScanner)
return scannerScanner
}

View File

@@ -7,7 +7,7 @@ import (
"github.com/google/wire"
)
func initializeDBClient() db.Client {
func initializeDBClient(quiet bool) db.Client {
wire.Build(db.SuperSet)
return db.Client{}
}

View File

@@ -4,6 +4,7 @@ import (
"context"
"os"
"github.com/google/wire"
"golang.org/x/xerrors"
"github.com/aquasecurity/fanal/cache"
@@ -12,27 +13,47 @@ import (
"github.com/aquasecurity/trivy/pkg/utils"
)
func Reset() (err error) {
log.Logger.Info("Resetting...")
if err = cache.Clear(); err != nil {
return xerrors.New("failed to remove image layer cache")
var SuperSet = wire.NewSet(
cache.Initialize,
NewCache,
)
type Cache struct {
client cache.Cache
}
func NewCache(client cache.Cache) Cache {
return Cache{client: client}
}
func (c Cache) Reset() (err error) {
if err := c.ClearDB(); err != nil {
return err
}
if err := c.ClearImages(); err != nil {
return err
}
return nil
}
func (c Cache) ClearDB() (err error) {
log.Logger.Info("Removing DB file...")
if err = os.RemoveAll(utils.CacheDir()); err != nil {
return xerrors.New("failed to remove cache")
}
return nil
}
func ClearCache() error {
func (c Cache) ClearImages() error {
log.Logger.Info("Removing image caches...")
if err := cache.Clear(); err != nil {
if err := c.client.Clear(); err != nil {
return xerrors.New("failed to remove image layer cache")
}
return nil
}
func DownloadDB(appVersion, cacheDir string, light, skipUpdate bool) error {
client := initializeDBClient()
func DownloadDB(appVersion, cacheDir string, quiet, light, skipUpdate bool) error {
client := initializeDBClient(quiet)
ctx := context.Background()
needsUpdate, err := client.NeedsUpdate(ctx, appVersion, light, skipUpdate)
if err != nil {
@@ -44,6 +65,7 @@ func DownloadDB(appVersion, cacheDir string, light, skipUpdate bool) error {
if err = db.Close(); err != nil {
return xerrors.Errorf("failed db close: %w", err)
}
log.Logger.Info("Downloading DB...")
if err := client.Download(ctx, cacheDir, light); err != nil {
return xerrors.Errorf("failed to download vulnerability DB: %w", err)
}

View File

@@ -9,15 +9,17 @@ import (
db2 "github.com/aquasecurity/trivy-db/pkg/db"
"github.com/aquasecurity/trivy/pkg/db"
"github.com/aquasecurity/trivy/pkg/github"
"github.com/aquasecurity/trivy/pkg/indicator"
"k8s.io/utils/clock"
)
// Injectors from inject.go:
func initializeDBClient() db.Client {
func initializeDBClient(quiet bool) db.Client {
config := db2.Config{}
client := github.NewClient()
progressBar := indicator.NewProgressBar(quiet)
realClock := clock.RealClock{}
dbClient := db.NewClient(config, client, realClock)
dbClient := db.NewClient(config, client, progressBar, realClock)
return dbClient
}

View File

@@ -3,8 +3,6 @@ package config
import (
"github.com/urfave/cli"
"golang.org/x/xerrors"
"github.com/aquasecurity/trivy/pkg/utils"
)
type Config struct {
@@ -17,8 +15,9 @@ type Config struct {
DownloadDBOnly bool
SkipUpdate bool
Listen string
Token string
Listen string
Token string
TokenHeader string
// these variables are generated by Init()
AppVersion string
@@ -38,6 +37,7 @@ func New(c *cli.Context) Config {
SkipUpdate: c.Bool("skip-update"),
Listen: c.String("listen"),
Token: c.String("token"),
TokenHeader: c.String("token-header"),
}
}
@@ -48,8 +48,5 @@ func (c *Config) Init() (err error) {
c.AppVersion = c.context.App.Version
// A server always suppresses a progress bar
utils.Quiet = true
return nil
}

View File

@@ -1,15 +1,15 @@
package server
import (
"github.com/aquasecurity/trivy/pkg/rpc/server"
"github.com/urfave/cli"
"golang.org/x/xerrors"
"github.com/aquasecurity/trivy-db/pkg/db"
"github.com/aquasecurity/trivy/internal/operation"
"github.com/aquasecurity/trivy/internal/server/config"
"github.com/aquasecurity/trivy/pkg/log"
"github.com/aquasecurity/trivy/pkg/rpc/server"
"github.com/aquasecurity/trivy/pkg/utils"
"github.com/urfave/cli"
"golang.org/x/xerrors"
)
func Run(ctx *cli.Context) error {
@@ -30,8 +30,10 @@ func run(c config.Config) (err error) {
utils.SetCacheDir(c.CacheDir)
log.Logger.Debugf("cache dir: %s", utils.CacheDir())
// server doesn't have image cache
cacheOperation := operation.NewCache(nil)
if c.Reset {
return operation.Reset()
return cacheOperation.ClearDB()
}
if err = db.Init(c.CacheDir); err != nil {
@@ -39,7 +41,7 @@ func run(c config.Config) (err error) {
}
// download the database file
if err = operation.DownloadDB(c.AppVersion, c.CacheDir, false, c.SkipUpdate); err != nil {
if err = operation.DownloadDB(c.AppVersion, c.CacheDir, true, false, c.SkipUpdate); err != nil {
return err
}

View File

@@ -12,7 +12,6 @@ import (
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
"github.com/aquasecurity/trivy/pkg/log"
"github.com/aquasecurity/trivy/pkg/utils"
)
type Config struct {
@@ -98,6 +97,16 @@ func New(c *cli.Context) (Config, error) {
}
func (c *Config) Init() (err error) {
if c.Template != "" {
if c.Format == "" {
c.logger.Warn("--template is ignored because --format template is not specified. Use --template option with --format template option.")
} else if c.Format != "template" {
c.logger.Warnf("--template is ignored because --format %s is specified. Use --template option with --format template option.", c.Format)
}
}
if c.Format == "template" && c.Template == "" {
c.logger.Warn("--format template is ignored because --template not is specified. Specify --template option when you use --format template.")
}
if c.onlyUpdate != "" || c.refresh || c.autoRefresh {
c.logger.Warn("--only-update, --refresh and --auto-refresh are unnecessary and ignored now. These commands will be removed in the next version.")
}
@@ -109,10 +118,6 @@ func (c *Config) Init() (err error) {
c.VulnType = strings.Split(c.vulnType, ",")
c.AppVersion = c.context.App.Version
if c.Quiet || c.NoProgress {
utils.Quiet = true
}
// --clear-cache, --download-db-only and --reset don't conduct the scan
if c.ClearCache || c.DownloadDBOnly || c.Reset {
return nil
@@ -123,6 +128,9 @@ func (c *Config) Init() (err error) {
c.logger.Error(`trivy requires at least 1 argument or --input option`)
cli.ShowAppHelp(c.context)
return xerrors.New("arguments error")
} else if len(args) > 1 {
c.logger.Error(`multiple images cannot be specified`)
return xerrors.New("arguments error")
}
c.Output = os.Stdout

View File

@@ -168,6 +168,68 @@ func TestConfig_Init(t *testing.T) {
onlyUpdate: "alpine",
},
},
{
name: "invalid option combination: --template enabled without --format",
fields: fields{
Template: "@contrib/gitlab.tpl",
severities: "LOW",
},
args: []string{"gitlab/gitlab-ce:12.7.2-ce.0"},
logs: []string{
"--template is ignored because --format template is not specified. Use --template option with --format template option.",
},
want: Config{
AppVersion: "0.0.0",
ImageName: "gitlab/gitlab-ce:12.7.2-ce.0",
Output: os.Stdout,
Severities: []dbTypes.Severity{dbTypes.SeverityLow},
severities: "LOW",
Template: "@contrib/gitlab.tpl",
VulnType: []string{""},
},
},
{
name: "invalid option combination: --template and --format json",
fields: fields{
Format: "json",
Template: "@contrib/gitlab.tpl",
severities: "LOW",
},
args: []string{"gitlab/gitlab-ce:12.7.2-ce.0"},
logs: []string{
"--template is ignored because --format json is specified. Use --template option with --format template option.",
},
want: Config{
AppVersion: "0.0.0",
Format: "json",
ImageName: "gitlab/gitlab-ce:12.7.2-ce.0",
Output: os.Stdout,
Severities: []dbTypes.Severity{dbTypes.SeverityLow},
severities: "LOW",
Template: "@contrib/gitlab.tpl",
VulnType: []string{""},
},
},
{
name: "invalid option combination: --format template without --template",
fields: fields{
Format: "template",
severities: "LOW",
},
args: []string{"gitlab/gitlab-ce:12.7.2-ce.0"},
logs: []string{
"--format template is ignored because --template not is specified. Specify --template option when you use --format template.",
},
want: Config{
AppVersion: "0.0.0",
Format: "template",
ImageName: "gitlab/gitlab-ce:12.7.2-ce.0",
Output: os.Stdout,
Severities: []dbTypes.Severity{dbTypes.SeverityLow},
severities: "LOW",
VulnType: []string{""},
},
},
{
name: "with latest tag",
fields: fields{
@@ -204,6 +266,17 @@ func TestConfig_Init(t *testing.T) {
},
wantErr: "The --skip-update and --download-db-only option can not be specified both",
},
{
name: "sad: multiple image names",
fields: fields{
severities: "MEDIUM",
},
args: []string{"centos:7", "alpine:3.10"},
logs: []string{
"multiple images cannot be specified",
},
wantErr: "arguments error",
},
{
name: "sad: no image name",
fields: fields{

View File

@@ -3,12 +3,19 @@
package standalone
import (
"github.com/aquasecurity/fanal/cache"
"github.com/aquasecurity/trivy/internal/operation"
"github.com/aquasecurity/trivy/pkg/scanner"
"github.com/aquasecurity/trivy/pkg/vulnerability"
"github.com/google/wire"
)
func initializeScanner() scanner.Scanner {
func initializeCacheClient(cacheDir string) (operation.Cache, error) {
wire.Build(operation.SuperSet)
return operation.Cache{}, nil
}
func initializeScanner(c cache.Cache) scanner.Scanner {
wire.Build(scanner.StandaloneSet)
return scanner.Scanner{}
}

View File

@@ -1,9 +1,12 @@
package standalone
import (
"io/ioutil"
l "log"
"os"
"strings"
"github.com/aquasecurity/fanal/cache"
"github.com/aquasecurity/trivy-db/pkg/db"
"github.com/aquasecurity/trivy/internal/operation"
"github.com/aquasecurity/trivy/internal/standalone/config"
@@ -35,14 +38,15 @@ func run(c config.Config) (err error) {
// configure cache dir
utils.SetCacheDir(c.CacheDir)
cacheClient := cache.Initialize(c.CacheDir)
cacheOperation := operation.NewCache(cacheClient)
log.Logger.Debugf("cache dir: %s", utils.CacheDir())
if c.Reset {
return operation.Reset()
return cacheOperation.Reset()
}
if c.ClearCache {
return operation.ClearCache()
return cacheOperation.ClearImages()
}
if err = db.Init(c.CacheDir); err != nil {
@@ -50,7 +54,8 @@ func run(c config.Config) (err error) {
}
// download the database file
if err = operation.DownloadDB(c.AppVersion, c.CacheDir, c.Light, c.SkipUpdate); err != nil {
noProgress := c.Quiet || c.NoProgress
if err = operation.DownloadDB(c.AppVersion, c.CacheDir, noProgress, c.Light, c.SkipUpdate); err != nil {
return err
}
@@ -64,7 +69,7 @@ func run(c config.Config) (err error) {
}
log.Logger.Debugf("Vulnerability type: %s", scanOptions.VulnType)
scanner := initializeScanner()
scanner := initializeScanner(cacheClient)
results, err := scanner.ScanImage(c.ImageName, c.Input, scanOptions)
if err != nil {
return xerrors.Errorf("error in image scan: %w", err)
@@ -77,7 +82,17 @@ func run(c config.Config) (err error) {
c.Severities, c.IgnoreUnfixed, c.IgnoreFile)
}
if err = report.WriteResults(c.Format, c.Output, results, c.Template, c.Light); err != nil {
template := c.Template
if strings.HasPrefix(c.Template, "@") {
buf, err := ioutil.ReadFile(strings.TrimPrefix(c.Template, "@"))
if err != nil {
return xerrors.Errorf("Error retrieving template from path: %w", err)
}
template = string(buf)
}
if err = report.WriteResults(c.Format, c.Output, results, template, c.Light); err != nil {
return xerrors.Errorf("unable to write results: %w", err)
}

View File

@@ -6,7 +6,9 @@
package standalone
import (
"github.com/aquasecurity/fanal/cache"
"github.com/aquasecurity/trivy-db/pkg/db"
"github.com/aquasecurity/trivy/internal/operation"
"github.com/aquasecurity/trivy/pkg/detector/library"
"github.com/aquasecurity/trivy/pkg/detector/ospkg"
"github.com/aquasecurity/trivy/pkg/scanner"
@@ -17,13 +19,19 @@ import (
// Injectors from inject.go:
func initializeScanner() scanner.Scanner {
func initializeCacheClient(cacheDir string) (operation.Cache, error) {
cacheCache := cache.Initialize(cacheDir)
operationCache := operation.NewCache(cacheCache)
return operationCache, nil
}
func initializeScanner(c cache.Cache) scanner.Scanner {
detector := ospkg.Detector{}
ospkgScanner := ospkg2.NewScanner(detector)
driverFactory := library.DriverFactory{}
libraryDetector := library.NewDetector(driverFactory)
libraryScanner := library2.NewScanner(libraryDetector)
scannerScanner := scanner.NewScanner(ospkgScanner, libraryScanner)
scannerScanner := scanner.NewScanner(c, ospkgScanner, libraryScanner)
return scannerScanner
}

View File

@@ -13,8 +13,8 @@ import (
"github.com/aquasecurity/trivy-db/pkg/db"
"github.com/aquasecurity/trivy/pkg/github"
"github.com/aquasecurity/trivy/pkg/indicator"
"github.com/aquasecurity/trivy/pkg/log"
"github.com/aquasecurity/trivy/pkg/utils"
)
const (
@@ -23,11 +23,21 @@ const (
)
var SuperSet = wire.NewSet(
// indicator.ProgressBar
indicator.NewProgressBar,
// clock.Clock
wire.Struct(new(clock.RealClock)),
wire.Bind(new(clock.Clock), new(clock.RealClock)),
// db.Config
wire.Struct(new(db.Config)),
// github.Client
github.NewClient,
wire.Bind(new(github.Operation), new(github.Client)),
// db.Client
NewClient,
wire.Bind(new(Operation), new(Client)),
)
@@ -44,13 +54,15 @@ type dbOperation interface {
type Client struct {
dbc dbOperation
githubClient github.Operation
pb indicator.ProgressBar
clock clock.Clock
}
func NewClient(dbc db.Config, githubClient github.Operation, clock clock.Clock) Client {
func NewClient(dbc db.Config, githubClient github.Operation, pb indicator.ProgressBar, clock clock.Clock) Client {
return Client{
dbc: dbc,
githubClient: githubClient,
pb: pb,
clock: clock,
}
}
@@ -102,23 +114,21 @@ func (c Client) NeedsUpdate(ctx context.Context, cliVersion string, light, skip
func (c Client) Download(ctx context.Context, cacheDir string, light bool) error {
dbFile := fullDB
message := " Downloading Full DB file..."
if light {
dbFile = lightDB
message = " Downloading Lightweight DB file..."
}
spinner := utils.NewSpinner(message)
spinner.Start()
defer spinner.Stop()
rc, err := c.githubClient.DownloadDB(ctx, dbFile)
rc, size, err := c.githubClient.DownloadDB(ctx, dbFile)
if err != nil {
return xerrors.Errorf("failed to download vulnerability DB: %w", err)
}
defer rc.Close()
gr, err := gzip.NewReader(rc)
bar := c.pb.Start(int64(size))
barReader := bar.NewProxyReader(rc)
defer bar.Finish()
gr, err := gzip.NewReader(barReader)
if err != nil {
return xerrors.Errorf("invalid gzip file: %w", err)
}

View File

@@ -3,12 +3,13 @@ package db
import (
"context"
"errors"
"io"
"io/ioutil"
"os"
"testing"
"time"
"github.com/aquasecurity/trivy/pkg/indicator"
"github.com/stretchr/testify/require"
"golang.org/x/xerrors"
@@ -208,30 +209,21 @@ func TestClient_NeedsUpdate(t *testing.T) {
}
func TestClient_Download(t *testing.T) {
type downloadDBOutput struct {
fileName string
err error
}
type downloadDB struct {
input string
output downloadDBOutput
}
testCases := []struct {
name string
light bool
downloadDB []downloadDB
downloadDB []github.DownloadDBExpectation
expectedContent []byte
expectedError error
}{
{
name: "happy path",
light: false,
downloadDB: []downloadDB{
downloadDB: []github.DownloadDBExpectation{
{
input: fullDB,
output: downloadDBOutput{
fileName: "testdata/test.db.gz",
Args: github.DownloadDBInput{FileName: fullDB},
ReturnArgs: github.DownloadDBOutput{
FileName: "testdata/test.db.gz",
},
},
},
@@ -239,11 +231,11 @@ func TestClient_Download(t *testing.T) {
{
name: "DownloadDB returns an error",
light: false,
downloadDB: []downloadDB{
downloadDB: []github.DownloadDBExpectation{
{
input: fullDB,
output: downloadDBOutput{
err: xerrors.New("download failed"),
Args: github.DownloadDBInput{FileName: fullDB},
ReturnArgs: github.DownloadDBOutput{
Err: xerrors.New("download failed"),
},
},
},
@@ -252,11 +244,11 @@ func TestClient_Download(t *testing.T) {
{
name: "invalid gzip",
light: false,
downloadDB: []downloadDB{
downloadDB: []github.DownloadDBExpectation{
{
input: fullDB,
output: downloadDBOutput{
fileName: "testdata/invalid.db.gz",
Args: github.DownloadDBInput{FileName: fullDB},
ReturnArgs: github.DownloadDBOutput{
FileName: "testdata/invalid.db.gz",
},
},
},
@@ -269,19 +261,8 @@ func TestClient_Download(t *testing.T) {
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
mockGitHubClient := new(github.MockClient)
for _, dd := range tc.downloadDB {
var rc io.ReadCloser
if dd.output.fileName != "" {
f, err := os.Open(dd.output.fileName)
assert.NoError(t, err, tc.name)
rc = f
}
mockGitHubClient.On("DownloadDB", mock.Anything, dd.input).Return(
rc, dd.output.err,
)
}
mockGitHubClient, err := github.NewMockClient(tc.downloadDB)
require.NoError(t, err, tc.name)
dir, err := ioutil.TempDir("", "db")
require.NoError(t, err, tc.name)
@@ -290,7 +271,8 @@ func TestClient_Download(t *testing.T) {
err = db.Init(dir)
require.NoError(t, err, tc.name)
client := NewClient(db.Config{}, mockGitHubClient, nil)
pb := indicator.NewProgressBar(true)
client := NewClient(db.Config{}, mockGitHubClient, pb, nil)
ctx := context.Background()
err = client.Download(ctx, dir, tc.light)

View File

@@ -2,6 +2,7 @@ package library
import (
"path/filepath"
"time"
"github.com/google/wire"
@@ -23,7 +24,7 @@ var SuperSet = wire.NewSet(
)
type Operation interface {
Detect(string, []ptypes.Library) ([]types.DetectedVulnerability, error)
Detect(string, string, time.Time, []ptypes.Library) ([]types.DetectedVulnerability, error)
}
type Detector struct {
@@ -34,7 +35,7 @@ func NewDetector(factory Factory) Detector {
return Detector{driverFactory: factory}
}
func (d Detector) Detect(filePath string, pkgs []ptypes.Library) ([]types.DetectedVulnerability, error) {
func (d Detector) Detect(_ string, filePath string, _ time.Time, pkgs []ptypes.Library) ([]types.DetectedVulnerability, error) {
log.Logger.Debugf("Detecting library vulnerabilities, path: %s", filePath)
driver := d.driverFactory.NewDriver(filepath.Base(filePath))
if driver == nil {

View File

@@ -1,6 +1,8 @@
package library
import (
"time"
ptypes "github.com/aquasecurity/go-dep-parser/pkg/types"
"github.com/aquasecurity/trivy/pkg/types"
"github.com/stretchr/testify/mock"
@@ -11,8 +13,10 @@ type MockDetector struct {
}
type DetectInput struct {
FilePath string
Libs []ptypes.Library
ImageName string
FilePath string
Created time.Time
Libs []ptypes.Library
}
type DetectOutput struct {
Vulns []types.DetectedVulnerability
@@ -26,14 +30,14 @@ type DetectExpectation struct {
func NewMockDetector(detectExpectations []DetectExpectation) *MockDetector {
mockDetector := new(MockDetector)
for _, e := range detectExpectations {
mockDetector.On("Detect", e.Args.FilePath, e.Args.Libs).Return(
mockDetector.On("Detect", e.Args.ImageName, e.Args.FilePath, e.Args.Created, e.Args.Libs).Return(
e.ReturnArgs.Vulns, e.ReturnArgs.Err)
}
return mockDetector
}
func (_m *MockDetector) Detect(a string, b []ptypes.Library) ([]types.DetectedVulnerability, error) {
ret := _m.Called(a, b)
func (_m *MockDetector) Detect(a, b string, c time.Time, d []ptypes.Library) ([]types.DetectedVulnerability, error) {
ret := _m.Called(a, b, c, d)
ret0 := ret.Get(0)
if ret0 == nil {
return nil, ret.Error(1)

View File

@@ -36,6 +36,7 @@ var (
"3.8": time.Date(2020, 5, 1, 23, 59, 59, 0, time.UTC),
"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),
}
)

View File

@@ -1,11 +1,15 @@
package ospkg
import (
"time"
"github.com/aquasecurity/trivy/pkg/detector/ospkg/alpine"
"github.com/aquasecurity/trivy/pkg/detector/ospkg/amazon"
"github.com/aquasecurity/trivy/pkg/detector/ospkg/debian"
"github.com/aquasecurity/trivy/pkg/detector/ospkg/oracle"
"github.com/aquasecurity/trivy/pkg/detector/ospkg/photon"
"github.com/aquasecurity/trivy/pkg/detector/ospkg/redhat"
"github.com/aquasecurity/trivy/pkg/detector/ospkg/suse"
"github.com/aquasecurity/trivy/pkg/detector/ospkg/ubuntu"
"github.com/aquasecurity/trivy/pkg/log"
"github.com/google/wire"
@@ -26,7 +30,7 @@ var (
)
type Operation interface {
Detect(string, string, []analyzer.Package) ([]types.DetectedVulnerability, bool, error)
Detect(string, string, string, time.Time, []analyzer.Package) ([]types.DetectedVulnerability, bool, error)
}
type Driver interface {
@@ -36,7 +40,7 @@ type Driver interface {
type Detector struct{}
func (d Detector) Detect(osFamily, osName string, pkgs []analyzer.Package) ([]types.DetectedVulnerability, bool, error) {
func (d Detector) Detect(_, osFamily, osName string, _ time.Time, pkgs []analyzer.Package) ([]types.DetectedVulnerability, bool, error) {
driver := newDriver(osFamily, osName)
if driver == nil {
return nil, false, ErrUnsupportedOS
@@ -68,6 +72,12 @@ func newDriver(osFamily, osName string) Driver {
d = amazon.NewScanner()
case fos.Oracle:
d = oracle.NewScanner()
case fos.OpenSUSELeap:
d = suse.NewScanner(suse.OpenSUSE)
case fos.SLES:
d = suse.NewScanner(suse.SUSEEnterpriseLinux)
case fos.Photon:
d = photon.NewScanner()
default:
log.Logger.Warnf("unsupported os : %s", osFamily)
return nil

View File

@@ -1,6 +1,8 @@
package ospkg
import (
"time"
"github.com/aquasecurity/fanal/analyzer"
"github.com/aquasecurity/trivy/pkg/types"
"github.com/stretchr/testify/mock"
@@ -11,9 +13,11 @@ type MockDetector struct {
}
type DetectInput struct {
OSFamily string
OSName string
Pkgs []analyzer.Package
ImageName string
OSFamily string
OSName string
Created time.Time
Pkgs []analyzer.Package
}
type DetectOutput struct {
Vulns []types.DetectedVulnerability
@@ -28,14 +32,14 @@ type DetectExpectation struct {
func NewMockDetector(detectExpectations []DetectExpectation) *MockDetector {
mockDetector := new(MockDetector)
for _, e := range detectExpectations {
mockDetector.On("Detect", e.Args.OSFamily, e.Args.OSName, e.Args.Pkgs).Return(
mockDetector.On("Detect", e.Args.ImageName, e.Args.OSFamily, e.Args.OSName, e.Args.Created, e.Args.Pkgs).Return(
e.ReturnArgs.Vulns, e.ReturnArgs.Eosl, e.ReturnArgs.Err)
}
return mockDetector
}
func (_m *MockDetector) Detect(a, b string, c []analyzer.Package) ([]types.DetectedVulnerability, bool, error) {
ret := _m.Called(a, b, c)
func (_m *MockDetector) Detect(a string, b string, c string, d time.Time, e []analyzer.Package) ([]types.DetectedVulnerability, bool, error) {
ret := _m.Called(a, b, c, d, e)
ret0 := ret.Get(0)
if ret0 == nil {
return nil, false, ret.Error(2)

View File

@@ -0,0 +1,68 @@
package photon
import (
"time"
"github.com/aquasecurity/trivy-db/pkg/vulnsrc/photon"
version "github.com/knqyf263/go-rpm-version"
"golang.org/x/xerrors"
"github.com/aquasecurity/fanal/analyzer"
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
"github.com/aquasecurity/trivy/pkg/log"
"github.com/aquasecurity/trivy/pkg/scanner/utils"
"github.com/aquasecurity/trivy/pkg/types"
"k8s.io/utils/clock"
)
var (
eolDates = map[string]time.Time{}
)
type Scanner struct {
vs dbTypes.VulnSrc
clock clock.Clock
}
func NewScanner() *Scanner {
return &Scanner{
vs: photon.NewVulnSrc(),
clock: clock.RealClock{},
}
}
func (s *Scanner) Detect(osVer string, pkgs []analyzer.Package) ([]types.DetectedVulnerability, error) {
log.Logger.Info("Detecting Photon Linux vulnerabilities...")
log.Logger.Debugf("Photon Linux: os version: %s", osVer)
log.Logger.Debugf("Photon Linux: the number of packages: %d", len(pkgs))
var vulns []types.DetectedVulnerability
for _, pkg := range pkgs {
advisories, err := s.vs.Get(osVer, pkg.SrcName)
if err != nil {
return nil, xerrors.Errorf("failed to get Photon Linux advisory: %w", err)
}
installed := utils.FormatVersion(pkg)
installedVersion := version.NewVersion(installed)
for _, adv := range advisories {
fixedVersion := version.NewVersion(adv.FixedVersion)
vuln := types.DetectedVulnerability{
VulnerabilityID: adv.VulnerabilityID,
PkgName: pkg.Name,
InstalledVersion: installed,
}
if installedVersion.LessThan(fixedVersion) {
vuln.FixedVersion = adv.FixedVersion
vulns = append(vulns, vuln)
}
}
}
return vulns, nil
}
func (s *Scanner) IsSupportedVersion(osFamily, osVer string) bool {
return true
}

View File

@@ -57,25 +57,42 @@ func (s *Scanner) Detect(osVer string, pkgs []analyzer.Package) ([]types.Detecte
var vulns []types.DetectedVulnerability
for _, pkg := range pkgs {
// For Red Hat Security Data API containing only source package names
advisories, err := s.vs.Get(osVer, pkg.SrcName)
if err != nil {
return nil, xerrors.Errorf("failed to get Red Hat advisories: %w", err)
}
installed := utils.FormatSrcVersion(pkg)
installed := utils.FormatVersion(pkg)
installedVersion := version.NewVersion(installed)
for _, adv := range advisories {
fixedVersion := version.NewVersion(adv.FixedVersion)
for _, adv := range advisories {
if adv.FixedVersion != "" {
continue
}
vuln := types.DetectedVulnerability{
VulnerabilityID: adv.VulnerabilityID,
PkgName: pkg.Name,
InstalledVersion: installed,
}
vulns = append(vulns, vuln)
}
// For Red Hat OVAL containing only binary package names
advisories, err = s.vs.Get(osVer, pkg.Name)
if err != nil {
return nil, xerrors.Errorf("failed to get Red Hat advisories: %w", err)
}
for _, adv := range advisories {
fixedVersion := version.NewVersion(adv.FixedVersion)
if installedVersion.LessThan(fixedVersion) {
vuln.FixedVersion = fixedVersion.String()
vulns = append(vulns, vuln)
} else if adv.FixedVersion == "" {
vuln := types.DetectedVulnerability{
VulnerabilityID: adv.VulnerabilityID,
PkgName: pkg.Name,
InstalledVersion: installed,
FixedVersion: fixedVersion.String(),
}
vulns = append(vulns, vuln)
}
}

View File

@@ -5,7 +5,14 @@ import (
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"golang.org/x/xerrors"
"github.com/aquasecurity/fanal/analyzer"
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
"github.com/aquasecurity/trivy/pkg/log"
"github.com/aquasecurity/trivy/pkg/types"
)
func TestMain(m *testing.M) {
@@ -13,6 +20,196 @@ func TestMain(m *testing.M) {
os.Exit(m.Run())
}
func TestScanner_Detect(t *testing.T) {
type args struct {
osVer string
pkgs []analyzer.Package
}
tests := []struct {
name string
args args
get []dbTypes.GetExpectation
want []types.DetectedVulnerability
wantErr bool
}{
{
name: "happy path: src pkg name is different from bin pkg name",
args: args{
osVer: "7.6",
pkgs: []analyzer.Package{
{
Name: "vim-minimal",
Version: "7.4.160",
Release: "5.el7",
Epoch: 2,
Arch: "x86_64",
SrcName: "vim",
SrcVersion: "7.4.160",
SrcRelease: "5.el7",
SrcEpoch: 2,
},
},
},
get: []dbTypes.GetExpectation{
{
Args: dbTypes.GetArgs{
Release: "7",
PkgName: "vim",
},
Returns: dbTypes.GetReturns{
Advisories: []dbTypes.Advisory{
{
VulnerabilityID: "CVE-2017-5953",
FixedVersion: "",
},
{
VulnerabilityID: "CVE-2017-6350",
FixedVersion: "",
},
},
},
},
{
Args: dbTypes.GetArgs{
Release: "7",
PkgName: "vim-minimal",
},
Returns: dbTypes.GetReturns{
Advisories: []dbTypes.Advisory{
{
VulnerabilityID: "CVE-2019-12735",
FixedVersion: "2:7.4.160-6.el7_6",
},
},
},
},
},
want: []types.DetectedVulnerability{
{
VulnerabilityID: "CVE-2017-5953",
PkgName: "vim-minimal",
InstalledVersion: "2:7.4.160-5.el7",
},
{
VulnerabilityID: "CVE-2017-6350",
PkgName: "vim-minimal",
InstalledVersion: "2:7.4.160-5.el7",
},
{
VulnerabilityID: "CVE-2019-12735",
PkgName: "vim-minimal",
InstalledVersion: "2:7.4.160-5.el7",
FixedVersion: "2:7.4.160-6.el7_6",
},
},
},
{
name: "happy path: src pkg name is the same as bin pkg name",
args: args{
osVer: "6.5",
pkgs: []analyzer.Package{
{
Name: "nss",
Version: "3.36.0",
Release: "7.1.el7_6",
Epoch: 0,
Arch: "x86_64",
SrcName: "nss",
SrcVersion: "3.36.0",
SrcRelease: "7.4.160",
SrcEpoch: 0,
},
},
},
get: []dbTypes.GetExpectation{
{
Args: dbTypes.GetArgs{
Release: "6",
PkgName: "nss",
},
Returns: dbTypes.GetReturns{
Advisories: []dbTypes.Advisory{
{
VulnerabilityID: "CVE-2015-2808",
FixedVersion: "",
},
{
VulnerabilityID: "CVE-2016-2183",
FixedVersion: "",
},
{
VulnerabilityID: "CVE-2018-12404",
FixedVersion: "3.44.0-4.el7",
},
},
},
},
},
want: []types.DetectedVulnerability{
{
VulnerabilityID: "CVE-2015-2808",
PkgName: "nss",
InstalledVersion: "3.36.0-7.1.el7_6",
},
{
VulnerabilityID: "CVE-2016-2183",
PkgName: "nss",
InstalledVersion: "3.36.0-7.1.el7_6",
},
{
VulnerabilityID: "CVE-2018-12404",
PkgName: "nss",
InstalledVersion: "3.36.0-7.1.el7_6",
FixedVersion: "3.44.0-4.el7",
},
},
},
{
name: "sad path: Get returns an error",
args: args{
osVer: "5",
pkgs: []analyzer.Package{
{
Name: "nss",
Version: "3.36.0",
Release: "7.1.el7_6",
Epoch: 0,
Arch: "x86_64",
SrcName: "nss",
SrcVersion: "3.36.0",
SrcRelease: "7.4.160",
SrcEpoch: 0,
},
},
},
get: []dbTypes.GetExpectation{
{
Args: dbTypes.GetArgs{
Release: "5",
PkgName: "nss",
},
Returns: dbTypes.GetReturns{
Err: xerrors.New("error"),
},
},
},
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
mockVs := new(dbTypes.MockVulnSrc)
mockVs.ApplyGetExpectations(tt.get)
s := &Scanner{
vs: mockVs,
}
got, err := s.Detect(tt.args.osVer, tt.args.pkgs)
require.Equal(t, tt.wantErr, err != nil)
assert.Equal(t, tt.want, got)
})
}
}
func TestScanner_IsSupportedVersion(t *testing.T) {
vectors := map[string]struct {
now time.Time

View File

@@ -0,0 +1,128 @@
package suse
import (
"time"
"github.com/aquasecurity/fanal/analyzer"
fos "github.com/aquasecurity/fanal/analyzer/os"
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
susecvrf "github.com/aquasecurity/trivy-db/pkg/vulnsrc/suse-cvrf"
"github.com/aquasecurity/trivy/pkg/log"
"github.com/aquasecurity/trivy/pkg/scanner/utils"
"github.com/aquasecurity/trivy/pkg/types"
version "github.com/knqyf263/go-rpm-version"
"golang.org/x/xerrors"
"k8s.io/utils/clock"
)
var (
slesEolDates = map[string]time.Time{
// Source: https://www.suse.com/lifecycle/
"10": time.Date(2007, 12, 31, 23, 59, 59, 0, time.UTC),
"10.1": time.Date(2008, 11, 30, 23, 59, 59, 0, time.UTC),
"10.2": time.Date(2010, 4, 11, 23, 59, 59, 0, time.UTC),
"10.3": time.Date(2011, 10, 11, 23, 59, 59, 0, time.UTC),
"10.4": time.Date(2013, 7, 31, 23, 59, 59, 0, time.UTC),
"11": time.Date(2010, 12, 31, 23, 59, 59, 0, time.UTC),
"11.1": time.Date(2012, 8, 31, 23, 59, 59, 0, time.UTC),
"11.2": time.Date(2014, 1, 31, 23, 59, 59, 0, time.UTC),
"11.3": time.Date(2016, 1, 31, 23, 59, 59, 0, time.UTC),
"11.4": time.Date(2019, 3, 31, 23, 59, 59, 0, time.UTC),
"12": time.Date(2016, 6, 30, 23, 59, 59, 0, time.UTC),
"12.1": time.Date(2017, 5, 31, 23, 59, 59, 0, time.UTC),
"12.2": time.Date(2018, 3, 31, 23, 59, 59, 0, time.UTC),
"12.3": time.Date(2019, 1, 30, 23, 59, 59, 0, time.UTC),
// 6 months after SLES12 SP5 release
// "12.4": time.Date(2024, 10, 31, 23, 59, 59, 0, time.UTC),
"15": time.Date(2019, 12, 31, 23, 59, 59, 0, time.UTC),
// 6 months after SLES 15 SP2 release
// "15.1": time.Date(2028, 7, 31, 23, 59, 59, 0, time.UTC),
}
opensuseEolDates = map[string]time.Time{
// Source: https://en.opensuse.org/Lifetime
"42.1": time.Date(2017, 5, 17, 23, 59, 59, 0, time.UTC),
"42.2": time.Date(2018, 1, 26, 23, 59, 59, 0, time.UTC),
"42.3": time.Date(2019, 6, 30, 23, 59, 59, 0, time.UTC),
"15.0": time.Date(2019, 12, 3, 23, 59, 59, 0, time.UTC),
"15.1": time.Date(2020, 11, 30, 23, 59, 59, 0, time.UTC),
"15.2": time.Date(2021, 11, 30, 23, 59, 59, 0, time.UTC),
}
)
type Scanner struct {
vs dbTypes.VulnSrc
clock clock.Clock
family string
}
type SUSEType int
const (
SUSEEnterpriseLinux SUSEType = iota
OpenSUSE
)
func NewScanner(t SUSEType) *Scanner {
switch t {
case SUSEEnterpriseLinux:
return &Scanner{
vs: susecvrf.NewVulnSrc(susecvrf.SUSEEnterpriseLinux),
clock: clock.RealClock{},
}
case OpenSUSE:
return &Scanner{
vs: susecvrf.NewVulnSrc(susecvrf.OpenSUSE),
clock: clock.RealClock{},
}
}
return nil
}
func (s *Scanner) Detect(osVer string, pkgs []analyzer.Package) ([]types.DetectedVulnerability, error) {
log.Logger.Info("Detecting SUSE vulnerabilities...")
log.Logger.Debugf("SUSE: os version: %s", osVer)
log.Logger.Debugf("SUSE: the number of packages: %d", len(pkgs))
var vulns []types.DetectedVulnerability
for _, pkg := range pkgs {
advisories, err := s.vs.Get(osVer, pkg.SrcName)
if err != nil {
return nil, xerrors.Errorf("failed to get SUSE advisory: %w", err)
}
installed := utils.FormatVersion(pkg)
installedVersion := version.NewVersion(installed)
for _, adv := range advisories {
fixedVersion := version.NewVersion(adv.FixedVersion)
vuln := types.DetectedVulnerability{
VulnerabilityID: adv.VulnerabilityID,
PkgName: pkg.Name,
InstalledVersion: installed,
}
if installedVersion.LessThan(fixedVersion) {
vuln.FixedVersion = adv.FixedVersion
vulns = append(vulns, vuln)
}
}
}
return vulns, nil
}
func (s *Scanner) IsSupportedVersion(osFamily, osVer string) bool {
var eolDate time.Time
var ok bool
if osFamily == fos.SLES {
eolDate, ok = slesEolDates[osVer]
} else if osFamily == fos.OpenSUSELeap {
eolDate, ok = opensuseEolDates[osVer]
}
if !ok {
log.Logger.Warnf("This OS version is not on the EOL list: %s %s", osFamily, osVer)
return false
}
return s.clock.Now().Before(eolDate)
}

View File

@@ -0,0 +1,92 @@
package suse
import (
"os"
"testing"
"time"
susecvrf "github.com/aquasecurity/trivy-db/pkg/vulnsrc/suse-cvrf"
"github.com/aquasecurity/trivy/pkg/log"
"k8s.io/utils/clock"
clocktesting "k8s.io/utils/clock/testing"
)
func TestMain(m *testing.M) {
log.InitLogger(false, false)
os.Exit(m.Run())
}
func TestScanner_IsSupportedVersion(t *testing.T) {
vectors := map[string]struct {
clock clock.Clock
osFamily string
osVersion string
distribution susecvrf.Distribution
expected bool
}{
"opensuse.leap42.3": {
clock: clocktesting.NewFakeClock(time.Date(2019, 5, 31, 23, 59, 59, 0, time.UTC)),
osFamily: "opensuse.leap",
osVersion: "42.3",
distribution: susecvrf.OpenSUSE,
expected: true,
},
"opensuse.leap15": {
clock: clocktesting.NewFakeClock(time.Date(2019, 5, 31, 23, 59, 59, 0, time.UTC)),
osFamily: "opensuse.leap",
osVersion: "15.0",
distribution: susecvrf.OpenSUSE,
expected: true,
},
"opensuse.leap15.1": {
clock: clocktesting.NewFakeClock(time.Date(2019, 5, 31, 23, 59, 59, 0, time.UTC)),
osFamily: "opensuse.leap",
osVersion: "15.1",
distribution: susecvrf.OpenSUSE,
expected: true,
},
"opensuse.leap15.1-sametime": {
clock: clocktesting.NewFakeClock(time.Date(2020, 11, 30, 23, 59, 59, 0, time.UTC)),
osFamily: "opensuse.leap",
osVersion: "15.1",
distribution: susecvrf.OpenSUSE,
expected: false,
},
"sles12.3": {
clock: clocktesting.NewFakeClock(time.Date(2019, 5, 31, 23, 59, 59, 0, time.UTC)),
osFamily: "suse linux enterprise server",
osVersion: "12.3",
distribution: susecvrf.SUSEEnterpriseLinux,
expected: false,
},
"sles15": {
clock: clocktesting.NewFakeClock(time.Date(2019, 5, 31, 23, 59, 59, 0, time.UTC)),
osFamily: "suse linux enterprise server",
osVersion: "15",
distribution: susecvrf.SUSEEnterpriseLinux,
expected: true,
},
"unknown": {
clock: clocktesting.NewFakeClock(time.Date(2019, 5, 31, 23, 59, 59, 0, time.UTC)),
osFamily: "oracle",
osVersion: "unknown",
distribution: susecvrf.SUSEEnterpriseLinux,
expected: false,
},
}
for testName, v := range vectors {
s := &Scanner{
vs: susecvrf.NewVulnSrc(v.distribution),
clock: v.clock,
}
t.Run(testName, func(t *testing.T) {
actual := s.IsSupportedVersion(v.osFamily, v.osVersion)
if actual != v.expected {
t.Errorf("[%s] got %v, want %v", testName, actual, v.expected)
}
})
}
}

View File

@@ -7,6 +7,7 @@ import (
"net/http"
"os"
"sort"
"strconv"
"strings"
"github.com/aquasecurity/trivy-db/pkg/db"
@@ -42,7 +43,7 @@ func (r Repository) DownloadAsset(ctx context.Context, id int64) (io.ReadCloser,
}
type Operation interface {
DownloadDB(ctx context.Context, fileName string) (io.ReadCloser, error)
DownloadDB(ctx context.Context, fileName string) (io.ReadCloser, int, error)
}
type Client struct {
@@ -72,11 +73,11 @@ func NewClient() Client {
}
}
func (c Client) DownloadDB(ctx context.Context, fileName string) (io.ReadCloser, error) {
func (c Client) DownloadDB(ctx context.Context, fileName string) (io.ReadCloser, int, error) {
options := github.ListOptions{}
releases, _, err := c.Repository.ListReleases(ctx, &options)
if err != nil {
return nil, xerrors.Errorf("failed to list releases: %w", err)
return nil, 0, xerrors.Errorf("failed to list releases: %w", err)
}
sort.Slice(releases, func(i, j int) bool {
@@ -91,37 +92,42 @@ func (c Client) DownloadDB(ctx context.Context, fileName string) (io.ReadCloser,
}
for _, asset := range release.Assets {
rc, err := c.downloadAsset(ctx, asset, fileName)
rc, size, err := c.downloadAsset(ctx, asset, fileName)
if err != nil {
log.Logger.Debug(err)
continue
}
return rc, nil
return rc, size, nil
}
}
return nil, xerrors.New("DB file not found")
return nil, 0, xerrors.New("DB file not found")
}
func (c Client) downloadAsset(ctx context.Context, asset github.ReleaseAsset, fileName string) (io.ReadCloser, error) {
func (c Client) downloadAsset(ctx context.Context, asset github.ReleaseAsset, fileName string) (io.ReadCloser, int, error) {
log.Logger.Debugf("asset name: %s", asset.GetName())
if asset.GetName() != fileName {
return nil, xerrors.New("file name doesn't match")
return nil, 0, xerrors.New("file name doesn't match")
}
rc, url, err := c.Repository.DownloadAsset(ctx, asset.GetID())
if err != nil {
return nil, xerrors.Errorf("unable to download the asset: %w", err)
return nil, 0, xerrors.Errorf("unable to download the asset: %w", err)
}
if rc != nil {
return rc, nil
return rc, asset.GetSize(), nil
}
log.Logger.Debugf("asset URL: %s", url)
resp, err := http.Get(url)
if err != nil || resp.StatusCode != http.StatusOK {
return nil, xerrors.Errorf("unable to download the asset via URL: %w", err)
return nil, 0, xerrors.Errorf("unable to download the asset via URL: %w", err)
}
return resp.Body, nil
size, err := strconv.Atoi(resp.Header.Get("Content-Length"))
if err != nil {
return nil, 0, xerrors.Errorf("invalid size: %w", err)
}
return resp.Body, size, nil
}

View File

@@ -3,6 +3,7 @@ package github
import (
"context"
"io"
"os"
"github.com/stretchr/testify/mock"
)
@@ -11,15 +12,46 @@ type MockClient struct {
mock.Mock
}
func (_m *MockClient) DownloadDB(ctx context.Context, fileName string) (io.ReadCloser, error) {
type DownloadDBInput struct {
FileName string
}
type DownloadDBOutput struct {
FileName string
Size int
Err error
}
type DownloadDBExpectation struct {
Args DownloadDBInput
ReturnArgs DownloadDBOutput
}
func NewMockClient(downloadDBExpectations []DownloadDBExpectation) (*MockClient, error) {
mockDetector := new(MockClient)
for _, e := range downloadDBExpectations {
var rc io.ReadCloser
if e.ReturnArgs.FileName != "" {
f, err := os.Open(e.ReturnArgs.FileName)
if err != nil {
return nil, err
}
rc = f
}
mockDetector.On("DownloadDB", mock.Anything, e.Args.FileName).Return(
rc, e.ReturnArgs.Size, e.ReturnArgs.Err)
}
return mockDetector, nil
}
func (_m *MockClient) DownloadDB(ctx context.Context, fileName string) (io.ReadCloser, int, error) {
ret := _m.Called(ctx, fileName)
ret0 := ret.Get(0)
if ret0 == nil {
return nil, ret.Error(1)
return nil, ret.Int(1), ret.Error(2)
}
rc, ok := ret0.(io.ReadCloser)
if !ok {
return nil, ret.Error(1)
return nil, ret.Int(1), ret.Error(2)
}
return rc, ret.Error(1)
return rc, ret.Int(1), ret.Error(2)
}

View File

@@ -451,7 +451,7 @@ func TestClient_DownloadDB(t *testing.T) {
}
ctx := context.Background()
rc, err := client.DownloadDB(ctx, tc.fileName)
rc, _, err := client.DownloadDB(ctx, tc.fileName)
switch {
case tc.expectedError != nil:

40
pkg/indicator/progress.go Normal file
View File

@@ -0,0 +1,40 @@
package indicator
import (
"io"
"github.com/cheggaaa/pb/v3"
)
type ProgressBar struct {
quiet bool
}
func NewProgressBar(quiet bool) ProgressBar {
return ProgressBar{quiet: quiet}
}
func (p ProgressBar) Start(total int64) Bar {
if p.quiet {
return Bar{}
}
bar := pb.Full.Start64(total)
return Bar{bar: bar}
}
type Bar struct {
bar *pb.ProgressBar
}
func (b Bar) NewProxyReader(r io.Reader) io.Reader {
if b.bar == nil {
return r
}
return b.bar.NewProxyReader(r)
}
func (b Bar) Finish() {
if b.bar == nil {
return
}
b.bar.Finish()
}

View File

@@ -19,7 +19,7 @@ import (
type Results []Result
type Result struct {
FileName string `json:"Target"`
Target string `json:"Target"`
Vulnerabilities []types.DetectedVulnerability `json:"Vulnerabilities"`
}
@@ -101,8 +101,8 @@ func (tw TableWriter) write(result Result) {
results = append(results, r)
}
fmt.Printf("\n%s\n", result.FileName)
fmt.Println(strings.Repeat("=", len(result.FileName)))
fmt.Printf("\n%s\n", result.Target)
fmt.Println(strings.Repeat("=", len(result.Target)))
fmt.Printf("Total: %d (%s)\n\n", len(result.Vulnerabilities), strings.Join(results, ", "))
if len(result.Vulnerabilities) == 0 {

View File

@@ -117,7 +117,7 @@ func TestReportWriter_Table(t *testing.T) {
t.Run(tc.name, func(t *testing.T) {
inputResults := report.Results{
{
FileName: "foo",
Target: "foo",
Vulnerabilities: tc.detectedVulns,
},
}
@@ -151,7 +151,7 @@ func TestReportWriter_JSON(t *testing.T) {
},
expectedJSON: report.Results{
report.Result{
FileName: "foojson",
Target: "foojson",
Vulnerabilities: []types.DetectedVulnerability{
{
VulnerabilityID: "123",
@@ -179,7 +179,7 @@ func TestReportWriter_JSON(t *testing.T) {
inputResults := report.Results{
{
FileName: "foojson",
Target: "foojson",
Vulnerabilities: tc.detectedVulns,
},
}
@@ -236,7 +236,7 @@ func TestReportWriter_Template(t *testing.T) {
tmplWritten := bytes.Buffer{}
inputResults := report.Results{
{
FileName: "foojson",
Target: "foojson",
Vulnerabilities: tc.detectedVulns,
},
}

20
pkg/rpc/client/headers.go Normal file
View File

@@ -0,0 +1,20 @@
package client
import (
"context"
"net/http"
"github.com/twitchtv/twirp"
"github.com/aquasecurity/trivy/pkg/log"
)
func WithCustomHeaders(ctx context.Context, customHeaders http.Header) context.Context {
// Attach the headers to a context
ctxWithToken, err := twirp.WithHTTPRequestHeaders(ctx, customHeaders)
if err != nil {
log.Logger.Warnf("twirp error setting headers: %s", err)
return ctx
}
return ctxWithToken
}

View File

@@ -0,0 +1,59 @@
package client
import (
"context"
"net/http"
"os"
"testing"
"github.com/twitchtv/twirp"
"github.com/aquasecurity/trivy/pkg/log"
"github.com/stretchr/testify/assert"
)
func TestMain(m *testing.M) {
_ = log.InitLogger(false, true)
os.Exit(m.Run())
}
func TestWithCustomHeaders(t *testing.T) {
type args struct {
ctx context.Context
customHeaders http.Header
}
tests := []struct {
name string
args args
want http.Header
}{
{
name: "happy path",
args: args{
ctx: context.Background(),
customHeaders: http.Header{
"Trivy-Token": []string{"token"},
},
},
want: http.Header{
"Trivy-Token": []string{"token"},
},
},
{
name: "sad path, invalid headers passed in",
args: args{
ctx: context.Background(),
customHeaders: http.Header{
"Content-Type": []string{"token"},
},
},
want: http.Header(nil),
},
}
for _, tt := range tests {
gotCtx := WithCustomHeaders(tt.args.ctx, tt.args.customHeaders)
header, _ := twirp.HTTPRequestHeaders(gotCtx)
assert.Equal(t, tt.want, header, tt.name)
}
}

View File

@@ -3,15 +3,18 @@ package library
import (
"context"
"net/http"
"time"
"github.com/aquasecurity/trivy/pkg/rpc/client"
"github.com/golang/protobuf/ptypes"
"github.com/golang/protobuf/ptypes/timestamp"
"github.com/google/wire"
"golang.org/x/xerrors"
ptypes "github.com/aquasecurity/go-dep-parser/pkg/types"
depptypes "github.com/aquasecurity/go-dep-parser/pkg/types"
detector "github.com/aquasecurity/trivy/pkg/detector/library"
"github.com/aquasecurity/trivy/pkg/log"
r "github.com/aquasecurity/trivy/pkg/rpc"
"github.com/aquasecurity/trivy/pkg/rpc/client"
"github.com/aquasecurity/trivy/pkg/types"
rpc "github.com/aquasecurity/trivy/rpc/detector"
)
@@ -28,22 +31,36 @@ func NewProtobufClient(remoteURL RemoteURL) rpc.LibDetector {
return rpc.NewLibDetectorProtobufClient(string(remoteURL), &http.Client{})
}
type Token string
type CustomHeaders http.Header
type Detector struct {
token Token
client rpc.LibDetector
customHeaders CustomHeaders
client rpc.LibDetector
}
func NewDetector(token Token, detector rpc.LibDetector) Detector {
return Detector{token: token, client: detector}
func NewDetector(customHeaders CustomHeaders, detector rpc.LibDetector) Detector {
return Detector{customHeaders: customHeaders, client: detector}
}
func (d Detector) Detect(filePath string, libs []ptypes.Library) ([]types.DetectedVulnerability, error) {
ctx := client.WithToken(context.Background(), string(d.token))
res, err := d.client.Detect(ctx, &rpc.LibDetectRequest{
FilePath: filePath,
Libraries: r.ConvertToRpcLibraries(libs),
func (d Detector) Detect(imageName, filePath string, created time.Time, libs []depptypes.Library) ([]types.DetectedVulnerability, error) {
ctx := client.WithCustomHeaders(context.Background(), http.Header(d.customHeaders))
var res *rpc.DetectResponse
err := r.Retry(func() error {
var err error
res, err = d.client.Detect(ctx, &rpc.LibDetectRequest{
ImageName: imageName,
FilePath: filePath,
Libraries: r.ConvertToRpcLibraries(libs),
Created: func() *timestamp.Timestamp {
t, err := ptypes.TimestampProto(created)
if err != nil {
log.Logger.Warnf("invalid timestamp: %s", err)
}
return t
}(),
})
return err
})
if err != nil {
return nil, xerrors.Errorf("failed to detect vulnerabilities via RPC: %w", err)

View File

@@ -3,14 +3,18 @@ package library
import (
"context"
"testing"
"time"
"golang.org/x/xerrors"
"github.com/golang/protobuf/ptypes"
"github.com/golang/protobuf/ptypes/timestamp"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
ptypes "github.com/aquasecurity/go-dep-parser/pkg/types"
deptypes "github.com/aquasecurity/go-dep-parser/pkg/types"
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
"github.com/aquasecurity/trivy/pkg/types"
"github.com/aquasecurity/trivy/rpc/detector"
@@ -48,11 +52,14 @@ func TestDetectClient_Detect(t *testing.T) {
}
type fields struct {
token Token
customHeaders CustomHeaders
}
type args struct {
filePath string
libs []ptypes.Library
imageName string
filePath string
created time.Time
libs []deptypes.Library
}
tests := []struct {
name string
@@ -65,17 +72,27 @@ func TestDetectClient_Detect(t *testing.T) {
{
name: "happy path",
fields: fields{
token: "token",
customHeaders: CustomHeaders{
"Trivy-Token": []string{"token"},
},
},
args: args{
filePath: "app/Pipfile.lock",
libs: []ptypes.Library{
imageName: "/tmp/alpine.tar",
filePath: "app/Pipfile.lock",
created: time.Date(2019, 1, 1, 0, 0, 0, 0, time.UTC),
libs: []deptypes.Library{
{Name: "django", Version: "3.0.0"},
},
},
detect: detect{
input: detectInput{req: &detector.LibDetectRequest{
FilePath: "app/Pipfile.lock",
ImageName: "/tmp/alpine.tar",
FilePath: "app/Pipfile.lock",
Created: func() *timestamp.Timestamp {
d := time.Date(2019, 1, 1, 0, 0, 0, 0, time.UTC)
t, _ := ptypes.TimestampProto(d)
return t
}(),
Libraries: []*detector.Library{
{Name: "django", Version: "3.0.0"},
},
@@ -115,17 +132,25 @@ func TestDetectClient_Detect(t *testing.T) {
name: "Detect returns an error",
fields: fields{},
args: args{
filePath: "app/Pipfile.lock",
libs: []ptypes.Library{
imageName: "/tmp/alpine.tar",
filePath: "app/Pipfile.lock",
created: time.Date(2019, 2, 1, 0, 0, 0, 0, time.UTC),
libs: []deptypes.Library{
{Name: "django", Version: "3.0.0"},
},
},
detect: detect{
input: detectInput{req: &detector.LibDetectRequest{
FilePath: "app/Pipfile.lock",
ImageName: "/tmp/alpine.tar",
FilePath: "app/Pipfile.lock",
Libraries: []*detector.Library{
{Name: "django", Version: "3.0.0"},
},
Created: func() *timestamp.Timestamp {
d := time.Date(2019, 2, 1, 0, 0, 0, 0, time.UTC)
t, _ := ptypes.TimestampProto(d)
return t
}(),
},
},
output: detectOutput{
@@ -141,8 +166,8 @@ func TestDetectClient_Detect(t *testing.T) {
mockDetector.On("Detect", mock.Anything, tt.detect.input.req).Return(
tt.detect.output.res, tt.detect.output.err)
d := NewDetector(tt.fields.token, mockDetector)
got, err := d.Detect(tt.args.filePath, tt.args.libs)
d := NewDetector(tt.fields.customHeaders, mockDetector)
got, err := d.Detect(tt.args.imageName, tt.args.filePath, tt.args.created, tt.args.libs)
if tt.wantErr != "" {
require.NotNil(t, err, tt.name)
assert.Contains(t, err.Error(), tt.wantErr, tt.name)

View File

@@ -3,8 +3,12 @@ package ospkg
import (
"context"
"net/http"
"time"
"github.com/aquasecurity/trivy/pkg/rpc/client"
"github.com/aquasecurity/trivy/pkg/log"
"github.com/golang/protobuf/ptypes"
"github.com/golang/protobuf/ptypes/timestamp"
"github.com/google/wire"
"golang.org/x/xerrors"
@@ -12,6 +16,7 @@ import (
"github.com/aquasecurity/fanal/analyzer"
detector "github.com/aquasecurity/trivy/pkg/detector/ospkg"
r "github.com/aquasecurity/trivy/pkg/rpc"
"github.com/aquasecurity/trivy/pkg/rpc/client"
"github.com/aquasecurity/trivy/pkg/types"
rpc "github.com/aquasecurity/trivy/rpc/detector"
)
@@ -28,23 +33,37 @@ func NewProtobufClient(remoteURL RemoteURL) rpc.OSDetector {
return rpc.NewOSDetectorProtobufClient(string(remoteURL), &http.Client{})
}
type Token string
type CustomHeaders http.Header
type Detector struct {
token Token
client rpc.OSDetector
customHeaders CustomHeaders
client rpc.OSDetector
}
func NewDetector(token Token, detector rpc.OSDetector) Detector {
return Detector{token: token, client: detector}
func NewDetector(customHeaders CustomHeaders, detector rpc.OSDetector) Detector {
return Detector{customHeaders: customHeaders, client: detector}
}
func (d Detector) Detect(osFamily, osName string, pkgs []analyzer.Package) ([]types.DetectedVulnerability, bool, error) {
ctx := client.WithToken(context.Background(), string(d.token))
res, err := d.client.Detect(ctx, &rpc.OSDetectRequest{
OsFamily: osFamily,
OsName: osName,
Packages: r.ConvertToRpcPkgs(pkgs),
func (d Detector) Detect(imageName, osFamily, osName string, created time.Time, pkgs []analyzer.Package) ([]types.DetectedVulnerability, bool, error) {
ctx := client.WithCustomHeaders(context.Background(), http.Header(d.customHeaders))
var res *rpc.DetectResponse
err := r.Retry(func() error {
var err error
res, err = d.client.Detect(ctx, &rpc.OSDetectRequest{
ImageName: imageName,
OsFamily: osFamily,
OsName: osName,
Created: func() *timestamp.Timestamp {
t, err := ptypes.TimestampProto(created)
if err != nil {
log.Logger.Warnf("invalid timestamp: %s", err)
}
return t
}(),
Packages: r.ConvertToRpcPkgs(pkgs),
})
return err
})
if err != nil {
return nil, false, xerrors.Errorf("failed to detect vulnerabilities via RPC: %w", err)

View File

@@ -3,18 +3,18 @@ package ospkg
import (
"context"
"testing"
"golang.org/x/xerrors"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"time"
"github.com/aquasecurity/fanal/analyzer"
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
"github.com/aquasecurity/trivy/pkg/types"
"github.com/aquasecurity/trivy/rpc/detector"
"github.com/golang/protobuf/ptypes"
"github.com/golang/protobuf/ptypes/timestamp"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
"golang.org/x/xerrors"
)
type mockDetector struct {
@@ -48,12 +48,14 @@ func TestDetectClient_Detect(t *testing.T) {
}
type fields struct {
token Token
customHeaders CustomHeaders
}
type args struct {
osFamily string
osName string
pkgs []analyzer.Package
imageName string
osFamily string
osName string
created time.Time
pkgs []analyzer.Package
}
tests := []struct {
name string
@@ -66,11 +68,15 @@ func TestDetectClient_Detect(t *testing.T) {
{
name: "happy path",
fields: fields{
token: "token",
customHeaders: CustomHeaders{
"Trivy-Token": []string{"token"},
},
},
args: args{
osFamily: "alpine",
osName: "3.10.2",
imageName: "alpine:3.10.2",
osFamily: "alpine",
osName: "3.10.2",
created: time.Unix(1581498560, 0),
pkgs: []analyzer.Package{
{
Name: "openssl",
@@ -83,8 +89,13 @@ func TestDetectClient_Detect(t *testing.T) {
detect: detect{
input: detectInput{
req: &detector.OSDetectRequest{
OsFamily: "alpine",
OsName: "3.10.2",
OsFamily: "alpine",
OsName: "3.10.2",
ImageName: "alpine:3.10.2",
Created: func() *timestamp.Timestamp {
t, _ := ptypes.TimestampProto(time.Unix(1581498560, 0))
return t
}(),
Packages: []*detector.Package{
{
Name: "openssl",
@@ -129,8 +140,10 @@ func TestDetectClient_Detect(t *testing.T) {
name: "Detect returns an error",
fields: fields{},
args: args{
osFamily: "alpine",
osName: "3.10.2",
imageName: "alpine:3.10.2",
osFamily: "alpine",
osName: "3.10.2",
created: time.Unix(1581498560, 0),
pkgs: []analyzer.Package{
{
Name: "openssl",
@@ -143,8 +156,13 @@ func TestDetectClient_Detect(t *testing.T) {
detect: detect{
input: detectInput{
req: &detector.OSDetectRequest{
OsFamily: "alpine",
OsName: "3.10.2",
ImageName: "alpine:3.10.2",
OsFamily: "alpine",
OsName: "3.10.2",
Created: func() *timestamp.Timestamp {
t, _ := ptypes.TimestampProto(time.Unix(1581498560, 0))
return t
}(),
Packages: []*detector.Package{
{
Name: "openssl",
@@ -168,8 +186,8 @@ func TestDetectClient_Detect(t *testing.T) {
mockDetector.On("Detect", mock.Anything, tt.detect.input.req).Return(
tt.detect.output.res, tt.detect.output.err)
d := NewDetector(tt.fields.token, mockDetector)
got, _, err := d.Detect(tt.args.osFamily, tt.args.osName, tt.args.pkgs)
d := NewDetector(tt.fields.customHeaders, mockDetector)
got, _, err := d.Detect(tt.args.imageName, tt.args.osFamily, tt.args.osName, tt.args.created, tt.args.pkgs)
if tt.wantErr != "" {
require.NotNil(t, err, tt.name)
assert.Contains(t, err.Error(), tt.wantErr, tt.name)

View File

@@ -1,35 +0,0 @@
package client
import (
"context"
"net/http"
"github.com/twitchtv/twirp"
"github.com/aquasecurity/trivy/pkg/log"
)
var (
buildRequestHeaderFunc = buildRequestHeader
)
func buildRequestHeader(inputHeaders map[string]string) http.Header {
header := make(http.Header)
for k, v := range inputHeaders {
header.Set(k, v)
}
return header
}
func WithToken(ctx context.Context, token string) context.Context {
// Prepare custom header
header := buildRequestHeaderFunc(map[string]string{"Trivy-Token": token})
// Attach the headers to a context
ctxWithToken, err := twirp.WithHTTPRequestHeaders(ctx, header)
if err != nil {
log.Logger.Warnf("twirp error setting headers: %s", err)
return ctx
}
return ctxWithToken
}

View File

@@ -1,72 +0,0 @@
package client
import (
"context"
"net/http"
"os"
"testing"
"github.com/twitchtv/twirp"
"github.com/aquasecurity/trivy/pkg/log"
"github.com/stretchr/testify/assert"
)
func TestMain(m *testing.M) {
_ = log.InitLogger(false, true)
os.Exit(m.Run())
}
func TestWithToken(t *testing.T) {
type args struct {
ctx context.Context
token string
}
tests := []struct {
name string
args args
buildRequestHeaderFunc func(map[string]string) http.Header
want http.Header
}{
{
name: "happy path",
args: args{
ctx: context.Background(),
token: "token",
},
want: http.Header{
"Trivy-Token": []string{"token"},
},
buildRequestHeaderFunc: buildRequestHeader,
},
{
name: "sad path, invalid headers passed in",
args: args{
ctx: context.Background(),
token: "token",
},
want: http.Header(nil),
buildRequestHeaderFunc: func(m map[string]string) http.Header {
header := make(http.Header)
for k, v := range m {
header.Set(k, v)
}
// add an extra header that is reserved for twirp
header.Set("Content-Type", "foobar")
return header
},
},
}
for _, tt := range tests {
oldbuildRequestHeaderFunc := buildRequestHeaderFunc
defer func() {
buildRequestHeaderFunc = oldbuildRequestHeaderFunc
}()
buildRequestHeaderFunc = tt.buildRequestHeaderFunc
gotCtx := WithToken(tt.args.ctx, tt.args.token)
header, _ := twirp.HTTPRequestHeaders(gotCtx)
assert.Equal(t, tt.want, header, tt.name)
}
}

40
pkg/rpc/retry.go Normal file
View File

@@ -0,0 +1,40 @@
package rpc
import (
"time"
"github.com/aquasecurity/trivy/pkg/log"
"github.com/cenkalti/backoff"
"github.com/twitchtv/twirp"
)
const (
maxRetries = 10
)
func Retry(f func() error) error {
operation := func() error {
err := f()
if err != nil {
twerr, ok := err.(twirp.Error)
if !ok {
return backoff.Permanent(err)
}
if twerr.Code() == twirp.Unavailable {
return err
}
return backoff.Permanent(err)
}
return nil
}
b := backoff.WithMaxRetries(backoff.NewExponentialBackOff(), maxRetries)
err := backoff.RetryNotify(operation, b, func(err error, _ time.Duration) {
log.Logger.Warn(err)
log.Logger.Info("Retrying HTTP request...")
})
if err != nil {
return err
}
return nil
}

View File

@@ -19,7 +19,7 @@ func initializeLibServer() *library.Server {
return &library.Server{}
}
func initializeDBWorker() dbWorker {
func initializeDBWorker(quiet bool) dbWorker {
wire.Build(SuperSet)
return dbWorker{}
}

View File

@@ -2,6 +2,7 @@ package library
import (
"context"
"time"
"github.com/google/wire"
"golang.org/x/xerrors"
@@ -28,8 +29,8 @@ func NewServer(detector detector.Operation, vulnClient vulnerability.Operation)
return &Server{detector: detector, vulnClient: vulnClient}
}
func (s *Server) Detect(ctx context.Context, req *proto.LibDetectRequest) (res *proto.DetectResponse, err error) {
vulns, err := s.detector.Detect(req.FilePath, rpc.ConvertFromRpcLibraries(req.Libraries))
func (s *Server) Detect(_ context.Context, req *proto.LibDetectRequest) (res *proto.DetectResponse, err error) {
vulns, err := s.detector.Detect("", req.FilePath, time.Time{}, rpc.ConvertFromRpcLibraries(req.Libraries))
if err != nil {
err = xerrors.Errorf("failed to detect library vulnerabilities: %w", err)
log.Logger.Error(err)

View File

@@ -42,7 +42,8 @@ func TestServer_Detect(t *testing.T) {
name: "happy path",
args: args{
req: &proto.LibDetectRequest{
FilePath: "app/Pipfile.lock",
ImageName: "alpine:3.10",
FilePath: "app/Pipfile.lock",
Libraries: []*proto.Library{
{Name: "django", Version: "3.0.0"},
},
@@ -91,7 +92,8 @@ func TestServer_Detect(t *testing.T) {
name: "Detect returns an error",
args: args{
req: &proto.LibDetectRequest{
FilePath: "app/Pipfile.lock",
ImageName: "alpine:3.10",
FilePath: "app/Pipfile.lock",
Libraries: []*proto.Library{
{Name: "django", Version: "3.0.0"},
},

View File

@@ -2,6 +2,7 @@ package ospkg
import (
"context"
"time"
"github.com/google/wire"
"golang.org/x/xerrors"
@@ -29,7 +30,7 @@ func NewServer(detector detector.Operation, vulnClient vulnerability.Operation)
}
func (s *Server) Detect(ctx context.Context, req *proto.OSDetectRequest) (res *proto.DetectResponse, err error) {
vulns, eosl, err := s.detector.Detect(req.OsFamily, req.OsName, rpc.ConvertFromRpcPkgs(req.Packages))
vulns, eosl, err := s.detector.Detect("", req.OsFamily, req.OsName, time.Time{}, rpc.ConvertFromRpcPkgs(req.Packages))
if err != nil {
err = xerrors.Errorf("failed to detect vulnerabilities of OS packages: %w", err)
log.Logger.Error(err)

View File

@@ -45,7 +45,7 @@ func ListenAndServe(addr string, c config.Config) error {
}
go func() {
worker := initializeDBWorker()
worker := initializeDBWorker(true)
ctx := context.Background()
for {
time.Sleep(1 * time.Hour)
@@ -58,19 +58,19 @@ func ListenAndServe(addr string, c config.Config) error {
mux := http.NewServeMux()
osHandler := rpc.NewOSDetectorServer(initializeOspkgServer(), nil)
mux.Handle(rpc.OSDetectorPathPrefix, withToken(withWaitGroup(osHandler), c.Token))
mux.Handle(rpc.OSDetectorPathPrefix, withToken(withWaitGroup(osHandler), c.Token, c.TokenHeader))
libHandler := rpc.NewLibDetectorServer(initializeLibServer(), nil)
mux.Handle(rpc.LibDetectorPathPrefix, withToken(withWaitGroup(libHandler), c.Token))
mux.Handle(rpc.LibDetectorPathPrefix, withToken(withWaitGroup(libHandler), c.Token, c.TokenHeader))
log.Logger.Infof("Listening %s...", addr)
return http.ListenAndServe(addr, mux)
}
func withToken(base http.Handler, token string) http.Handler {
func withToken(base http.Handler, token, tokenHeader string) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if token != "" && token != r.Header.Get("Trivy-Token") {
if token != "" && token != r.Header.Get(tokenHeader) {
rpc.WriteError(w, twirp.NewError(twirp.Unauthenticated, "invalid token"))
return
}

View File

@@ -11,6 +11,7 @@ import (
library2 "github.com/aquasecurity/trivy/pkg/detector/library"
ospkg2 "github.com/aquasecurity/trivy/pkg/detector/ospkg"
"github.com/aquasecurity/trivy/pkg/github"
"github.com/aquasecurity/trivy/pkg/indicator"
"github.com/aquasecurity/trivy/pkg/rpc/server/library"
"github.com/aquasecurity/trivy/pkg/rpc/server/ospkg"
"github.com/aquasecurity/trivy/pkg/vulnerability"
@@ -36,11 +37,12 @@ func initializeLibServer() *library.Server {
return server
}
func initializeDBWorker() dbWorker {
func initializeDBWorker(quiet bool) dbWorker {
config := db.Config{}
client := github.NewClient()
progressBar := indicator.NewProgressBar(quiet)
realClock := clock.RealClock{}
dbClient := db2.NewClient(config, client, realClock)
dbClient := db2.NewClient(config, client, progressBar, realClock)
serverDbWorker := newDBWorker(dbClient)
return serverDbWorker
}

View File

@@ -1,8 +1,7 @@
package library
import (
"io/ioutil"
"os"
"time"
detector "github.com/aquasecurity/trivy/pkg/detector/library"
@@ -27,7 +26,7 @@ func NewScanner(detector detector.Operation) Scanner {
return Scanner{detector: detector}
}
func (s Scanner) Scan(files extractor.FileMap) (map[string][]types.DetectedVulnerability, error) {
func (s Scanner) Scan(imageName string, created time.Time, files extractor.FileMap) (map[string][]types.DetectedVulnerability, error) {
results, err := analyzer.GetLibraries(files)
if err != nil {
return nil, xerrors.Errorf("failed to analyze libraries: %w", err)
@@ -35,7 +34,7 @@ func (s Scanner) Scan(files extractor.FileMap) (map[string][]types.DetectedVulne
vulnerabilities := map[string][]types.DetectedVulnerability{}
for path, libs := range results {
vulns, err := s.detector.Detect(string(path), libs)
vulns, err := s.detector.Detect(imageName, string(path), created, libs)
if err != nil {
return nil, xerrors.Errorf("failed library scan: %w", err)
}
@@ -44,24 +43,3 @@ func (s Scanner) Scan(files extractor.FileMap) (map[string][]types.DetectedVulne
}
return vulnerabilities, nil
}
func (s Scanner) ScanFile(f *os.File) ([]types.DetectedVulnerability, error) {
content, err := ioutil.ReadAll(f)
if err != nil {
return nil, err
}
files := extractor.FileMap{
f.Name(): content,
}
results, err := s.Scan(files)
if err != nil {
return nil, err
}
// need only 1 result
for _, vulns := range results {
return vulns, nil
}
return nil, nil
}

View File

@@ -2,6 +2,7 @@ package library
import (
"testing"
"time"
library2 "github.com/aquasecurity/trivy/pkg/detector/library"
@@ -17,8 +18,10 @@ import (
func TestScanner_Scan(t *testing.T) {
type detectInput struct {
filePath string
libs []ptypes.Library
imageName string
filePath string
created time.Time
libs []ptypes.Library
}
type detectOutput struct {
vulns []types.DetectedVulnerability
@@ -29,7 +32,9 @@ func TestScanner_Scan(t *testing.T) {
output detectOutput
}
type args struct {
files extractor.FileMap
imageName string
created time.Time
files extractor.FileMap
}
tests := []struct {
name string
@@ -41,6 +46,8 @@ func TestScanner_Scan(t *testing.T) {
{
name: "happy",
args: args{
imageName: "alpine:3.10",
created: time.Date(2019, 5, 11, 0, 7, 3, 510395965, time.UTC),
files: extractor.FileMap{
"app/Pipfile.lock": []byte(`{
"_meta": {
@@ -94,7 +101,9 @@ func TestScanner_Scan(t *testing.T) {
detect: []detect{
{
input: detectInput{
filePath: "app/Pipfile.lock",
imageName: "alpine:3.10",
filePath: "app/Pipfile.lock",
created: time.Date(2019, 5, 11, 0, 7, 3, 510395965, time.UTC),
libs: []ptypes.Library{
{Name: "django", Version: "3.0.0"},
},
@@ -107,7 +116,9 @@ func TestScanner_Scan(t *testing.T) {
},
{
input: detectInput{
filePath: "app/package-lock.json",
imageName: "alpine:3.10",
filePath: "app/package-lock.json",
created: time.Date(2019, 5, 11, 0, 7, 3, 510395965, time.UTC),
libs: []ptypes.Library{
{Name: "react", Version: "16.8.6"},
},
@@ -131,6 +142,8 @@ func TestScanner_Scan(t *testing.T) {
{
name: "broken lock file",
args: args{
imageName: "alpine:3.10",
created: time.Date(2019, 5, 11, 0, 7, 3, 510395965, time.UTC),
files: extractor.FileMap{
"app/Pipfile.lock": []byte(`{broken}`),
},
@@ -179,14 +192,14 @@ func TestScanner_Scan(t *testing.T) {
t.Run(tt.name, func(t *testing.T) {
mockDetector := new(library2.MockDetector)
for _, d := range tt.detect {
mockDetector.On("Detect", d.input.filePath, d.input.libs).Return(
mockDetector.On("Detect", d.input.imageName, d.input.filePath, d.input.created, d.input.libs).Return(
d.output.vulns, d.output.err)
}
s := Scanner{
detector: mockDetector,
}
got, err := s.Scan(tt.args.files)
got, err := s.Scan(tt.args.imageName, tt.args.created, tt.args.files)
if tt.wantErr != "" {
require.NotNil(t, err, tt.name)
assert.Contains(t, err.Error(), tt.wantErr, tt.name)

View File

@@ -1,6 +1,8 @@
package ospkg
import (
"time"
"golang.org/x/xerrors"
"github.com/aquasecurity/fanal/analyzer"
@@ -8,8 +10,9 @@ import (
_ "github.com/aquasecurity/fanal/analyzer/os/alpine"
_ "github.com/aquasecurity/fanal/analyzer/os/amazonlinux"
_ "github.com/aquasecurity/fanal/analyzer/os/debianbase"
_ "github.com/aquasecurity/fanal/analyzer/os/opensuse"
_ "github.com/aquasecurity/fanal/analyzer/os/photon"
_ "github.com/aquasecurity/fanal/analyzer/os/redhatbase"
_ "github.com/aquasecurity/fanal/analyzer/os/suse"
_ "github.com/aquasecurity/fanal/analyzer/pkg/apk"
_ "github.com/aquasecurity/fanal/analyzer/pkg/dpkg"
"github.com/aquasecurity/fanal/extractor"
@@ -27,7 +30,7 @@ func NewScanner(detector detector.Operation) Scanner {
return Scanner{detector: detector}
}
func (s Scanner) Scan(files extractor.FileMap) (string, string, []types.DetectedVulnerability, error) {
func (s Scanner) Scan(imageName string, created time.Time, files extractor.FileMap) (string, string, []types.DetectedVulnerability, error) {
os, err := analyzer.GetOS(files)
if err != nil {
return "", "", nil, xerrors.Errorf("failed to analyze OS: %w", err)
@@ -52,11 +55,12 @@ func (s Scanner) Scan(files extractor.FileMap) (string, string, []types.Detected
pkgs = mergePkgs(pkgs, pkgsFromCommands)
log.Logger.Debugf("the number of packages: %d", len(pkgs))
vulns, eosl, err := s.detector.Detect(os.Family, os.Name, pkgs)
vulns, eosl, err := s.detector.Detect(imageName, os.Family, os.Name, created, pkgs)
if err != nil {
return "", "", nil, xerrors.Errorf("failed to detect vulnerabilities: %w", err)
}
if eosl {
// TODO: test logger
log.Logger.Warnf("This OS version is no longer supported by the distribution: %s %s", os.Family, os.Name)
log.Logger.Warnf("The vulnerability detection may be insufficient because security updates are not provided")
}

View File

@@ -3,11 +3,12 @@ package ospkg
import (
"os"
"testing"
ospkg2 "github.com/aquasecurity/trivy/pkg/detector/ospkg"
"time"
"golang.org/x/xerrors"
ospkg2 "github.com/aquasecurity/trivy/pkg/detector/ospkg"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/assert"
@@ -26,9 +27,11 @@ func TestMain(m *testing.M) {
func TestScanner_Scan(t *testing.T) {
type detectInput struct {
osFamily string
osName string
pkgs []analyzer.Package
imageName string
osFamily string
osName string
buildTime time.Time
pkgs []analyzer.Package
}
type detectOutput struct {
vulns []types.DetectedVulnerability
@@ -41,7 +44,9 @@ func TestScanner_Scan(t *testing.T) {
}
type fields struct {
files extractor.FileMap
imageName string
created time.Time
files extractor.FileMap
}
type want struct {
osFamily string
@@ -58,7 +63,10 @@ func TestScanner_Scan(t *testing.T) {
{
name: "happy path",
fields: fields{
imageName: "alpine:3.10.2",
created: time.Date(2019, 5, 11, 0, 7, 3, 510395965, time.UTC),
files: extractor.FileMap{
"/config": []byte(`{"architecture":"amd64","config":{"Hostname":"","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd":["/bin/sh"],"ArgsEscaped":true,"Image":"sha256:09f2bbe58e774849d74dc1391c2e01731896c745c4aba1ecf69a283bdb4b537a","Volumes":null,"WorkingDir":"","Entrypoint":null,"OnBuild":null,"Labels":null},"container":"c10d36fa368a7ea673683682666758adf35efe98e10989505f4f566b5b18538f","container_config":{"Hostname":"c10d36fa368a","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd":["/bin/sh","-c","#(nop) ","CMD [\"/bin/sh\"]"],"ArgsEscaped":true,"Image":"sha256:09f2bbe58e774849d74dc1391c2e01731896c745c4aba1ecf69a283bdb4b537a","Volumes":null,"WorkingDir":"","Entrypoint":null,"OnBuild":null,"Labels":{}},"created":"2019-05-11T00:07:03.510395965Z","docker_version":"18.06.1-ce","history":[{"created":"2019-05-11T00:07:03.358250803Z","created_by":"/bin/sh -c #(nop) ADD file:a86aea1f3a7d68f6ae03397b99ea77f2e9ee901c5c59e59f76f93adbb4035913 in / "},{"created":"2019-05-11T00:07:03.510395965Z","created_by":"/bin/sh -c #(nop) CMD [\"/bin/sh\"]","empty_layer":true}],"os":"linux","rootfs":{"type":"layers","diff_ids":["sha256:f1b5933fe4b5f49bbe8258745cf396afe07e625bdab3168e364daf7c956b6b81"]}}`),
"etc/alpine-release": []byte("3.10.2"),
"lib/apk/db/installed": []byte(`C:Q11Ing8/u1VIdY9czSxaDO9wJg72I=
P:musl
@@ -88,8 +96,10 @@ F:usr/lib
},
detect: detect{
input: detectInput{
osFamily: "alpine",
osName: "3.10.2",
imageName: "alpine:3.10.2",
osFamily: "alpine",
osName: "3.10.2",
buildTime: time.Date(2019, 5, 11, 0, 7, 3, 510395965, time.UTC),
pkgs: []analyzer.Package{
{Name: "musl", Version: "1.1.22-r3"},
},
@@ -122,7 +132,10 @@ F:usr/lib
{
name: "Detect returns an error",
fields: fields{
imageName: "alpine:3.10",
created: time.Date(2019, 5, 11, 0, 7, 3, 510395965, time.UTC),
files: extractor.FileMap{
"/config": []byte(`{"architecture":"amd64","config":{"Hostname":"","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd":["/bin/sh"],"ArgsEscaped":true,"Image":"sha256:09f2bbe58e774849d74dc1391c2e01731896c745c4aba1ecf69a283bdb4b537a","Volumes":null,"WorkingDir":"","Entrypoint":null,"OnBuild":null,"Labels":null},"container":"c10d36fa368a7ea673683682666758adf35efe98e10989505f4f566b5b18538f","container_config":{"Hostname":"c10d36fa368a","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd":["/bin/sh","-c","#(nop) ","CMD [\"/bin/sh\"]"],"ArgsEscaped":true,"Image":"sha256:09f2bbe58e774849d74dc1391c2e01731896c745c4aba1ecf69a283bdb4b537a","Volumes":null,"WorkingDir":"","Entrypoint":null,"OnBuild":null,"Labels":{}},"created":"2019-05-11T00:07:03.510395965Z","docker_version":"18.06.1-ce","history":[{"created":"2019-05-11T00:07:03.358250803Z","created_by":"/bin/sh -c #(nop) ADD file:a86aea1f3a7d68f6ae03397b99ea77f2e9ee901c5c59e59f76f93adbb4035913 in / "},{"created":"2019-05-11T00:07:03.510395965Z","created_by":"/bin/sh -c #(nop) CMD [\"/bin/sh\"]","empty_layer":true}],"os":"linux","rootfs":{"type":"layers","diff_ids":["sha256:f1b5933fe4b5f49bbe8258745cf396afe07e625bdab3168e364daf7c956b6b81"]}}`),
"etc/alpine-release": []byte("3.10.2"),
"lib/apk/db/installed": []byte(`C:Q11Ing8/u1VIdY9czSxaDO9wJg72I=
P:musl
@@ -133,8 +146,10 @@ A:x86_64
},
detect: detect{
input: detectInput{
osFamily: "alpine",
osName: "3.10.2",
imageName: "alpine:3.10",
osFamily: "alpine",
osName: "3.10.2",
buildTime: time.Date(2019, 5, 11, 0, 7, 3, 510395965, time.UTC),
pkgs: []analyzer.Package{
{Name: "musl", Version: "1.1.22-r3"},
},
@@ -151,11 +166,11 @@ A:x86_64
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
mockDetector := new(ospkg2.MockDetector)
mockDetector.On("Detect", tt.detect.input.osFamily, tt.detect.input.osName,
tt.detect.input.pkgs).Return(tt.detect.output.vulns, tt.detect.output.eosl, tt.detect.output.err)
mockDetector.On("Detect", tt.detect.input.imageName, tt.detect.input.osFamily, tt.detect.input.osName,
tt.detect.input.buildTime, tt.detect.input.pkgs).Return(tt.detect.output.vulns, tt.detect.output.eosl, tt.detect.output.err)
s := NewScanner(mockDetector)
got, got1, got2, err := s.Scan(tt.fields.files)
got, got1, got2, err := s.Scan(tt.fields.imageName, tt.fields.created, tt.fields.files)
if tt.want.err != "" {
require.NotNil(t, err, tt.name)

View File

@@ -2,19 +2,24 @@ package scanner
import (
"context"
"encoding/json"
"flag"
"fmt"
"os"
"sort"
"time"
"github.com/google/wire"
"github.com/aquasecurity/trivy/pkg/report"
"golang.org/x/crypto/ssh/terminal"
"golang.org/x/xerrors"
"github.com/aquasecurity/fanal/analyzer"
"github.com/aquasecurity/fanal/cache"
"github.com/aquasecurity/fanal/extractor"
"github.com/aquasecurity/fanal/extractor/docker"
libDetector "github.com/aquasecurity/trivy/pkg/detector/library"
ospkgDetector "github.com/aquasecurity/trivy/pkg/detector/ospkg"
"github.com/aquasecurity/trivy/pkg/report"
rpcLibDetector "github.com/aquasecurity/trivy/pkg/rpc/client/library"
rpcOSDetector "github.com/aquasecurity/trivy/pkg/rpc/client/ospkg"
"github.com/aquasecurity/trivy/pkg/scanner/library"
@@ -23,8 +28,6 @@ import (
ospkgScanner "github.com/aquasecurity/trivy/pkg/scanner/ospkg"
"github.com/aquasecurity/trivy/pkg/types"
"github.com/aquasecurity/trivy/pkg/utils"
"golang.org/x/crypto/ssh/terminal"
"golang.org/x/xerrors"
)
var StandaloneSet = wire.NewSet(
@@ -44,12 +47,13 @@ var ClientSet = wire.NewSet(
)
type Scanner struct {
cacheClient cache.Cache
ospkgScanner ospkg.Scanner
libScanner library.Scanner
}
func NewScanner(ospkgScanner ospkg.Scanner, libScanner library.Scanner) Scanner {
return Scanner{ospkgScanner: ospkgScanner, libScanner: libScanner}
func NewScanner(cacheClient cache.Cache, ospkgScanner ospkg.Scanner, libScanner library.Scanner) Scanner {
return Scanner{cacheClient: cacheClient, ospkgScanner: ospkgScanner, libScanner: libScanner}
}
func (s Scanner) ScanImage(imageName, filePath string, scanOptions types.ScanOptions) (report.Results, error) {
@@ -58,15 +62,24 @@ func (s Scanner) ScanImage(imageName, filePath string, scanOptions types.ScanOpt
var target string
var files extractor.FileMap
var ac analyzer.Config
dockerOption, err := types.GetDockerOption()
if err != nil {
return nil, xerrors.Errorf("failed to get docker option: %w", err)
}
if imageName != "" {
dockerOption.Timeout = scanOptions.Timeout
}
ext, err := docker.NewDockerExtractor(dockerOption, s.cacheClient)
if err != nil {
return nil, err
}
ac = analyzer.Config{Extractor: ext}
if imageName != "" {
target = imageName
dockerOption, err := types.GetDockerOption()
if err != nil {
return nil, xerrors.Errorf("failed to get docker option: %w", err)
}
dockerOption.Timeout = scanOptions.Timeout
files, err = analyzer.Analyze(ctx, imageName, dockerOption)
files, err = ac.Analyze(ctx, imageName, dockerOption)
if err != nil {
return nil, xerrors.Errorf("failed to analyze image: %w", err)
}
@@ -77,7 +90,7 @@ func (s Scanner) ScanImage(imageName, filePath string, scanOptions types.ScanOpt
return nil, xerrors.Errorf("failed to open stream: %w", err)
}
files, err = analyzer.AnalyzeFile(ctx, rc)
files, err = ac.AnalyzeFile(ctx, rc)
if err != nil {
return nil, err
}
@@ -85,22 +98,27 @@ func (s Scanner) ScanImage(imageName, filePath string, scanOptions types.ScanOpt
return nil, xerrors.New("image name or image file must be specified")
}
created, err := getCreated(files["/config"])
if err != nil {
return nil, err
}
if utils.StringInSlice("os", scanOptions.VulnType) {
osFamily, osVersion, osVulns, err := s.ospkgScanner.Scan(files)
osFamily, osVersion, osVulns, err := s.ospkgScanner.Scan(target, created, files)
if err != nil && err != ospkgDetector.ErrUnsupportedOS {
return nil, xerrors.Errorf("failed to scan the image: %w", err)
}
if osFamily != "" {
imageDetail := fmt.Sprintf("%s (%s %s)", target, osFamily, osVersion)
results = append(results, report.Result{
FileName: imageDetail,
Target: imageDetail,
Vulnerabilities: osVulns,
})
}
}
if utils.StringInSlice("library", scanOptions.VulnType) {
libVulns, err := s.libScanner.Scan(files)
libVulns, err := s.libScanner.Scan(target, created, files)
if err != nil {
return nil, xerrors.Errorf("failed to scan libraries: %w", err)
}
@@ -108,12 +126,12 @@ func (s Scanner) ScanImage(imageName, filePath string, scanOptions types.ScanOpt
var libResults report.Results
for path, vulns := range libVulns {
libResults = append(libResults, report.Result{
FileName: path,
Target: path,
Vulnerabilities: vulns,
})
}
sort.Slice(libResults, func(i, j int) bool {
return libResults[i].FileName < libResults[j].FileName
return libResults[i].Target < libResults[j].Target
})
results = append(results, libResults...)
}
@@ -121,15 +139,16 @@ func (s Scanner) ScanImage(imageName, filePath string, scanOptions types.ScanOpt
return results, nil
}
func (s Scanner) ScanFile(f *os.File) (report.Results, error) {
vulns, err := s.libScanner.ScanFile(f)
if err != nil {
return nil, xerrors.Errorf("failed to scan libraries in file: %w", err)
type config struct {
Created time.Time
}
func getCreated(configBlob []byte) (time.Time, error) {
var config config
if err := json.Unmarshal(configBlob, &config); err != nil {
return time.Time{}, xerrors.Errorf("invalid config JSON: %w", err)
}
results := report.Results{
{FileName: f.Name(), Vulnerabilities: vulns},
}
return results, nil
return config.Created, nil
}
func openStream(path string) (*os.File, error) {

View File

@@ -1,64 +0,0 @@
package utils
import (
"time"
"github.com/briandowns/spinner"
pb "gopkg.in/cheggaaa/pb.v1"
)
var (
Quiet = false
)
type Spinner struct {
client *spinner.Spinner
}
func NewSpinner(suffix string) *Spinner {
if Quiet {
return &Spinner{}
}
s := spinner.New(spinner.CharSets[36], 100*time.Millisecond)
s.Suffix = suffix
return &Spinner{client: s}
}
func (s *Spinner) Start() {
if s.client == nil {
return
}
s.client.Start()
}
func (s *Spinner) Stop() {
if s.client == nil {
return
}
s.client.Stop()
}
// TODO: Expose an interface for progressbar
type ProgressBar struct {
client *pb.ProgressBar
}
func PbStartNew(total int) *ProgressBar {
if Quiet {
return &ProgressBar{}
}
bar := pb.StartNew(total)
return &ProgressBar{client: bar}
}
func (p *ProgressBar) Increment() {
if p.client == nil {
return
}
p.client.Increment()
}
func (p *ProgressBar) Finish() {
if p.client == nil {
return
}
p.client.Finish()
}

View File

@@ -33,7 +33,7 @@ type Operation interface {
}
type Client struct {
dbc db.Operations
dbc db.Operation
}
func NewClient(dbc db.Config) Client {

View File

@@ -26,41 +26,26 @@ func TestMain(m *testing.M) {
}
func TestClient_FillInfo(t *testing.T) {
type getSeverityOutput struct {
severity dbTypes.Severity
err error
}
type getSeverity struct {
input string
output getSeverityOutput
}
type getVulnerabilityOutput struct {
vulnerability dbTypes.Vulnerability
err error
}
type getVulnerability struct {
input string
output getVulnerabilityOutput
}
type args struct {
vulns []types.DetectedVulnerability
light bool
}
tests := []struct {
name string
getSeverity []getSeverity
getVulnerability []getVulnerability
getSeverity []db.GetSeverityExpectation
getVulnerability []db.GetVulnerabilityExpectation
args args
expected []types.DetectedVulnerability
}{
{
name: "happy path",
getVulnerability: []getVulnerability{
getVulnerability: []db.GetVulnerabilityExpectation{
{
input: "CVE-2019-0001",
output: getVulnerabilityOutput{
vulnerability: dbTypes.Vulnerability{
Args: db.GetVulnerabilityArgs{
VulnerabilityID: "CVE-2019-0001",
},
Returns: db.GetVulnerabilityReturns{
Vulnerability: dbTypes.Vulnerability{
Title: "dos",
Description: "dos vulnerability",
Severity: dbTypes.SeverityMedium.String(),
@@ -89,17 +74,21 @@ func TestClient_FillInfo(t *testing.T) {
},
{
name: "happy path with light option",
getSeverity: []getSeverity{
getSeverity: []db.GetSeverityExpectation{
{
input: "CVE-2019-0001",
output: getSeverityOutput{
severity: dbTypes.SeverityCritical,
Args: db.GetSeverityArgs{
VulnerabilityID: "CVE-2019-0001",
},
Returns: db.GetSeverityReturns{
Severity: dbTypes.SeverityCritical,
},
},
{
input: "CVE-2019-0002",
output: getSeverityOutput{
severity: dbTypes.SeverityHigh,
Args: db.GetSeverityArgs{
VulnerabilityID: "CVE-2019-0002",
},
Returns: db.GetSeverityReturns{
Severity: dbTypes.SeverityHigh,
},
},
},
@@ -127,11 +116,13 @@ func TestClient_FillInfo(t *testing.T) {
},
{
name: "GetVulnerability returns an error",
getVulnerability: []getVulnerability{
getVulnerability: []db.GetVulnerabilityExpectation{
{
input: "CVE-2019-0004",
output: getVulnerabilityOutput{
err: xerrors.New("failed"),
Args: db.GetVulnerabilityArgs{
VulnerabilityID: "CVE-2019-0004",
},
Returns: db.GetVulnerabilityReturns{
Err: xerrors.New("failed"),
},
},
},
@@ -147,11 +138,13 @@ func TestClient_FillInfo(t *testing.T) {
},
{
name: "GetSeverity returns an error",
getSeverity: []getSeverity{
getSeverity: []db.GetSeverityExpectation{
{
input: "CVE-2019-0003",
output: getSeverityOutput{
err: xerrors.New("failed"),
Args: db.GetSeverityArgs{
VulnerabilityID: "CVE-2019-0003",
},
Returns: db.GetSeverityReturns{
Err: xerrors.New("failed"),
},
},
},
@@ -174,18 +167,13 @@ func TestClient_FillInfo(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
mockDBConfig := new(db.MockDBConfig)
mockDBConfig := new(db.MockOperation)
mockDBConfig.ApplyGetSeverityExpectations(tt.getSeverity)
mockDBConfig.ApplyGetVulnerabilityExpectations(tt.getVulnerability)
c := Client{
dbc: mockDBConfig,
}
for _, gs := range tt.getSeverity {
mockDBConfig.On("GetSeverity", gs.input).Return(
gs.output.severity, gs.output.err)
}
for _, gv := range tt.getVulnerability {
mockDBConfig.On("GetVulnerability", gv.input).Return(
gv.output.vulnerability, gv.output.err)
}
c.FillInfo(tt.args.vulns, tt.args.light)
assert.Equal(t, tt.expected, tt.args.vulns, tt.name)

View File

@@ -6,6 +6,7 @@ package detector
import (
fmt "fmt"
proto "github.com/golang/protobuf/proto"
timestamp "github.com/golang/protobuf/ptypes/timestamp"
math "math"
)
@@ -55,12 +56,14 @@ func (Severity) EnumDescriptor() ([]byte, []int) {
}
type OSDetectRequest struct {
OsFamily string `protobuf:"bytes,1,opt,name=os_family,json=osFamily,proto3" json:"os_family,omitempty"`
OsName string `protobuf:"bytes,2,opt,name=os_name,json=osName,proto3" json:"os_name,omitempty"`
Packages []*Package `protobuf:"bytes,3,rep,name=packages,proto3" json:"packages,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
OsFamily string `protobuf:"bytes,1,opt,name=os_family,json=osFamily,proto3" json:"os_family,omitempty"`
OsName string `protobuf:"bytes,2,opt,name=os_name,json=osName,proto3" json:"os_name,omitempty"`
Packages []*Package `protobuf:"bytes,3,rep,name=packages,proto3" json:"packages,omitempty"`
ImageName string `protobuf:"bytes,4,opt,name=image_name,json=imageName,proto3" json:"image_name,omitempty"`
Created *timestamp.Timestamp `protobuf:"bytes,5,opt,name=created,proto3" json:"created,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *OSDetectRequest) Reset() { *m = OSDetectRequest{} }
@@ -109,6 +112,20 @@ func (m *OSDetectRequest) GetPackages() []*Package {
return nil
}
func (m *OSDetectRequest) GetImageName() string {
if m != nil {
return m.ImageName
}
return ""
}
func (m *OSDetectRequest) GetCreated() *timestamp.Timestamp {
if m != nil {
return m.Created
}
return nil
}
type DetectResponse struct {
Vulnerabilities []*Vulnerability `protobuf:"bytes,1,rep,name=vulnerabilities,proto3" json:"vulnerabilities,omitempty"`
Eosl bool `protobuf:"varint,2,opt,name=eosl,proto3" json:"eosl,omitempty"`
@@ -264,11 +281,13 @@ func (m *Package) GetSrcEpoch() int32 {
}
type LibDetectRequest struct {
FilePath string `protobuf:"bytes,1,opt,name=file_path,json=filePath,proto3" json:"file_path,omitempty"`
Libraries []*Library `protobuf:"bytes,2,rep,name=libraries,proto3" json:"libraries,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
FilePath string `protobuf:"bytes,1,opt,name=file_path,json=filePath,proto3" json:"file_path,omitempty"`
Libraries []*Library `protobuf:"bytes,2,rep,name=libraries,proto3" json:"libraries,omitempty"`
ImageName string `protobuf:"bytes,3,opt,name=image_name,json=imageName,proto3" json:"image_name,omitempty"`
Created *timestamp.Timestamp `protobuf:"bytes,4,opt,name=created,proto3" json:"created,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *LibDetectRequest) Reset() { *m = LibDetectRequest{} }
@@ -310,6 +329,20 @@ func (m *LibDetectRequest) GetLibraries() []*Library {
return nil
}
func (m *LibDetectRequest) GetImageName() string {
if m != nil {
return m.ImageName
}
return ""
}
func (m *LibDetectRequest) GetCreated() *timestamp.Timestamp {
if m != nil {
return m.Created
}
return nil
}
type Library struct {
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
Version string `protobuf:"bytes,2,opt,name=version,proto3" json:"version,omitempty"`
@@ -465,44 +498,49 @@ func init() {
func init() { proto.RegisterFile("rpc/detector/service.proto", fileDescriptor_93e16dbd737b8924) }
var fileDescriptor_93e16dbd737b8924 = []byte{
// 618 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x54, 0x4d, 0x4f, 0xdb, 0x40,
0x10, 0x6d, 0x3e, 0xed, 0x4c, 0xf8, 0x70, 0x57, 0x48, 0xb8, 0xa0, 0x42, 0x94, 0x5e, 0x68, 0x2b,
0x05, 0x29, 0xb4, 0xea, 0xb9, 0x05, 0x0a, 0x69, 0x43, 0x40, 0xa6, 0x80, 0xda, 0x4b, 0xb4, 0x71,
0x26, 0x64, 0x85, 0x93, 0x75, 0x77, 0x97, 0xa8, 0x96, 0xfa, 0xb7, 0xfa, 0xd3, 0x7a, 0xaf, 0x76,
0xd7, 0x36, 0x49, 0xca, 0x85, 0xdb, 0xcc, 0xbc, 0xe7, 0x99, 0xd9, 0xf7, 0xd6, 0x0b, 0x5b, 0x22,
0x0e, 0xf7, 0x87, 0xa8, 0x30, 0x54, 0x5c, 0xec, 0x4b, 0x14, 0x33, 0x16, 0x62, 0x2b, 0x16, 0x5c,
0x71, 0xb2, 0xa6, 0x04, 0x9b, 0x25, 0xad, 0x0c, 0x6d, 0xfe, 0x86, 0xf5, 0xf3, 0xcb, 0x23, 0x93,
0x05, 0xf8, 0xf3, 0x1e, 0xa5, 0x22, 0xdb, 0x50, 0xe3, 0xb2, 0x3f, 0xa2, 0x13, 0x16, 0x25, 0x7e,
0xa1, 0x51, 0xd8, 0xab, 0x05, 0x2e, 0x97, 0x9f, 0x4d, 0x4e, 0x36, 0xc1, 0xe1, 0xb2, 0x3f, 0xa5,
0x13, 0xf4, 0x8b, 0x06, 0xaa, 0x72, 0xd9, 0xa3, 0x13, 0x24, 0x07, 0xe0, 0xc6, 0x34, 0xbc, 0xa3,
0xb7, 0x28, 0xfd, 0x52, 0xa3, 0xb4, 0x57, 0x6f, 0x6f, 0xb6, 0x16, 0x67, 0xb5, 0x2e, 0x2c, 0x1e,
0xe4, 0xc4, 0xe6, 0x04, 0xd6, 0xb2, 0xd9, 0x32, 0xe6, 0x53, 0x89, 0xe4, 0x04, 0xd6, 0x67, 0xf7,
0xd1, 0x14, 0x05, 0x1d, 0xb0, 0x88, 0x29, 0x86, 0xd2, 0x2f, 0x98, 0x6e, 0x2f, 0x97, 0xbb, 0x5d,
0xcf, 0xd1, 0x92, 0x60, 0xf9, 0x2b, 0x42, 0xa0, 0x8c, 0x5c, 0x46, 0x66, 0x4b, 0x37, 0x30, 0x71,
0xf3, 0x6f, 0x01, 0x9c, 0x74, 0x09, 0x8d, 0x9b, 0x53, 0xd8, 0x03, 0x9a, 0x98, 0xf8, 0xe0, 0xcc,
0x50, 0x48, 0xc6, 0xa7, 0xe9, 0xe1, 0xb2, 0x54, 0x23, 0x02, 0x23, 0xa4, 0x12, 0xfd, 0x92, 0x45,
0xd2, 0x94, 0x6c, 0x40, 0x05, 0x63, 0x1e, 0x8e, 0xfd, 0x72, 0xa3, 0xb0, 0x57, 0x09, 0x6c, 0xa2,
0xbb, 0x53, 0x11, 0x8e, 0xfd, 0x8a, 0xed, 0xae, 0x63, 0xf2, 0x02, 0x5c, 0x29, 0x42, 0xab, 0x5d,
0xd5, 0x36, 0x91, 0x22, 0x34, 0xe2, 0xed, 0x42, 0x5d, 0x43, 0xd9, 0x70, 0xc7, 0xa0, 0x20, 0x45,
0x78, 0x9d, 0xce, 0x4f, 0x09, 0xd9, 0x0e, 0x6e, 0x4e, 0x08, 0xd2, 0x35, 0xb6, 0xa1, 0xa6, 0x09,
0x76, 0x95, 0x9a, 0x59, 0x45, 0x4f, 0x3b, 0xd6, 0x79, 0x73, 0x04, 0x5e, 0x97, 0x0d, 0xfe, 0x73,
0x79, 0xc4, 0x22, 0xec, 0xc7, 0x54, 0x8d, 0x33, 0x97, 0x75, 0xe1, 0x82, 0xaa, 0x31, 0x79, 0x0f,
0xb5, 0x88, 0x0d, 0x04, 0x15, 0x5a, 0xff, 0xe2, 0xe3, 0x6e, 0x76, 0x0d, 0x21, 0x09, 0x1e, 0x98,
0xcd, 0x0f, 0xe0, 0xa4, 0xd5, 0xa7, 0xc9, 0xdb, 0xfc, 0x53, 0x84, 0xd5, 0x05, 0x3f, 0xc9, 0x6b,
0xf0, 0xe6, 0x1d, 0x4d, 0xfa, 0x6c, 0x98, 0xf6, 0x5a, 0x70, 0x3a, 0xe9, 0x0c, 0xb5, 0xae, 0xf1,
0xdd, 0xed, 0xfc, 0x9d, 0x74, 0xe2, 0xbb, 0x5b, 0xa3, 0xeb, 0x5b, 0x78, 0xce, 0xa6, 0x52, 0xd1,
0x28, 0xc2, 0x61, 0xae, 0xae, 0x35, 0xd0, 0xcb, 0x81, 0x4c, 0xe3, 0x57, 0xb0, 0x3a, 0x62, 0xbf,
0xe6, 0x88, 0x65, 0x43, 0x5c, 0x31, 0xc5, 0x8c, 0xb4, 0x01, 0x15, 0xc5, 0x54, 0x84, 0xa9, 0xb3,
0x36, 0x21, 0x0d, 0xa8, 0x0f, 0x51, 0x86, 0x82, 0xc5, 0x4a, 0x7f, 0x68, 0xdd, 0x9d, 0x2f, 0x91,
0x77, 0xe0, 0x4a, 0x9c, 0xa1, 0x60, 0x2a, 0x31, 0xf6, 0xae, 0xb5, 0xfd, 0x65, 0x41, 0x2f, 0x53,
0x3c, 0xc8, 0x99, 0x64, 0x07, 0x40, 0xe0, 0x08, 0x05, 0x4e, 0x43, 0x94, 0xbe, 0xdb, 0x28, 0x69,
0xd7, 0x1f, 0x2a, 0x6f, 0x8e, 0xc0, 0xcd, 0xbe, 0x22, 0x75, 0x70, 0xae, 0x7a, 0x5f, 0x7b, 0xe7,
0x37, 0x3d, 0xef, 0x19, 0x71, 0xa0, 0xd4, 0x3d, 0xbf, 0xf1, 0x0a, 0x04, 0xa0, 0x7a, 0x76, 0x7c,
0xd4, 0xb9, 0x3a, 0xf3, 0x8a, 0xc4, 0x85, 0xf2, 0x69, 0xe7, 0xe4, 0xd4, 0x2b, 0x91, 0x15, 0x70,
0x0f, 0x83, 0xce, 0xb7, 0xce, 0xe1, 0xc7, 0xae, 0x57, 0x6e, 0xdf, 0x00, 0x64, 0x6f, 0x00, 0x17,
0xa4, 0x03, 0x55, 0x1b, 0x93, 0xdd, 0xe5, 0x0d, 0x97, 0x5e, 0x8a, 0xad, 0x9d, 0x65, 0xc2, 0xe2,
0xcf, 0xdc, 0xfe, 0x0e, 0xf5, 0xfc, 0xde, 0x71, 0x41, 0xbe, 0xe4, 0x9d, 0x1b, 0x8f, 0x5c, 0xa6,
0x27, 0xb5, 0xfe, 0x04, 0x3f, 0xdc, 0x0c, 0x1a, 0x54, 0xcd, 0xd3, 0x76, 0xf0, 0x2f, 0x00, 0x00,
0xff, 0xff, 0xde, 0x1c, 0x85, 0x42, 0xf8, 0x04, 0x00, 0x00,
// 693 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x54, 0x4d, 0x6f, 0xd3, 0x40,
0x10, 0xc5, 0xf9, 0xb2, 0x33, 0xe9, 0x87, 0x59, 0x55, 0xaa, 0x49, 0xd5, 0x36, 0x0a, 0x97, 0x02,
0x52, 0x22, 0xa5, 0x45, 0x9c, 0xa1, 0x2d, 0x6d, 0x20, 0x4d, 0x2b, 0xf7, 0x4b, 0x70, 0x89, 0x36,
0xce, 0x24, 0x59, 0xd5, 0xc9, 0x9a, 0xdd, 0x6d, 0x44, 0x7e, 0x18, 0x27, 0x7e, 0x05, 0x3f, 0x86,
0x3b, 0xf2, 0xae, 0x9d, 0x26, 0xa1, 0x42, 0xf4, 0xb6, 0x33, 0xef, 0xed, 0xec, 0xbc, 0x99, 0x67,
0x43, 0x59, 0x44, 0x41, 0xbd, 0x87, 0x0a, 0x03, 0xc5, 0x45, 0x5d, 0xa2, 0x98, 0xb0, 0x00, 0x6b,
0x91, 0xe0, 0x8a, 0x93, 0x35, 0x25, 0xd8, 0x64, 0x5a, 0x4b, 0xd1, 0xf2, 0xee, 0x80, 0xf3, 0x41,
0x88, 0x75, 0x8d, 0x76, 0xef, 0xfb, 0x75, 0xc5, 0x46, 0x28, 0x15, 0x1d, 0x45, 0xe6, 0x42, 0xf5,
0x97, 0x05, 0xeb, 0xe7, 0x97, 0x47, 0x9a, 0xef, 0xe3, 0xb7, 0x7b, 0x94, 0x8a, 0x6c, 0x41, 0x91,
0xcb, 0x4e, 0x9f, 0x8e, 0x58, 0x38, 0xf5, 0xac, 0x8a, 0xb5, 0x57, 0xf4, 0x1d, 0x2e, 0x3f, 0xea,
0x98, 0x6c, 0x82, 0xcd, 0x65, 0x67, 0x4c, 0x47, 0xe8, 0x65, 0x34, 0x54, 0xe0, 0xb2, 0x4d, 0x47,
0x48, 0xf6, 0xc1, 0x89, 0x68, 0x70, 0x47, 0x07, 0x28, 0xbd, 0x6c, 0x25, 0xbb, 0x57, 0x6a, 0x6c,
0xd6, 0x16, 0xbb, 0xa9, 0x5d, 0x18, 0xdc, 0x9f, 0x11, 0xc9, 0x36, 0x00, 0x1b, 0xd1, 0x01, 0x9a,
0x82, 0x39, 0x5d, 0xb0, 0xa8, 0x33, 0xba, 0xe6, 0x01, 0xd8, 0x81, 0x40, 0xaa, 0xb0, 0xe7, 0xe5,
0x2b, 0xd6, 0x5e, 0xa9, 0x51, 0xae, 0x19, 0x41, 0xb5, 0x54, 0x50, 0xed, 0x2a, 0x15, 0xe4, 0xa7,
0xd4, 0xea, 0x08, 0xd6, 0x52, 0x41, 0x32, 0xe2, 0x63, 0x89, 0xe4, 0x04, 0xd6, 0x27, 0xf7, 0xe1,
0x18, 0x05, 0xed, 0xb2, 0x90, 0x29, 0x86, 0xd2, 0xb3, 0x74, 0x8b, 0xdb, 0xcb, 0x2d, 0xde, 0xcc,
0xd1, 0xa6, 0xfe, 0xf2, 0x2d, 0x42, 0x20, 0x87, 0x5c, 0x86, 0x5a, 0xba, 0xe3, 0xeb, 0x73, 0xf5,
0xb7, 0x05, 0x76, 0xa2, 0x2c, 0xc6, 0xb5, 0x12, 0x33, 0x35, 0x7d, 0x26, 0x1e, 0xd8, 0x13, 0x14,
0x92, 0xf1, 0x71, 0x32, 0xb1, 0x34, 0x8c, 0x11, 0x81, 0x21, 0x52, 0x89, 0x5e, 0xd6, 0x20, 0x49,
0x48, 0x36, 0x20, 0x8f, 0x11, 0x0f, 0x86, 0x7a, 0x24, 0x79, 0xdf, 0x04, 0x71, 0x75, 0x2a, 0x82,
0xa1, 0x9e, 0x45, 0xd1, 0xd7, 0x67, 0xf2, 0x02, 0x1c, 0x29, 0x02, 0x33, 0xbf, 0x82, 0x29, 0x22,
0x45, 0xa0, 0xa7, 0xb7, 0x0b, 0xa5, 0x18, 0x4a, 0x1f, 0xb7, 0x35, 0x0a, 0x52, 0x04, 0x37, 0xc9,
0xfb, 0x09, 0x21, 0xed, 0xc1, 0x99, 0x11, 0xfc, 0xa4, 0x8d, 0x2d, 0x28, 0xc6, 0x04, 0xd3, 0x4a,
0x51, 0xb7, 0x12, 0xbf, 0x76, 0x1c, 0xc7, 0xd5, 0x9f, 0x16, 0xb8, 0x2d, 0xd6, 0xfd, 0xcb, 0x3b,
0x7d, 0x16, 0x62, 0x27, 0xa2, 0x6a, 0x98, 0x7a, 0x27, 0x4e, 0x5c, 0x50, 0x35, 0x24, 0x6f, 0xa1,
0x18, 0xb2, 0xae, 0xa0, 0x22, 0x5e, 0x40, 0xe6, 0x71, 0x8f, 0xb4, 0x34, 0x61, 0xea, 0x3f, 0x30,
0x97, 0x4c, 0x92, 0xfd, 0x87, 0x49, 0x72, 0xff, 0x6f, 0x92, 0x77, 0x60, 0x27, 0x4f, 0x3d, 0x6d,
0x69, 0xd5, 0x1f, 0x19, 0x58, 0x5d, 0x70, 0x09, 0x79, 0x05, 0xee, 0xbc, 0x4f, 0xa6, 0x1d, 0xd6,
0x4b, 0x6a, 0x2d, 0xf8, 0x67, 0xda, 0xec, 0xc5, 0xdb, 0x8a, 0xee, 0x06, 0xf3, 0x9f, 0x8f, 0x1d,
0xdd, 0x0d, 0xb4, 0x8c, 0x37, 0xf0, 0x9c, 0x8d, 0xa5, 0xa2, 0x61, 0x88, 0xbd, 0xd9, 0xce, 0x8c,
0x58, 0x77, 0x06, 0xa4, 0x9b, 0x7b, 0x09, 0xab, 0x7d, 0xf6, 0x7d, 0x8e, 0x68, 0x3e, 0x9d, 0x15,
0x9d, 0x4c, 0x49, 0x1b, 0x90, 0x57, 0x4c, 0x85, 0x98, 0xf8, 0xc5, 0x04, 0xa4, 0x02, 0xa5, 0x1e,
0xca, 0x40, 0xb0, 0x48, 0xc5, 0x17, 0x8d, 0x67, 0xe6, 0x53, 0xe4, 0x00, 0x1c, 0x89, 0x13, 0x14,
0x4c, 0x4d, 0xb5, 0x69, 0xd6, 0x1a, 0xde, 0xf2, 0x96, 0x2e, 0x13, 0xdc, 0x9f, 0x31, 0xc9, 0x0e,
0x80, 0xc0, 0x3e, 0x0a, 0x1c, 0x07, 0x28, 0x3d, 0xa7, 0x92, 0x8d, 0xbd, 0xf4, 0x90, 0x79, 0x7d,
0x04, 0x4e, 0x7a, 0x8b, 0x94, 0xc0, 0xbe, 0x6e, 0x7f, 0x6e, 0x9f, 0xdf, 0xb6, 0xdd, 0x67, 0xc4,
0x86, 0x6c, 0xeb, 0xfc, 0xd6, 0xb5, 0x08, 0x40, 0xe1, 0xec, 0xf8, 0xa8, 0x79, 0x7d, 0xe6, 0x66,
0x88, 0x03, 0xb9, 0xd3, 0xe6, 0xc9, 0xa9, 0x9b, 0x25, 0x2b, 0xe0, 0x1c, 0xfa, 0xcd, 0xab, 0xe6,
0xe1, 0xfb, 0x96, 0x9b, 0x6b, 0xdc, 0x02, 0xa4, 0xbf, 0x2b, 0x2e, 0x48, 0x13, 0x0a, 0xe6, 0x4c,
0x76, 0x97, 0x3b, 0x5c, 0xfa, 0xa9, 0x95, 0x77, 0x96, 0x09, 0x8b, 0xbf, 0x88, 0xc6, 0x17, 0x28,
0xcd, 0xcc, 0xcc, 0x05, 0xf9, 0x34, 0xab, 0x5c, 0x79, 0xc4, 0xa1, 0x4f, 0x2a, 0xfd, 0x01, 0xbe,
0x3a, 0x29, 0xd4, 0x2d, 0x68, 0x4f, 0xee, 0xff, 0x09, 0x00, 0x00, 0xff, 0xff, 0x65, 0x1f, 0xdb,
0x8d, 0xc5, 0x05, 0x00, 0x00,
}

View File

@@ -1,5 +1,7 @@
syntax = "proto3";
import "google/protobuf/timestamp.proto";
package trivy.detector;
option go_package = "detector";
@@ -8,9 +10,11 @@ service OSDetector {
}
message OSDetectRequest {
string os_family = 1;
string os_name = 2;
repeated Package packages = 3;
string os_family = 1;
string os_name = 2;
repeated Package packages = 3;
string image_name = 4;
google.protobuf.Timestamp created = 5;
}
message DetectResponse {
@@ -39,8 +43,10 @@ service LibDetector {
}
message LibDetectRequest {
string file_path = 1;
repeated Library libraries = 2;
string file_path = 1;
repeated Library libraries = 2;
string image_name = 3;
google.protobuf.Timestamp created = 4;
}
message Library {

View File

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