Compare commits

..

17 Commits

Author SHA1 Message Date
Teppei Fukuda
1391b3bf47 fix(oracle): handle ksplice advisories (#745) 2020-11-18 20:14:01 +02:00
Teppei Fukuda
b6d5b82c48 fix: version comparison (#740)
* feat: add comparer

* refactor: rename lang with ecosystem

* feat(bundler): add comparer

* feat(node): add comparer

* feat(bundler): integrate comparer

* feat(cargo): integrate comparer

* feat(composer): add comparer

* feat(ghsa): integrate comparer

* feat(node): integrate comparer

* feat(python): integrate comparer

* test(bundler): add tests

* test(cargo): add tests

* test(composer): add tests

* test(ghsa): add tests

* test(node): add tests

* test(python): add tests

* refactor(utils): remove unnecessary functions

* test(utils): add tests

* test: rename bucket prefixes

* fix(detect): use string

* chore: update dependencies

* docs: add comments

* fix(cargo): handle unpatched vulnerability

* test(db): update trivy-db for integration tests

* test(integration): update a golden file

* test(cargo): Add a case for missing patched version

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

* refactor(advisory): update comments

* refactor(node/advisory): change the receiver

* chore(mod): update dependencies

* refactor(comparer): unexport MatchVersion

* refactor: fix maligned structs

* test(node): add empty value

* refactor

* refactor: sort imports

* chore(mod): update trivy-db

Co-authored-by: Simarpreet Singh <simar@linux.com>
2020-11-17 11:38:58 +02:00
Gianni Carafa
9dfb0fe3a9 updated Readme.md (#737)
removed unused env var TRIVY_AUTH_URL
2020-11-12 21:16:42 -08:00
Dirk Mueller
455546975c Add suse sles 15.2 to the EOL list as well (#734)
without that you get this arning:
  WARN	This OS version is not on the EOL list: suse linux enterprise server 15.2

which is actually misleading because 15.2 is the most current release,
we just don't know when it ends. we can however assume that it runs
for at least another year.

Signed-off-by: Dirk Mueller <dirk@dmllr.de>
Signed-off-by: Dirk Mueller <dmueller@suse.com>
2020-10-30 16:42:48 -07:00
Sinith
c189aa6a0a Update README.md (#731) 2020-10-29 12:24:21 -07:00
Dax McDonald
8442528fa7 Warn when a user attempts to use trivy without a detectable lockfile (#729)
* Warn when a user attempts to use trivy without a detectable lockfile

* Update pkg/scanner/local/scan.go

Co-authored-by: Teppei Fukuda <knqyf263@gmail.com>

Co-authored-by: Teppei Fukuda <knqyf263@gmail.com>
2020-10-29 12:45:59 +02:00
Dax McDonald
d09787e150 Add back support for FreeBSD & OpenBSD (#728)
Reverts 7fc94ad95c
2020-10-29 07:21:49 +02:00
Carlos Eduardo
0285a89c7c Add support for ppc64le architecture (#724) 2020-10-26 17:08:14 -07:00
Evgeniy Kosov
7d7784fecb Skip packages from unsupported repository (remi) (#695)
* Skip packages from unsupported repository (remi)

* Use HasSuffix instead of regexp match
2020-10-26 13:14:46 +02:00
Huang Huang
ca6f196001 Skip downloading DB if a remote DB is not updated (#717)
* Skip downloading DB if a remote DB is not updated

* Apply suggestions from code review

Co-authored-by: Teppei Fukuda <knqyf263@gmail.com>

* update github.com/aquasecurity/trivy-db version

* fix lint

* Use UTC datetime

* display DownloadedAt info in debug log

* refactor(db): merge isLatestDB into isNewDB

Co-authored-by: Teppei Fukuda <knqyf263@gmail.com>
2020-10-26 09:07:30 +02:00
Huang Huang
e621cf2bc1 Sunsetting VendorVectors (#718) 2020-10-25 13:45:56 +02:00
Teppei Fukuda
906ab5483e Add GitHub Container Registry to README (#712) 2020-10-25 13:17:16 +02:00
Pascal Andy
1549c25709 update BUG_REPORT.md using H2 instead of bold formatting (#714) 2020-10-22 14:15:20 -07:00
Teppei Fukuda
fe1d07e58c fix(ci/deb): do not remove old packages for EOL versions (#706) 2020-10-22 06:52:42 +03:00
rahul2393
793a1aa3c8 Add linter check support (#679)
* add linter supports

* add only minor version

* use latest version

* Fix println with format issue

* Fix test

* Fix tests

* For slice with unknown length, preallocating the array

* fix code-coverage

* Removed linter rules

* Reverting linter fixes, adding TODO for later

* Ignore linter error for import

* Remove another err var.

* Ignore shadow error

* Fixes

* Fix issue

* Add back goimports local-prefixes

* Update local prefixes

* Removed extra spaces and merge the imports

* more refactoring

* Update photon.go

Co-authored-by: Teppei Fukuda <knqyf263@gmail.com>
2020-10-20 15:20:04 +03:00
Jeff Rescignano
4a94477532 Optimize images (#696) 2020-10-20 08:13:33 +03:00
Teppei Fukuda
9bc2b1949c Update triage.md (#701) 2020-10-20 08:12:47 +03:00
113 changed files with 2566 additions and 818 deletions

View File

@@ -4,28 +4,28 @@ labels: kind/bug
about: If something isn't working as expected.
---
**Description**
## Description
<!--
Briefly describe the problem you are having in a few paragraphs.
-->
**What did you expect to happen?**
## What did you expect to happen?
**What happened instead?**
## What happened instead?
**Output of run with `-debug`:**
## Output of run with `-debug`:
```
(paste your output here)
```
**Output of `trivy -v`:**
## Output of `trivy -v`:
```
(paste your output here)
```
**Additional details (base image name, container registry info...):**
## Additional details (base image name, container registry info...):

View File

@@ -1,6 +1,17 @@
name: Test
on: pull_request
jobs:
golangci:
name: lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: golangci-lint
uses: golangci/golangci-lint-action@v2
with:
version: v1.31
args: --deadline=30m
integration:
name: Integration Test
runs-on: ubuntu-latest
@@ -34,3 +45,4 @@ jobs:
with:
version: latest
args: release --snapshot --rm-dist --skip-publish

71
.golangci.yaml Normal file
View File

@@ -0,0 +1,71 @@
linters-settings:
errcheck:
check-type-assertions: true
check-blank: true
govet:
check-shadowing: false
gofmt:
simplify: false
golint:
min-confidence: 0
gocyclo:
min-complexity: 10
maligned:
suggest-new: true
dupl:
threshold: 100
goconst:
min-len: 3
min-occurrences: 3
misspell:
locale: US
goimports:
local-prefixes: github.com/aquasecurity
linters:
disable-all: true
enable:
- structcheck
- ineffassign
- typecheck
- govet
- errcheck
- varcheck
- deadcode
- golint
- gosec
- unconvert
- goconst
- gocyclo
- gofmt
- goimports
- maligned
- misspell
run:
skip-files:
- ".*._mock.go$"
- ".*._test.go$"
- "integration/*"
issues:
exclude-rules:
- linters:
- gosec
text: "G304: Potential file inclusion"
- linters:
- gosec
text: "Deferring unsafe method"
- linters:
- errcheck
text: "Close` is not checked"
- linters:
- errcheck
text: "os.*` is not checked"
- linters:
- golint
text: "a blank import should be only in a main or test package"
exclude:
- "should have a package comment, unless it's in another file for this package"
exclude-use-default: false
max-same-issues: 0

View File

@@ -106,7 +106,7 @@ See [here](#continuous-integration-ci) for details.
- See [Quick Start](#quick-start) and [Examples](#examples)
- Fast
- The first scan will finish within 10 seconds (depending on your network). Consequent scans will finish in single seconds.
- Unlike other scanners that take long to fetch vulnerability information (~10 minutes) on the first run, and encourage you to maintain the a durable vulnerability database, Trivy is stateless and requires no maintenance or preparation.
- Unlike other scanners that take long to fetch vulnerability information (~10 minutes) on the first run, and encourage you to maintain a durable vulnerability database, Trivy is stateless and requires no maintenance or preparation.
- Easy installation
- `apt-get install`, `yum install` and `brew install` is possible (See [Installation](#installation))
- **No pre-requisites** such as installation of DB, libraries, etc. (The exception is that you need `rpm` installed to scan images based on RHEL/CentOS. This is automatically included if you use our installers or the Trivy container image. See [Vulnerability Detection](#vulnerability-detection) for background information.)
@@ -258,6 +258,7 @@ Total: 1 (UNKNOWN: 0, LOW: 0, MEDIUM: 1, HIGH: 0, CRITICAL: 0)
</details>
### Docker
#### Docker Hub
Replace [YOUR_CACHE_DIR] with the cache directory on your machine.
@@ -301,6 +302,14 @@ Total: 1 (UNKNOWN: 0, LOW: 0, MEDIUM: 1, HIGH: 0, CRITICAL: 0)
</details>
#### GitHub Container Registry
The same image is hosted on GitHub Container Registry as well.
https://github.com/orgs/aquasecurity/packages/container/package/trivy
```
$ docker pull ghcr.io/aquasecurity/trivy:latest
```
## Filesystem
Scan a filesystem (such as a host machine, a virtual machine image, or an unpacked container image filesystem).
@@ -1593,11 +1602,10 @@ But, I can't recommend using ENV vars in your local machine to you.
### Docker Hub
Docker Hub needs `TRIVY_AUTH_URL`, `TRIVY_USERNAME` and `TRIVY_PASSWORD`.
Docker Hub needs `TRIVY_USERNAME` and `TRIVY_PASSWORD`.
You don't need to set ENV vars when download from public repository.
```bash
export TRIVY_AUTH_URL=https://registry.hub.docker.com
export TRIVY_USERNAME={DOCKERHUB_USERNAME}
export TRIVY_PASSWORD={DOCKERHUB_PASSWORD}
```

View File

@@ -5,7 +5,7 @@ UBUNTU_RELEASES=$(ubuntu-distro-info --supported)
cd trivy-repo/deb
for release in $(reprepro ls trivy | awk -F "|" '{print $3}' | sed 's/ //g'); do
for release in ${DEBIAN_RELEASES[@]} ${UBUNTU_RELEASES[@]}; do
echo "Removing deb package of $release"
reprepro -A i386 remove $release trivy
reprepro -A amd64 remove $release trivy

View File

@@ -72,6 +72,7 @@ get_binaries() {
freebsd/armv7) BINARIES="trivy" ;;
linux/386) BINARIES="trivy" ;;
linux/amd64) BINARIES="trivy" ;;
linux/ppc64le) BINARIES="trivy" ;;
linux/arm64) BINARIES="trivy" ;;
linux/armv7) BINARIES="trivy" ;;
openbsd/386) BINARIES="trivy" ;;
@@ -110,6 +111,7 @@ adjust_os() {
amd64) OS=64bit ;;
arm) OS=ARM ;;
arm64) OS=ARM64 ;;
ppc64le) OS=PPC64LE ;;
darwin) OS=macOS ;;
dragonfly) OS=DragonFlyBSD ;;
freebsd) OS=FreeBSD ;;
@@ -126,6 +128,7 @@ adjust_arch() {
amd64) ARCH=64bit ;;
arm) ARCH=ARM ;;
arm64) ARCH=ARM64 ;;
ppc64le) OS=PPC64LE ;;
darwin) ARCH=macOS ;;
dragonfly) ARCH=DragonFlyBSD ;;
freebsd) ARCH=FreeBSD ;;
@@ -209,6 +212,7 @@ uname_arch() {
x86) arch="386" ;;
i686) arch="386" ;;
i386) arch="386" ;;
ppc64le) arch="ppc64le" ;;
aarch64) arch="arm64" ;;
armv5*) arch="armv5" ;;
armv6*) arch="armv6" ;;

View File

@@ -185,7 +185,7 @@ We use two labels [help wanted](https://github.com/aquasecurity/trivy/issues?q=i
and [good first issue](https://github.com/aquasecurity/trivy/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22)
to identify issues that have been specially groomed for new contributors.
We have specific [guidelines](/docs/help-wanted.md)
We have specific [guidelines](/docs/contrib/help-wanted.md)
for how to use these labels. If you see an issue that satisfies these
guidelines, you can add the `help wanted` label and the `good first issue` label.
Please note that adding the `good first issue` label must also

16
go.mod
View File

@@ -3,17 +3,19 @@ module github.com/aquasecurity/trivy
go 1.15
require (
github.com/Masterminds/semver/v3 v3.1.0
github.com/aquasecurity/bolt-fixtures v0.0.0-20200825112230-c0f517aea2ed
github.com/aquasecurity/bolt-fixtures v0.0.0-20200903104109-d34e7f983986
github.com/aquasecurity/fanal v0.0.0-20200820074632-6de62ef86882
github.com/aquasecurity/go-dep-parser v0.0.0-20190819075924-ea223f0ef24b
github.com/aquasecurity/trivy-db v0.0.0-20200826140828-6da6467703aa
github.com/aquasecurity/go-gem-version v0.0.0-20201115065557-8eed6fe000ce
github.com/aquasecurity/go-npm-version v0.0.0-20201110091526-0b796d180798
github.com/aquasecurity/go-version v0.0.0-20201115065329-578079e4ab05
github.com/aquasecurity/trivy-db v0.0.0-20201117092632-b09c30858fc2
github.com/caarlos0/env/v6 v6.0.0
github.com/cenkalti/backoff v2.2.1+incompatible
github.com/cheggaaa/pb/v3 v3.0.3
github.com/docker/docker v1.4.2-0.20190924003213-a8608b5b67c7
github.com/docker/go-connections v0.4.0
github.com/golang/protobuf v1.3.3
github.com/golang/protobuf v1.4.2
github.com/google/go-containerregistry v0.0.0-20200331213917-3d03ed9b1ca2
github.com/google/go-github/v28 v28.1.1
github.com/google/wire v0.3.0
@@ -27,11 +29,11 @@ require (
github.com/stretchr/testify v1.6.1
github.com/testcontainers/testcontainers-go v0.3.1
github.com/twitchtv/twirp v5.10.1+incompatible
github.com/urfave/cli/v2 v2.2.0
github.com/urfave/cli/v2 v2.3.0
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/oauth2 v0.0.0-20190604053449-0f29369cfe45
golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1
k8s.io/utils v0.0.0-20191114184206-e782cd3c129f
k8s.io/utils v0.0.0-20201005171033-6301aaf42dc7
)

354
go.sum
View File

@@ -2,16 +2,51 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMT
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.38.0 h1:ROfEUZz+Gh5pa62DJWXSaonyu3StP6EA6lPEXPI6mCo=
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
cloud.google.com/go v0.65.0 h1:Dg9iHVQfrhq82rUNu9ZxUDrJLaxFUe/HlCVaLyRruq8=
cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
github.com/Azure/azure-sdk-for-go v35.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
github.com/Azure/azure-sdk-for-go v38.0.0+incompatible h1:3D2O4g8AwDwyWkM1HpMFVux/ccQJmGJHXsE004Wsu1Q=
github.com/Azure/azure-sdk-for-go v38.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8=
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI=
github.com/Azure/go-autorest/autorest v0.9.3 h1:OZEIaBbMdUE/Js+BQKlpO81XlISgipr6yDJ+PSwsgi4=
github.com/Azure/go-autorest/autorest v0.9.3/go.mod h1:GsRuLYvwzLjjjRoWEIyMUaYq8GNUx2nRB378IPt/1p0=
github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0=
github.com/Azure/go-autorest/autorest/adal v0.8.0/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc=
github.com/Azure/go-autorest/autorest/adal v0.8.1 h1:pZdL8o72rK+avFWl+p9nE8RWi1JInZrWJYlnpfXJwHk=
github.com/Azure/go-autorest/autorest/adal v0.8.1/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q=
github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA=
github.com/Azure/go-autorest/autorest/date v0.2.0 h1:yW+Zlqf26583pE43KhfnhFcdmSWlm5Ew6bxipnr/tbM=
github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g=
github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0=
github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0=
@@ -19,7 +54,9 @@ github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN
github.com/Azure/go-autorest/autorest/to v0.2.0/go.mod h1:GunWKJp1AEqgMaGLV+iocmRAJWqST1wQYhyyjXJ3SJc=
github.com/Azure/go-autorest/autorest/to v0.3.0/go.mod h1:MgwOyqaIuKdG4TL/2ywSsIWKAfJfgHDo8ObuUk3t5sA=
github.com/Azure/go-autorest/autorest/validation v0.1.0/go.mod h1:Ha3z/SqBeaalWQvokg3NZAlQTalVMtOIAs1aGK7G6u8=
github.com/Azure/go-autorest/logger v0.1.0 h1:ruG4BSDXONFRrZZJ2GUXDiUyVpayPmb1GnWeHDdaNKY=
github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc=
github.com/Azure/go-autorest/tracing v0.5.0 h1:TRn4WjSnkcSy5AEG3pnbtFSwNtwzjr4VYyQflFE619k=
github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk=
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
@@ -27,8 +64,6 @@ github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym
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/GoogleCloudPlatform/k8s-cloud-provider v0.0.0-20190822182118-27a4ced34534/go.mod h1:iroGtC8B3tQiqtds1l+mgk/BBOrxbqjH+eUfFQYRc14=
github.com/Masterminds/semver/v3 v3.1.0 h1:Y2lUDsFKVRSYGojLJ1yLxSXdMmMYTYls0rCvoqmMUQk=
github.com/Masterminds/semver/v3 v3.1.0/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA=
github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5 h1:ygIc8M6trr62pF5DucadTWGdEB4mEyvzi0e2nbcmcyA=
@@ -50,16 +85,24 @@ github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuy
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA=
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
github.com/aquasecurity/bolt-fixtures v0.0.0-20200825112230-c0f517aea2ed h1:o6vSjobtDn634//l4yBCGCC2RWoRc4K5AUH8W8DZZds=
github.com/aquasecurity/bolt-fixtures v0.0.0-20200825112230-c0f517aea2ed/go.mod h1:eViGpgc5g/JGRHWUfVaNLFJQwXQOVWDDQ40c7uViyZU=
github.com/aquasecurity/bolt-fixtures v0.0.0-20200903104109-d34e7f983986 h1:2a30xLN2sUZcMXl50hg+PJCIDdJgIvIbVcKqLJ/ZrtM=
github.com/aquasecurity/bolt-fixtures v0.0.0-20200903104109-d34e7f983986/go.mod h1:NT+jyeCzXk6vXR5MTkdn4z64TgGfE5HMLC8qfj5unl8=
github.com/aquasecurity/fanal v0.0.0-20200820074632-6de62ef86882 h1:65VcAKqhkKwMpLr9Wz+wNnsk+U+lv+v/qfOK04uXT3E=
github.com/aquasecurity/fanal v0.0.0-20200820074632-6de62ef86882/go.mod h1:VP1+n6hMi6krpA0umEl0CkJp4hbg0R21kXWg0mjrekc=
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/go-gem-version v0.0.0-20201115065557-8eed6fe000ce h1:QgBRgJvtEOBtUXilDb1MLi1p1MWoyFDXAu5DEUl5nwM=
github.com/aquasecurity/go-gem-version v0.0.0-20201115065557-8eed6fe000ce/go.mod h1:HXgVzOPvXhVGLJs4ZKO817idqr/xhwsTcj17CLYY74s=
github.com/aquasecurity/go-npm-version v0.0.0-20201110091526-0b796d180798 h1:eveqE9ivrt30CJ7dOajOfBavhZ4zPqHcZe/4tKp0alc=
github.com/aquasecurity/go-npm-version v0.0.0-20201110091526-0b796d180798/go.mod h1:hxbJZtKlO4P8sZ9nztizR6XLoE33O+BkPmuYQ4ACyz0=
github.com/aquasecurity/go-version v0.0.0-20201107203531-5e48ac5d022a h1:SMEtDBnLyP/EVOeJhj4yeR8GYPFpBsFBk3lSrpjZ8yI=
github.com/aquasecurity/go-version v0.0.0-20201107203531-5e48ac5d022a/go.mod h1:9Beu8XsUNNfzml7WBf3QmyPToP1wm1Gj/Vc5UJKqTzU=
github.com/aquasecurity/go-version v0.0.0-20201115065329-578079e4ab05 h1:q0ZpFBjwzDk1ofey7gJ2kfA6ZNi2PeBWxNzmRPrfetA=
github.com/aquasecurity/go-version v0.0.0-20201115065329-578079e4ab05/go.mod h1:9Beu8XsUNNfzml7WBf3QmyPToP1wm1Gj/Vc5UJKqTzU=
github.com/aquasecurity/testdocker v0.0.0-20200426142840-5f05bce6f12a h1:hsw7PpiymXP64evn/K7gsj3hWzMqLrdoeE6JkqDocVg=
github.com/aquasecurity/testdocker v0.0.0-20200426142840-5f05bce6f12a/go.mod h1:psfu0MVaiTDLpNxCoNsTeILSKY2EICBwv345f3M+Ffs=
github.com/aquasecurity/trivy-db v0.0.0-20200826140828-6da6467703aa h1:v+ghkIw3D3qUP++M3e9XGkkoq59iZdCOT4uxj4l2pXs=
github.com/aquasecurity/trivy-db v0.0.0-20200826140828-6da6467703aa/go.mod h1:/uvzkPkLMA6ZM1M2uIODx5J7b1wYb/goJ34Nidcukaw=
github.com/aquasecurity/trivy-db v0.0.0-20201117092632-b09c30858fc2 h1:AXA9aW464copH1GTKv35yCwztJsqDVZWKfCtBuMpI9U=
github.com/aquasecurity/trivy-db v0.0.0-20201117092632-b09c30858fc2/go.mod h1:+3+NEz0U0NCgO87Cyk0dy3SwH7CI6J4HUeCqqPj1fvQ=
github.com/aquasecurity/vuln-list-update v0.0.0-20191016075347-3d158c2bf9a2 h1:xbdUfr2KE4THsFx9CFWtWpU91lF+YhgP46moV94nYTA=
github.com/aquasecurity/vuln-list-update v0.0.0-20191016075347-3d158c2bf9a2/go.mod h1:6NhOP0CjZJL27bZZcaHECtzWdwDDm2g6yCY0QgXEGQQ=
github.com/araddon/dateparse v0.0.0-20190426192744-0d74ffceef83/go.mod h1:SLqhdZcd+dF3TEVL2RMoob5bBP5R1P1qkox+HtCBgGI=
@@ -73,8 +116,8 @@ github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
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/briandowns/spinner v1.11.1 h1:OixPqDEcX3juo5AjQZAnFPbeUA0jvkp2qzB5gOZJ/L0=
github.com/briandowns/spinner v1.11.1/go.mod h1:QOuQk7x+EaDASo80FEXwlwiA+j/PPIcX3FScO+3/ZPQ=
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=
@@ -82,6 +125,9 @@ github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QH
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
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/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
@@ -101,8 +147,9 @@ github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfc
github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/cpuguy83/go-md2man v1.0.10 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF22jk=
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM=
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -134,19 +181,22 @@ github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZ
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
github.com/elazarl/goproxy v0.0.0-20190421051319-9d40249d3c2f h1:8GDPb0tCY8LQ+OJ3dbHb5sA6YZWXFORQYZx5sdsTlMs=
github.com/elazarl/goproxy v0.0.0-20190421051319-9d40249d3c2f/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
github.com/elazarl/goproxy/ext v0.0.0-20190421051319-9d40249d3c2f h1:AUj1VoZUfhPhOPHULCQQDnGhRelpFWHMLhQVWDsS0v4=
github.com/elazarl/goproxy v0.0.0-20200809112317-0581fc3aee2d h1:rtM8HsT3NG37YPjz8sYSbUSdElP9lUsQENYzJDZDUBE=
github.com/elazarl/goproxy v0.0.0-20200809112317-0581fc3aee2d/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM=
github.com/elazarl/goproxy/ext v0.0.0-20190421051319-9d40249d3c2f/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8=
github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8=
github.com/elazarl/goproxy/ext v0.0.0-20200809112317-0581fc3aee2d h1:st1tmvy+4duoRj+RaeeJoECWCWM015fBtf/4aR+hhqk=
github.com/elazarl/goproxy/ext v0.0.0-20200809112317-0581fc3aee2d/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8=
github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg=
github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s=
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
@@ -170,6 +220,9 @@ github.com/go-git/go-git-fixtures/v4 v4.0.1 h1:q+IFMfLx200Q3scvt2hN79JsEzy4AmBTp
github.com/go-git/go-git-fixtures/v4 v4.0.1/go.mod h1:m+ICp2rF3jDhFgEZ/8yziagdT1C+ZpZcrJjappBCDSw=
github.com/go-git/go-git/v5 v5.0.0 h1:k5RWPm4iJwYtfWoxIJy4wJX9ON7ihPeZZYC1fLYDnpg=
github.com/go-git/go-git/v5 v5.0.0/go.mod h1:oYD8y9kWsGINPFJoLdaScGCN6dlKg23blmClfZwtUVA=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
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-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
@@ -197,8 +250,9 @@ github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LB
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
github.com/goccy/go-yaml v1.8.0 h1:WCe9sBiI0oZb6EC6f3kq3dv0+aEiNdstT7b4xxq4MJQ=
github.com/goccy/go-yaml v1.8.0/go.mod h1:wS4gNoLalDSJxo/SpngzPQ2BN4uuZVLCmbM4S3vd4+Y=
github.com/goccy/go-yaml v1.8.1/go.mod h1:wS4gNoLalDSJxo/SpngzPQ2BN4uuZVLCmbM4S3vd4+Y=
github.com/goccy/go-yaml v1.8.2 h1:gDYrSN12XK/wQTFjxWIgcIqjNCV/Zb5V09M7cq+dbCs=
github.com/goccy/go-yaml v1.8.2/go.mod h1:wS4gNoLalDSJxo/SpngzPQ2BN4uuZVLCmbM4S3vd4+Y=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
@@ -208,22 +262,44 @@ github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls=
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
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/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.4 h1:l75CXGRSwbaYNpl/Z2X1XIIAMSCquvXgpVZDhwEIJsc=
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v0.0.0-20181025225059-d3de96c4c28e/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-containerregistry v0.0.0-20200331213917-3d03ed9b1ca2 h1:k2YJ1fw6LwICNNUQHZNp9vTtHMuVqHJtMjZOc5SDIJo=
github.com/google/go-containerregistry v0.0.0-20200331213917-3d03ed9b1ca2/go.mod h1:pD1UFYs7MCAx+ZLShBdttcaOSbyc8F9Na/9IZLNwJeA=
github.com/google/go-github/v28 v28.1.1 h1:kORf5ekX5qwXO2mGzXXOjMe/g6ap8ahVe0sBEulhSxo=
@@ -233,7 +309,14 @@ github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO
github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/subcommands v1.0.1/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
@@ -241,11 +324,13 @@ github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+
github.com/google/wire v0.3.0 h1:imGQZGEVEHpje5056+K+cgdO72p0LQv2xIIFXNGUf60=
github.com/google/wire v0.3.0/go.mod h1:i1DMg/Lu8Sz5yYl25iOdmc5CT5qusaa+zmRWs16741s=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
github.com/googleapis/gnostic v0.2.2/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00 h1:l5lAOZEym3oK3SQ2HBHWsJUfbNBiTXJDeW2QDxw9AQ0=
github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
github.com/gorilla/mux v0.0.0-20181024020800-521ea7b17d02/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
@@ -262,14 +347,16 @@ github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/U
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-multierror v1.1.0 h1:B9UzwGQJehnUY1yNrnwREHc3fGbC2xefo8g4TbElacI=
github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA=
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/go-version v1.2.1 h1:zEfKbn2+PDgroKdiOzqiE8rsmLqU2uwi5PB5pBJ3TkI=
github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
@@ -284,6 +371,7 @@ github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCV
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
@@ -326,15 +414,14 @@ github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA=
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.7 h1:bQGKb3vps/j0E9GfJQ03JyhRuxsvdAanXlT9BTw3mdw=
github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
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-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
@@ -343,8 +430,9 @@ github.com/mattn/go-jsonpointer v0.0.0-20180225143300-37667080efed/go.mod h1:SDJ
github.com/mattn/go-runewidth v0.0.0-20181025052659-b20a3daf6a39/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
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/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2/go.mod h1:eD9eIE7cdwcMi9rYluz88Jz2VyhSmden33/aXg4oVIY=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
@@ -436,10 +524,12 @@ github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMB
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.5.0 h1:1N5EYkVAPEywqZRJd7cwnRtCb6xJx7NH3T3WUTF980Q=
github.com/sirupsen/logrus v1.5.0/go.mod h1:+F7Ogzej0PZc/94MaYx/nvG9jOFMD2osvC3s+Squfpo=
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/assertions v1.2.0 h1:42S6lae5dvLc7BrLu/0ugRtcFVjoJNMC/N3yZFZkDFs=
github.com/smartystreets/assertions v1.2.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo=
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
github.com/sosedoff/gitkit v0.2.0 h1:cVre9QZvsDzS/v42PSOsf+GCaecvb/CWGX+diP232F8=
github.com/sosedoff/gitkit v0.2.0/go.mod h1:A+o6ZazfVJwetlcHz3ah6th66XcBdsyzLo+aBt/AsK4=
@@ -459,14 +549,12 @@ github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48=
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
github.com/stretchr/objx v0.3.0 h1:NGXK3lHquSN08v5vWalVI/L8XU9hdzE/G6xsrze47As=
github.com/stretchr/objx v0.3.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
@@ -479,10 +567,13 @@ github.com/twitchtv/twirp v5.10.1+incompatible/go.mod h1:RRJoFSAmTEh2weEqWtpPE3v
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
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/urfave/cli v1.22.4 h1:u7tSpNPPswAFymm8IehJhy4uJMlUuU/GmqSkvJ1InXA=
github.com/urfave/cli v1.22.4/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/urfave/cli/v2 v2.2.0 h1:JTTnM6wKzdA0Jqodd966MVj4vWbbquZykeX1sKbe2C4=
github.com/urfave/cli/v2 v2.2.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ=
github.com/urfave/cli/v2 v2.3.0 h1:qph92Y649prgesehzOrQjdWyxFOp/QVM+6imKHad91M=
github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
github.com/vdemeester/k8s-pkg-credentialprovider v1.17.4/go.mod h1:inCTmtUdr5KJbreVojo06krnTgaeAz/Z7lynpPk/Q2c=
github.com/vmware/govmomi v0.20.3/go.mod h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59bHWk6aFU=
github.com/xanzy/ssh-agent v0.2.1 h1:TCbipTQL2JiiCprBWx9frJ2eJlCYT00NmctrHxVAr70=
@@ -491,11 +582,18 @@ github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
github.com/yashtewari/glob-intersection v0.0.0-20180916065949-5c77d914dd0b h1:vVRagRXf67ESqAb72hG2C/ZwI8NtJF2u2V76EsuOHGY=
github.com/yashtewari/glob-intersection v0.0.0-20180916065949-5c77d914dd0b/go.mod h1:HptNXiXVDcJjXe9SqMd0v2FsL9f8dz4GnXgltU6q/co=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.etcd.io/bbolt v1.3.5 h1:XAzx9gjCb0Rxj7EoqcClPD1d5ZBxZJk0jbuoPHenBt0=
go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/atomic v1.5.1 h1:rsqfU5vBkVknbhUGbAUwQKR2H4ItV8tjJ+6kJX4cxHM=
@@ -515,31 +613,50 @@ golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnf
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-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073 h1:xMPOj6Pz6UipU1wXLkrtqpHbR0AVFnyPEQq/wRWz9lM=
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de h1:ikNHVSjEfnvz6sxdSPCaPt572qowuyMDMJLLm3Db3ig=
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0 h1:hb9wdF1z5waM+dSIICn1l0DkLVDT3hqhhQsDNUmHPRE=
golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190312203227-4b39c73a6495/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/lint v0.0.0-20181023182221-1baf3a9d7d67/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=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs=
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/lint v0.0.0-20200302205851-738671d3881b h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k=
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee h1:WG0RUwxtNT4qqaXX3DPA8zHFNm/D9xaBpxzHt1WcA/E=
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
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=
@@ -550,28 +667,46 @@ golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73r
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-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200301022130-244492dfa37a h1:GuSPYbZzB5/dcLNCwLQLsg3obCJtX9IJhpXkvY7kzk0=
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200625001655-4c5254603344 h1:vGXIOMxbNfDTk/aXCmfdLgkrSV+Z2tcbze+pEc3v5W4=
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0 h1:wBouT66WTYFXdxfVdz9sVWARVd/2vfGcmI45D2gj45M=
golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43 h1:ld7aEMNHoBnnDAX15v1T6z31v8HwR2A9FYOuAhWqkwc=
golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208 h1:qwRHBd0NqMbJxfbotnDhm2ByMI1Shq4Y6oRJo21SGJA=
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -588,30 +723,49 @@ golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20190312061237-fead79001313/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-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191128015809-6d18c012aee9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200327173247-9dae0f8f5775 h1:TC0v2RSO1u2kn1ZugjrFXkRZAEaqMN/RW+OTZkBzmLE=
golang.org/x/sys v0.0.0-20200327173247-9dae0f8f5775/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200824131525-c12d262b63d8 h1:AvbQYmiaaaza3cW3QXRyPo5kYgpFIzOAfeAAN7m3qQ4=
golang.org/x/sys v0.0.0-20200824131525-c12d262b63d8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200831180312-196b9ba8737a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201006155630-ac719f4daadf h1:Bg47KQy0JhTHuf4sLiQwTMKwUMfSDwgSGatrxGR7nLM=
golang.org/x/sys v0.0.0-20201006155630-ac719f4daadf/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
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/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@@ -631,17 +785,48 @@ golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/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-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190706070813-72ffa07ba3db/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI=
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191011211836-4c025a95b26e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200210192313-1ace956b0e17 h1:a/Fd23DJvg1CaeDH0dYHahE+hCI0v9rFgxSNIThoUcM=
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200210192313-1ace956b0e17/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d h1:W07d4xkoAUSNOkOzdzXCdFGxT7o2rW4q8M34tB2i//k=
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -653,32 +838,93 @@ gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6d
gonum.org/v1/netlib v0.0.0-20190331212654-76723241ea4e/go.mod h1:kS+toOQn6AQKjmKJ7gzohV1XkqsFehRA2FbsbkopSuQ=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/api v0.6.1-0.20190607001116-5213b8090861/go.mod h1:btoxGiFvQNVUZQ8W08zLtrVS08CNpINPEfxXxgJL1Q4=
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.5.0 h1:KxkO13IPW4Lslp2bz+KHP2E3gtFlrIGNThxkZQ3g+4c=
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.6 h1:lMO5rYAqUxkmaj76jAkRUvt5JZgFymx/+Q5Mzfivuhc=
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/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-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55 h1:gSJIx1SDwno+2ElGhA4+qG2zF97qiUzTM+rQ0klBOcE=
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987 h1:PDIOdWxZ8eRizhKa1AAvY53xsvLB1cWorMjslvY3VA8=
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.28.0 h1:bO/TA4OxCOummhSf10siHuG7vJOiwh7SpRpFZDkOgl4=
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.31.0 h1:T7P4R73V3SSDPhH7WW7ATbfViLtmamH0DKrP3f9AuDI=
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
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/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b h1:QRR6H1YWRnHb4Y/HeNFCTJLFVxaq6wH4YuVdsUOr75U=
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
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=
@@ -689,8 +935,9 @@ gopkg.in/gcfg.v1 v1.2.0/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o=
gopkg.in/go-playground/assert.v1 v1.2.1 h1:xoYuJVE7KT85PYWrN730RguIQO0ePzVRfFMXadIrXTM=
gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
gopkg.in/go-playground/validator.v9 v9.29.1/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ=
gopkg.in/go-playground/validator.v9 v9.30.0 h1:Wk0Z37oBmKj9/n+tPyBHZmeL19LaCoK3Qq48VwYENss=
gopkg.in/go-playground/validator.v9 v9.30.0/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ=
gopkg.in/go-playground/validator.v9 v9.31.0 h1:bmXmP2RSNtFES+bn4uYuHT7iJFJv7Vj+an+ZQdDaD1M=
gopkg.in/go-playground/validator.v9 v9.31.0/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA=
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
@@ -704,6 +951,7 @@ gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRN
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/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
@@ -719,8 +967,10 @@ honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWh
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/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=
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
honnef.co/go/tools v0.0.1-2020.1.4 h1:UoveltGrhghAA7ePc+e+QYDHXrBps2PqFZiHkGR/xK8=
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
k8s.io/api v0.17.4/go.mod h1:5qxx6vjmwUVG2nHQTKGlLts8Tbok8PzHl4vHtVFuZCA=
k8s.io/apimachinery v0.17.4/go.mod h1:gxLnyZcGNdZTCLnq3fgzyg2A5BVCHTNDFrw8AmuJ+0g=
k8s.io/apiserver v0.17.4/go.mod h1:5ZDQ6Xr5MNBxyi3iUZXS84QOhZl+W7Oq2us/29c0j9I=
@@ -734,11 +984,12 @@ k8s.io/gengo v0.0.0-20190822140433-26a664648505/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8
k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I=
k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE=
k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E=
k8s.io/legacy-cloud-providers v0.17.4/go.mod h1:FikRNoD64ECjkxO36gkDgJeiQWwyZTuBkhu+yxOc1Js=
k8s.io/utils v0.0.0-20191010214722-8d271d903fe4/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
k8s.io/utils v0.0.0-20191114184206-e782cd3c129f h1:GiPwtSzdP43eI1hpPCbROQCCIgCuiMMNF8YUVLF3vJo=
k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
k8s.io/utils v0.0.0-20201005171033-6301aaf42dc7 h1:XQ0OMFdRDkDIu0b1zqEKSZdWUD7I4bZ4d4nqr8CLKbQ=
k8s.io/utils v0.0.0-20201005171033-6301aaf42dc7/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
modernc.org/cc v1.0.0/go.mod h1:1Sk4//wdnYJiUIxnW8ddKpaOJCF37yAdqYnkxUpaYxw=
modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk=
modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k=
@@ -746,6 +997,9 @@ modernc.org/strutil v1.0.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs
modernc.org/xc v1.0.0/go.mod h1:mRNCo0bvLjGhHO9WsyuKVU4q0ceiDDDoEeWDJHrNx8I=
moul.io/http2curl v1.0.0 h1:6XwpyZOYsgZJrU8exnG87ncVkU1FVCcTRpwzOkTDUi8=
moul.io/http2curl v1.0.0/go.mod h1:f6cULg+e4Md/oW1cYmwW4IWQOVl2lGbmCNGOHvzX2kE=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI=
sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06/go.mod h1:/ULNhyfzRopfcjskuui0cTITekDduZ7ycKN3oUT9R18=
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=

View File

@@ -12,11 +12,14 @@ builds:
goos:
- darwin
- linux
- freebsd
- openbsd
goarch:
- amd64
- 386
- arm
- arm64
- ppc64le
goarm:
- 7
ignore:
@@ -41,6 +44,7 @@ nfpms:
386: 32bit
arm: ARM
arm64: ARM64
ppc64le: PPC64LE
darwin: macOS
linux: Linux
openbsd: OpenBSD
@@ -57,6 +61,7 @@ archives:
386: 32bit
arm: ARM
arm64: ARM64
ppc64le: PPC64LE
darwin: macOS
linux: Linux
openbsd: OpenBSD

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 MiB

After

Width:  |  Height:  |  Size: 3.6 MiB

View File

@@ -15,12 +15,14 @@ import (
"github.com/docker/docker/api/types"
)
// RegistryConfig holds the config for docker registry
type RegistryConfig struct {
URL *url.URL
Username string
Password string
}
// GetAuthConfig returns the docker registry authConfig
func (c RegistryConfig) GetAuthConfig() types.AuthConfig {
return types.AuthConfig{
Username: c.Username,
@@ -29,6 +31,7 @@ func (c RegistryConfig) GetAuthConfig() types.AuthConfig {
}
}
// GetRegistryAuth returns the json encoded docker registry auth
func (c RegistryConfig) GetRegistryAuth() (string, error) {
authConfig := types.AuthConfig{
Username: c.Username,
@@ -41,10 +44,12 @@ func (c RegistryConfig) GetRegistryAuth() (string, error) {
return base64.URLEncoding.EncodeToString(encodedJSON), nil
}
// Docker returns docker client
type Docker struct {
cli *client.Client
}
// New is the factory method to return docker client
func New() (Docker, error) {
cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
if err != nil {
@@ -73,7 +78,7 @@ func (d Docker) ReplicateImage(ctx context.Context, imageRef, imagePath string,
if err != nil {
return err
}
if _, err := io.Copy(ioutil.Discard, resp.Body); err != nil {
if _, err = io.Copy(ioutil.Discard, resp.Body); err != nil {
return err
}
defer resp.Body.Close()

View File

@@ -7,11 +7,12 @@
"VulnerabilityID": "RUSTSEC-2019-0001",
"PkgName": "ammonia",
"InstalledVersion": "1.9.0",
"FixedVersion": "\u003e= 2.1.0",
"Layer": {
"DiffID": "sha256:ea6f6933da66090da8bfe233d68f083792a68f944cd2d8f9fbb52da795813a4f"
},
"Title": "Uncontrolled recursion leads to abort in HTML serialization",
"Description": "Affected versions of this crate did use recursion for serialization of HTML\nDOM trees.\n\nThis allows an attacker to cause abort due to stack overflow by providing\na pathologically nested input.\n\nThe flaw was corrected by serializing the DOM tree iteratively instead.\n",
"Description": "Affected versions of this crate did use recursion for serialization of HTML\nDOM trees.\n\nThis allows an attacker to cause abort due to stack overflow by providing\na pathologically nested input.\n\nThe flaw was corrected by serializing the DOM tree iteratively instead.",
"Severity": "UNKNOWN",
"References": [
"https://github.com/rust-ammonia/ammonia/blob/master/CHANGELOG.md#210"
@@ -21,53 +22,72 @@
"VulnerabilityID": "RUSTSEC-2016-0001",
"PkgName": "openssl",
"InstalledVersion": "0.8.3",
"FixedVersion": "\u003e= 0.9.0",
"Layer": {
"DiffID": "sha256:ea6f6933da66090da8bfe233d68f083792a68f944cd2d8f9fbb52da795813a4f"
},
"Title": "SSL/TLS MitM vulnerability due to insecure defaults",
"Description": "All versions of rust-openssl prior to 0.9.0 contained numerous insecure defaults\nincluding off-by-default certificate verification and no API to perform hostname\nverification.\n\nUnless configured correctly by a developer, these defaults could allow an attacker\nto perform man-in-the-middle attacks.\n\nThe problem was addressed in newer versions by enabling certificate verification\nby default and exposing APIs to perform hostname verification. Use the\n`SslConnector` and `SslAcceptor` types to take advantage of these new features\n(as opposed to the lower-level `SslContext` type).\n",
"Description": "All versions of rust-openssl prior to 0.9.0 contained numerous insecure defaults\nincluding off-by-default certificate verification and no API to perform hostname\nverification.\n\nUnless configured correctly by a developer, these defaults could allow an attacker\nto perform man-in-the-middle attacks.\n\nThe problem was addressed in newer versions by enabling certificate verification\nby default and exposing APIs to perform hostname verification. Use the\n`SslConnector` and `SslAcceptor` types to take advantage of these new features\n(as opposed to the lower-level `SslContext` type).",
"Severity": "UNKNOWN",
"References": [
"https://github.com/sfackler/rust-openssl/releases/tag/v0.9.0"
]
},
{
"VulnerabilityID": "RUSTSEC-2018-0010",
"PkgName": "openssl",
"InstalledVersion": "0.8.3",
"VulnerabilityID": "RUSTSEC-2019-0035",
"PkgName": "rand_core",
"InstalledVersion": "0.3.1",
"FixedVersion": "\u003e= 0.4.2",
"Layer": {
"DiffID": "sha256:ea6f6933da66090da8bfe233d68f083792a68f944cd2d8f9fbb52da795813a4f"
},
"Title": "Use after free in CMS Signing",
"Description": "Affected versions of the OpenSSL crate used structures after they'd been freed.",
"Title": "Unaligned memory access",
"Description": "Affected versions of this crate violated alignment when casting byte slices to\ninteger slices, resulting in undefined behavior.\n\nThe flaw was corrected by Ralf Jung and Diggory Hardy.",
"Severity": "UNKNOWN",
"References": [
"https://github.com/sfackler/rust-openssl/pull/942"
"https://github.com/rust-random/rand/blob/master/rand_core/CHANGELOG.md#050---2019-06-06"
]
},
{
"VulnerabilityID": "RUSTSEC-2018-0003",
"PkgName": "smallvec",
"InstalledVersion": "0.6.9",
"VulnerabilityID": "RUSTSEC-2019-0035",
"PkgName": "rand_core",
"InstalledVersion": "0.4.0",
"FixedVersion": "\u003e= 0.4.2",
"Layer": {
"DiffID": "sha256:ea6f6933da66090da8bfe233d68f083792a68f944cd2d8f9fbb52da795813a4f"
},
"Title": "Possible double free during unwinding in SmallVec::insert_many",
"Description": "If an iterator passed to `SmallVec::insert_many` panicked in `Iterator::next`,\ndestructors were run during unwinding while the vector was in an inconsistent\nstate, possibly causing a double free (a destructor running on two copies of\nthe same value).\n\nThis is fixed in smallvec 0.6.3 by ensuring that the vector's length is not\nupdated to include moved items until they have been removed from their\noriginal positions. Items may now be leaked if `Iterator::next` panics, but\nthey will not be dropped more than once.\n\nThank you to @Vurich for reporting this bug.\n",
"Title": "Unaligned memory access",
"Description": "Affected versions of this crate violated alignment when casting byte slices to\ninteger slices, resulting in undefined behavior.\n\nThe flaw was corrected by Ralf Jung and Diggory Hardy.",
"Severity": "UNKNOWN",
"References": [
"https://github.com/servo/rust-smallvec/issues/96"
"https://github.com/rust-random/rand/blob/master/rand_core/CHANGELOG.md#050---2019-06-06"
]
},
{
"VulnerabilityID": "RUSTSEC-2018-0018",
"PkgName": "smallvec",
"InstalledVersion": "0.6.9",
"FixedVersion": "\u003e= 0.6.13",
"Layer": {
"DiffID": "sha256:ea6f6933da66090da8bfe233d68f083792a68f944cd2d8f9fbb52da795813a4f"
},
"Title": "smallvec creates uninitialized value of any type",
"Description": "Affected versions of this crate called `mem::uninitialized()` to create values of a user-supplied type `T`.\nThis is unsound e.g. if `T` is a reference type (which must be non-null and thus may not remain uninitialized).\n \nThe flaw was corrected by avoiding the use of `mem::uninitialized()`, using `MaybeUninit` instead.",
"Severity": "UNKNOWN",
"References": [
"https://github.com/servo/rust-smallvec/issues/126"
]
},
{
"VulnerabilityID": "RUSTSEC-2019-0009",
"PkgName": "smallvec",
"InstalledVersion": "0.6.9",
"FixedVersion": "\u003e= 0.6.10",
"Layer": {
"DiffID": "sha256:ea6f6933da66090da8bfe233d68f083792a68f944cd2d8f9fbb52da795813a4f"
},
"Title": "Double-free and use-after-free in SmallVec::grow()",
"Description": "Attempting to call `grow` on a spilled SmallVec with a value equal to the current capacity causes it to free the existing data. This performs a double free immediately and may lead to use-after-free on subsequent accesses to the SmallVec contents.\n\nAn attacker that controls the value passed to `grow` may exploit this flaw to obtain memory contents or gain remote code execution.\n\nCredits to @ehuss for discovering, reporting and fixing the bug.\n",
"Description": "Attempting to call `grow` on a spilled SmallVec with a value equal to the current capacity causes it to free the existing data. This performs a double free immediately and may lead to use-after-free on subsequent accesses to the SmallVec contents.\n\nAn attacker that controls the value passed to `grow` may exploit this flaw to obtain memory contents or gain remote code execution.\n\nCredits to @ehuss for discovering, reporting and fixing the bug.",
"Severity": "UNKNOWN",
"References": [
"https://github.com/servo/rust-smallvec/issues/148"
@@ -77,15 +97,30 @@
"VulnerabilityID": "RUSTSEC-2019-0012",
"PkgName": "smallvec",
"InstalledVersion": "0.6.9",
"FixedVersion": "\u003e= 0.6.10",
"Layer": {
"DiffID": "sha256:ea6f6933da66090da8bfe233d68f083792a68f944cd2d8f9fbb52da795813a4f"
},
"Title": "Memory corruption in SmallVec::grow()",
"Description": "Attempting to call `grow` on a spilled SmallVec with a value less than the current capacity causes corruption of memory allocator data structures.\n\nAn attacker that controls the value passed to `grow` may exploit this flaw to obtain memory contents or gain remote code execution.\n\nCredits to @ehuss for discovering, reporting and fixing the bug.\n",
"Description": "Attempting to call `grow` on a spilled SmallVec with a value less than the current capacity causes corruption of memory allocator data structures.\n\nAn attacker that controls the value passed to `grow` may exploit this flaw to obtain memory contents or gain remote code execution.\n\nCredits to @ehuss for discovering, reporting and fixing the bug.",
"Severity": "UNKNOWN",
"References": [
"https://github.com/servo/rust-smallvec/issues/149"
]
},
{
"VulnerabilityID": "RUSTSEC-2018-0017",
"PkgName": "tempdir",
"InstalledVersion": "0.3.7",
"Layer": {
"DiffID": "sha256:ea6f6933da66090da8bfe233d68f083792a68f944cd2d8f9fbb52da795813a4f"
},
"Title": "`tempdir` crate has been deprecated; use `tempfile` instead",
"Description": "The [`tempdir`](https://crates.io/crates/tempdir) crate has been deprecated\nand the functionality is merged into [`tempfile`](https://crates.io/crates/tempfile).",
"Severity": "UNKNOWN",
"References": [
"https://github.com/rust-lang-deprecated/tempdir/pull/46"
]
}
]
}

Binary file not shown.

View File

@@ -20,6 +20,7 @@ import (
"github.com/aquasecurity/trivy/pkg/vulnerability"
)
// VersionInfo holds the trivy DB version Info
type VersionInfo struct {
Version string `json:",omitempty"`
VulnerabilityDB *db.Metadata `json:",omitempty"`
@@ -250,6 +251,7 @@ var (
}
)
// NewApp is the factory method to return Trivy CLI
func NewApp(version string) *cli.App {
cli.VersionPrinter = func(c *cli.Context) {
showVersion(c.String("cache-dir"), c.String("format"), c.App.Version, c.App.Writer)
@@ -307,19 +309,20 @@ func setHidden(flags []cli.Flag, hidden bool) []cli.Flag {
func showVersion(cacheDir, outputFormat, version string, outputWriter io.Writer) {
var dbMeta *db.Metadata
metadata, _ := tdb.NewMetadata(afero.NewOsFs(), cacheDir).Get()
metadata, _ := tdb.NewMetadata(afero.NewOsFs(), cacheDir).Get() // nolint: errcheck
if !metadata.UpdatedAt.IsZero() && !metadata.NextUpdate.IsZero() && metadata.Version != 0 {
dbMeta = &db.Metadata{
Version: metadata.Version,
Type: metadata.Type,
NextUpdate: metadata.NextUpdate.UTC(),
UpdatedAt: metadata.UpdatedAt.UTC(),
DownloadedAt: metadata.DownloadedAt.UTC(),
}
}
switch outputFormat {
case "json":
b, _ := json.Marshal(VersionInfo{
b, _ := json.Marshal(VersionInfo{ // nolint: errcheck
Version: version,
VulnerabilityDB: dbMeta,
})
@@ -339,12 +342,14 @@ func showVersion(cacheDir, outputFormat, version string, outputWriter io.Writer)
Version: %d
UpdatedAt: %s
NextUpdate: %s
`, dbType, dbMeta.Version, dbMeta.UpdatedAt.UTC(), dbMeta.NextUpdate.UTC())
DownloadedAt: %s
`, dbType, dbMeta.Version, dbMeta.UpdatedAt.UTC(), dbMeta.NextUpdate.UTC(), dbMeta.DownloadedAt.UTC())
}
fmt.Fprintf(outputWriter, output)
}
}
// NewImageCommand is the factory method to add image command
func NewImageCommand() *cli.Command {
return &cli.Command{
Name: "image",
@@ -356,6 +361,7 @@ func NewImageCommand() *cli.Command {
}
}
// NewFilesystemCommand is the factory method to add filesystem command
func NewFilesystemCommand() *cli.Command {
return &cli.Command{
Name: "filesystem",
@@ -389,6 +395,7 @@ func NewFilesystemCommand() *cli.Command {
}
}
// NewRepositoryCommand is the factory method to add repository command
func NewRepositoryCommand() *cli.Command {
return &cli.Command{
Name: "repository",
@@ -422,6 +429,7 @@ func NewRepositoryCommand() *cli.Command {
}
}
// NewClientCommand is the factory method to add client command
func NewClientCommand() *cli.Command {
return &cli.Command{
Name: "client",
@@ -465,6 +473,7 @@ func NewClientCommand() *cli.Command {
}
}
// NewServerCommand is the factory method to add server command
func NewServerCommand() *cli.Command {
return &cli.Command{
Name: "server",

View File

@@ -42,6 +42,7 @@ Vulnerability DB:
Version: 42
UpdatedAt: 2020-03-16 23:40:20 +0000 UTC
NextUpdate: 2020-03-16 23:57:00 +0000 UTC
DownloadedAt: 2020-03-16 23:40:20 +0000 UTC
`,
createDB: true,
},
@@ -51,7 +52,7 @@ Vulnerability DB:
outputFormat: "json",
version: "1.2.3",
},
expectedOutput: `{"Version":"1.2.3","VulnerabilityDB":{"Version":42,"Type":1,"NextUpdate":"2020-03-16T23:57:00Z","UpdatedAt":"2020-03-16T23:40:20Z"}}
expectedOutput: `{"Version":"1.2.3","VulnerabilityDB":{"Version":42,"Type":1,"NextUpdate":"2020-03-16T23:57:00Z","UpdatedAt":"2020-03-16T23:40:20Z","DownloadedAt":"2020-03-16T23:40:20Z"}}
`,
createDB: true,
},
@@ -97,6 +98,7 @@ Vulnerability DB:
Type: 1,
NextUpdate: time.Unix(1584403020, 0),
UpdatedAt: time.Unix(1584402020, 0),
DownloadedAt: time.Unix(1584402020, 0),
})
require.NoError(t, err)
err = afero.WriteFile(fs, metadataFile, b, 0600)
@@ -109,3 +111,12 @@ Vulnerability DB:
})
}
}
func TestNewCommands(t *testing.T) {
NewApp("test")
NewClientCommand()
NewFilesystemCommand()
NewImageCommand()
NewRepositoryCommand()
NewServerCommand()
}

View File

@@ -7,6 +7,7 @@ import (
"github.com/aquasecurity/trivy/internal/config"
)
// Config holds the artifact config
type Config struct {
config.GlobalConfig
config.ArtifactConfig
@@ -22,6 +23,7 @@ type Config struct {
autoRefresh bool
}
// New is the factory method to return config
func New(c *cli.Context) (Config, error) {
gc, err := config.NewGlobalConfig(c)
if err != nil {
@@ -41,6 +43,7 @@ func New(c *cli.Context) (Config, error) {
}, nil
}
// Init initializes the artifact config
func (c *Config) Init(image bool) error {
if err := c.ReportConfig.Init(c.Logger); err != nil {
return err
@@ -53,7 +56,7 @@ func (c *Config) Init(image bool) error {
}
// --clear-cache, --download-db-only and --reset don't conduct the scan
if c.ClearCache || c.DownloadDBOnly || c.Reset {
if c.skipScan() {
return nil
}
@@ -69,3 +72,10 @@ func (c *Config) Init(image bool) error {
return nil
}
func (c *Config) skipScan() bool {
if c.ClearCache || c.DownloadDBOnly || c.Reset {
return true
}
return false
}

View File

@@ -21,6 +21,7 @@ func filesystemScanner(ctx context.Context, dir string, ac cache.ArtifactCache,
return s, cleanup, nil
}
// FilesystemRun runs scan on filesystem
func FilesystemRun(cliCtx *cli.Context) error {
c, err := config.New(cliCtx)
if err != nil {

View File

@@ -30,6 +30,7 @@ func dockerScanner(ctx context.Context, imageName string, ac cache.ArtifactCache
return s, cleanup, nil
}
// ImageRun runs scan on docker image
func ImageRun(cliCtx *cli.Context) error {
c, err := config.New(cliCtx)
if err != nil {

View File

@@ -21,6 +21,7 @@ func repositoryScanner(ctx context.Context, dir string, ac cache.ArtifactCache,
return s, cleanup, nil
}
// RepositoryRun runs scan on repository
func RepositoryRun(cliCtx *cli.Context) error {
c, err := config.New(cliCtx)
if err != nil {

View File

@@ -19,9 +19,12 @@ import (
"github.com/aquasecurity/trivy/pkg/utils"
)
// InitializeScanner type to define initialize function signature
type InitializeScanner func(context.Context, string, cache.ArtifactCache, cache.LocalArtifactCache, time.Duration) (
scanner.Scanner, func(), error)
// nolint: gocyclo
// TODO: refactror and fix cyclometic complexity
func run(c config.Config, initializeScanner InitializeScanner) error {
if err := log.InitLogger(c.Debug, c.Quiet); err != nil {
l.Fatal(err)

View File

@@ -10,6 +10,7 @@ import (
"github.com/aquasecurity/trivy/internal/config"
)
// Config holds the Trivy client config
type Config struct {
config.GlobalConfig
config.ArtifactConfig
@@ -25,6 +26,7 @@ type Config struct {
CustomHeaders http.Header
}
// New is the factory method for Config
func New(c *cli.Context) (Config, error) {
gc, err := config.NewGlobalConfig(c)
if err != nil {
@@ -43,6 +45,7 @@ func New(c *cli.Context) (Config, error) {
}, nil
}
// Init initializes the config
func (c *Config) Init() (err error) {
// --clear-cache doesn't conduct the scan
if c.ClearCache {

View File

@@ -17,6 +17,7 @@ import (
"github.com/aquasecurity/trivy/pkg/utils"
)
// Run runs the scan
func Run(cliCtx *cli.Context) error {
c, err := config.New(cliCtx)
if err != nil {
@@ -25,6 +26,8 @@ func Run(cliCtx *cli.Context) error {
return run(c)
}
// nolint: gocyclo
// TODO: refactror and fix cyclometic complexity
func run(c config.Config) (err error) {
if err = log.InitLogger(c.Debug, c.Quiet); err != nil {
return xerrors.Errorf("failed to initialize a logger: %w", err)

View File

@@ -10,6 +10,7 @@ import (
"golang.org/x/xerrors"
)
// ArtifactConfig holds the config for a artifact scanning
type ArtifactConfig struct {
Input string
Timeout time.Duration
@@ -24,6 +25,7 @@ type ArtifactConfig struct {
Target string
}
// NewArtifactConfig is the factory method to return artifact config
func NewArtifactConfig(c *cli.Context) ArtifactConfig {
return ArtifactConfig{
Input: c.String("input"),
@@ -34,10 +36,11 @@ func NewArtifactConfig(c *cli.Context) ArtifactConfig {
}
}
// Init initialize the CLI context for artifact scanning
func (c *ArtifactConfig) Init(ctx *cli.Context, logger *zap.SugaredLogger) (err error) {
if c.Input == "" && ctx.Args().Len() == 0 {
logger.Debug(`trivy requires at least 1 argument or --input option`)
_ = cli.ShowSubcommandHelp(ctx)
_ = cli.ShowSubcommandHelp(ctx) // nolint: errcheck
os.Exit(0)
} else if ctx.Args().Len() > 1 {
logger.Error(`multiple targets cannot be specified`)

View File

@@ -5,6 +5,7 @@ import (
"golang.org/x/xerrors"
)
// DBConfig holds the config for trivy DB
type DBConfig struct {
Reset bool
DownloadDBOnly bool
@@ -13,6 +14,7 @@ type DBConfig struct {
NoProgress bool
}
// NewDBConfig is the factory method to return the DBConfig
func NewDBConfig(c *cli.Context) DBConfig {
return DBConfig{
Reset: c.Bool("reset"),
@@ -23,6 +25,7 @@ func NewDBConfig(c *cli.Context) DBConfig {
}
}
// Init initialize the DBConfig
func (c *DBConfig) Init() (err error) {
if c.SkipUpdate && c.DownloadDBOnly {
return xerrors.New("--skip-update and --download-db-only options can not be specified both")

View File

@@ -8,6 +8,7 @@ import (
"github.com/aquasecurity/trivy/pkg/log"
)
// GlobalConfig holds the global config for trivy
type GlobalConfig struct {
Context *cli.Context
Logger *zap.SugaredLogger
@@ -18,6 +19,7 @@ type GlobalConfig struct {
CacheDir string
}
// NewGlobalConfig is the factory method to return GlobalConfig
func NewGlobalConfig(c *cli.Context) (GlobalConfig, error) {
quiet := c.Bool("quiet")
debug := c.Bool("debug")

View File

@@ -7,11 +7,13 @@ import (
"golang.org/x/xerrors"
)
// ImageConfig holds the config for scanning images
type ImageConfig struct {
ScanRemovedPkgs bool
ListAllPkgs bool
}
// NewImageConfig is the factory method to return imageConfig
func NewImageConfig(c *cli.Context) ImageConfig {
return ImageConfig{
ScanRemovedPkgs: c.Bool("removed-pkgs"),
@@ -19,6 +21,7 @@ func NewImageConfig(c *cli.Context) ImageConfig {
}
}
// Init initializes the imageConfig
func (c *ImageConfig) Init(args cli.Args, logger *zap.SugaredLogger) (err error) {
imageName := args.First()

View File

@@ -11,6 +11,7 @@ import (
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
)
// ReportConfig holds the config for reporting scan results
type ReportConfig struct {
Format string
Template string
@@ -31,6 +32,7 @@ type ReportConfig struct {
Severities []dbTypes.Severity
}
// NewReportConfig is the factory method to return ReportConfig
func NewReportConfig(c *cli.Context) ReportConfig {
return ReportConfig{
output: c.String("output"),
@@ -46,6 +48,7 @@ func NewReportConfig(c *cli.Context) ReportConfig {
}
}
// Init initializes the ReportConfig
func (c *ReportConfig) Init(logger *zap.SugaredLogger) (err error) {
if c.Template != "" {
if c.Format == "" {

View File

@@ -15,20 +15,24 @@ import (
"github.com/aquasecurity/trivy/pkg/utils"
)
// SuperSet binds cache dependencies
var SuperSet = wire.NewSet(
cache.NewFSCache,
wire.Bind(new(cache.LocalArtifactCache), new(cache.FSCache)),
NewCache,
)
// Cache implements the local cache
type Cache struct {
client cache.LocalArtifactCache
}
// NewCache is the factory method for Cache
func NewCache(client cache.LocalArtifactCache) Cache {
return Cache{client: client}
}
// Reset resets the cache
func (c Cache) Reset() (err error) {
if err := c.ClearDB(); err != nil {
return xerrors.Errorf("failed to clear the database: %w", err)
@@ -39,6 +43,7 @@ func (c Cache) Reset() (err error) {
return nil
}
// ClearDB clears the DB cache
func (c Cache) ClearDB() (err error) {
log.Logger.Info("Removing DB file...")
if err = os.RemoveAll(utils.CacheDir()); err != nil {
@@ -47,6 +52,7 @@ func (c Cache) ClearDB() (err error) {
return nil
}
// ClearImages clears the cache images
func (c Cache) ClearImages() error {
log.Logger.Info("Removing image caches...")
if err := c.client.Clear(); err != nil {
@@ -55,6 +61,7 @@ func (c Cache) ClearImages() error {
return nil
}
// DownloadDB downloads the DB
func DownloadDB(appVersion, cacheDir string, quiet, light, skipUpdate bool) error {
client := initializeDBClient(cacheDir, quiet)
ctx := context.Background()
@@ -66,7 +73,7 @@ func DownloadDB(appVersion, cacheDir string, quiet, light, skipUpdate bool) erro
if needsUpdate {
log.Logger.Info("Need to update DB")
log.Logger.Info("Downloading DB...")
if err := client.Download(ctx, cacheDir, light); err != nil {
if err = client.Download(ctx, cacheDir, light); err != nil {
return xerrors.Errorf("failed to download vulnerability DB: %w", err)
}
if err = client.UpdateMetadata(cacheDir); err != nil {
@@ -87,7 +94,7 @@ func showDBInfo(cacheDir string) error {
if err != nil {
return xerrors.Errorf("something wrong with DB: %w", err)
}
log.Logger.Debugf("DB Schema: %d, Type: %d, UpdatedAt: %s, NextUpdate: %s",
metadata.Version, metadata.Type, metadata.UpdatedAt, metadata.NextUpdate)
log.Logger.Debugf("DB Schema: %d, Type: %d, UpdatedAt: %s, NextUpdate: %s, DownloadedAt: %s",
metadata.Version, metadata.Type, metadata.UpdatedAt, metadata.NextUpdate, metadata.DownloadedAt)
return nil
}

View File

@@ -1,10 +1,12 @@
package config
import (
"github.com/aquasecurity/trivy/internal/config"
"github.com/urfave/cli/v2"
"github.com/aquasecurity/trivy/internal/config"
)
// Config holds the Trivy config
type Config struct {
config.GlobalConfig
config.DBConfig
@@ -14,10 +16,10 @@ type Config struct {
TokenHeader string
}
// New is the factory method to return cofig
func New(c *cli.Context) Config {
// the error is ignored because logger is unnecessary
gc, _ := config.NewGlobalConfig(c)
gc, _ := config.NewGlobalConfig(c) // nolint: errcheck
return Config{
GlobalConfig: gc,
DBConfig: config.NewDBConfig(c),
@@ -28,6 +30,7 @@ func New(c *cli.Context) Config {
}
}
// Init initializes the DB config
func (c *Config) Init() (err error) {
if err := c.DBConfig.Init(); err != nil {
return err

View File

@@ -13,6 +13,7 @@ import (
"github.com/aquasecurity/trivy/pkg/utils"
)
// Run runs the scan
func Run(ctx *cli.Context) error {
return run(config.New(ctx))
}

View File

@@ -32,7 +32,7 @@ func debianEOL() {
if len(fields) < 6 && fields[0] != "" {
fmt.Printf("\"%s\": time.Date(3000, 1, 1, 23, 59, 59, 0, time.UTC),\n", fields[0])
} else if len(fields) == 6 {
eol, _ := time.Parse("2006-1-2", fields[5])
eol, _ := time.Parse("2006-1-2", fields[5]) // nolint: errcheck
fmt.Printf("\"%s\": time.Date(%d, %d, %d, 23, 59, 59, 0, time.UTC),\n", fields[0], eol.Year(), eol.Month(), eol.Day())
}
}
@@ -49,8 +49,7 @@ func ubuntuEOL() {
for scanner.Scan() {
line := scanner.Text()
fields := strings.Split(line, ",")
eol, _ := time.Parse("2006-1-2", fields[len(fields)-1])
eol, _ := time.Parse("2006-1-2", fields[len(fields)-1]) // nolint: errcheck
fmt.Printf("\"%s\": time.Date(%d, %d, %d, 23, 59, 59, 0, time.UTC),\n", strings.Fields(fields[0])[0], eol.Year(), eol.Month(), eol.Day())
}
}

10
pkg/cache/remote.go vendored
View File

@@ -13,35 +13,41 @@ import (
rpcCache "github.com/aquasecurity/trivy/rpc/cache"
)
// RemoteCache implements remote cache
type RemoteCache struct {
ctx context.Context // for custom header
client rpcCache.Cache
}
// RemoteURL to hold remote host
type RemoteURL string
// NewRemoteCache is the factory method for RemoteCache
func NewRemoteCache(url RemoteURL, customHeaders http.Header) cache.ArtifactCache {
ctx := client.WithCustomHeaders(context.Background(), customHeaders)
c := rpcCache.NewCacheProtobufClient(string(url), &http.Client{})
return &RemoteCache{ctx: ctx, client: c}
}
// PutArtifact sends artifact to remote client
func (c RemoteCache) PutArtifact(imageID string, imageInfo types.ArtifactInfo) error {
_, err := c.client.PutArtifact(c.ctx, rpc.ConvertToRpcArtifactInfo(imageID, imageInfo))
_, err := c.client.PutArtifact(c.ctx, rpc.ConvertToRPCArtifactInfo(imageID, imageInfo))
if err != nil {
return xerrors.Errorf("unable to store cache on the server: %w", err)
}
return nil
}
// PutBlob sends blobInfo to remote client
func (c RemoteCache) PutBlob(diffID string, layerInfo types.BlobInfo) error {
_, err := c.client.PutBlob(c.ctx, rpc.ConvertToRpcBlobInfo(diffID, layerInfo))
_, err := c.client.PutBlob(c.ctx, rpc.ConvertToRPCBlobInfo(diffID, layerInfo))
if err != nil {
return xerrors.Errorf("unable to store cache on the server: %w", err)
}
return nil
}
// MissingBlobs fetches missing blobs from RemoteCache
func (c RemoteCache) MissingBlobs(imageID string, layerIDs []string) (bool, []string, error) {
layers, err := c.client.MissingBlobs(c.ctx, rpc.ConvertToMissingBlobsRequest(imageID, layerIDs))
if err != nil {

View File

@@ -7,6 +7,7 @@ import (
"io"
"os"
"path/filepath"
"time"
"github.com/google/wire"
"github.com/spf13/afero"
@@ -24,8 +25,11 @@ const (
lightDB = "trivy-light.db.gz"
metadataFile = "metadata.json"
gb = 1024 * 1024 * 1024
)
// SuperSet binds the dependencies
var SuperSet = wire.NewSet(
// indicator.ProgressBar
indicator.NewProgressBar,
@@ -51,6 +55,7 @@ var SuperSet = wire.NewSet(
wire.Bind(new(Operation), new(Client)),
)
// Operation defines the DB operations
type Operation interface {
NeedsUpdate(cliVersion string, skip, light bool) (need bool, err error)
Download(ctx context.Context, cacheDir string, light bool) (err error)
@@ -62,6 +67,7 @@ type dbOperation interface {
StoreMetadata(metadata db.Metadata, dir string) (err error)
}
// Client implements DB operations
type Client struct {
dbc dbOperation
githubClient github.Operation
@@ -70,6 +76,7 @@ type Client struct {
metadata Metadata
}
// NewClient is the factory method for DB client
func NewClient(dbc dbOperation, githubClient github.Operation, pb indicator.ProgressBar, clock clock.Clock, metadata Metadata) Client {
return Client{
dbc: dbc,
@@ -80,6 +87,7 @@ func NewClient(dbc dbOperation, githubClient github.Operation, pb indicator.Prog
}
}
// NeedsUpdate check is DB needs update
func (c Client) NeedsUpdate(cliVersion string, light, skip bool) (bool, error) {
dbType := db.TypeFull
if light {
@@ -103,28 +111,48 @@ func (c Client) NeedsUpdate(cliVersion string, light, skip bool) (bool, error) {
}
if skip {
if err = c.validate(dbType, metadata); err != nil {
return false, err
}
return false, nil
}
if db.SchemaVersion != metadata.Version || metadata.Type != dbType {
return true, nil
}
return !c.isNewDB(metadata), nil
}
func (c Client) validate(dbType db.Type, metadata db.Metadata) error {
if db.SchemaVersion != metadata.Version {
log.Logger.Error("The local DB is old and needs to be updated")
return false, xerrors.New("--skip-update cannot be specified with the old DB")
return xerrors.New("--skip-update cannot be specified with the old DB")
} else if metadata.Type != dbType {
if dbType == db.TypeFull {
log.Logger.Error("The local DB is a lightweight DB. You have to download a full DB")
} else {
log.Logger.Error("The local DB is a full DB. You have to download a lightweight DB")
}
return false, xerrors.New("--skip-update cannot be specified with the different schema DB")
return xerrors.New("--skip-update cannot be specified with the different schema DB")
}
return false, nil
return nil
}
if db.SchemaVersion == metadata.Version && metadata.Type == dbType &&
c.clock.Now().Before(metadata.NextUpdate) {
func (c Client) isNewDB(metadata db.Metadata) bool {
if c.clock.Now().Before(metadata.NextUpdate) {
log.Logger.Debug("DB update was skipped because DB is the latest")
return false, nil
}
return true, nil
return true
}
if c.clock.Now().Before(metadata.DownloadedAt.Add(time.Hour)) {
log.Logger.Debug("DB update was skipped because DB was downloaded during the last hour")
return true
}
return false
}
// Download downloads the DB file
func (c Client) Download(ctx context.Context, cacheDir string, light bool) error {
// Remove the metadata file before downloading DB
if err := c.metadata.Delete(); err != nil {
@@ -145,7 +173,6 @@ func (c Client) Download(ctx context.Context, cacheDir string, light bool) error
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)
@@ -164,13 +191,15 @@ func (c Client) Download(ctx context.Context, cacheDir string, light bool) error
}
defer file.Close()
if _, err = io.Copy(file, gr); err != nil {
limited := io.LimitReader(gr, 2*gb)
if _, err = io.Copy(file, limited); err != nil {
return xerrors.Errorf("failed to save DB file: %w", err)
}
return nil
}
// UpdateMetadata updates the DB metadata
func (c Client) UpdateMetadata(cacheDir string) error {
log.Logger.Debug("Updating database metadata...")
@@ -185,6 +214,7 @@ func (c Client) UpdateMetadata(cacheDir string) error {
return xerrors.Errorf("unable to get metadata: %w", err)
}
metadata.DownloadedAt = c.clock.Now().UTC()
if err = c.dbc.StoreMetadata(metadata, filepath.Join(cacheDir, "db")); err != nil {
return xerrors.Errorf("failed to store metadata: %w", err)
}
@@ -192,11 +222,13 @@ func (c Client) UpdateMetadata(cacheDir string) error {
return nil
}
// Metadata defines the file meta
type Metadata struct { // TODO: Move all Metadata things to trivy-db repo
fs afero.Fs
filePath string
}
// NewMetadata is the factory method for file Metadata
func NewMetadata(fs afero.Fs, cacheDir string) Metadata {
filePath := MetadataPath(cacheDir)
return Metadata{
@@ -205,13 +237,14 @@ func NewMetadata(fs afero.Fs, cacheDir string) Metadata {
}
}
// MetadataPath returns the metaData file path
func MetadataPath(cacheDir string) string {
dbPath := db.Path(cacheDir)
dbDir := filepath.Dir(dbPath)
return filepath.Join(dbDir, metadataFile)
}
// DeleteMetadata deletes the file of database metadata
// Delete deletes the file of database metadata
func (m Metadata) Delete() error {
if err := m.fs.Remove(m.filePath); err != nil {
return xerrors.Errorf("unable to remove the metadata file: %w", err)
@@ -219,6 +252,7 @@ func (m Metadata) Delete() error {
return nil
}
// Get returns the file metadata
func (m Metadata) Get() (db.Metadata, error) {
f, err := m.fs.Open(m.filePath)
if err != nil {

View File

@@ -133,6 +133,30 @@ func TestClient_NeedsUpdate(t *testing.T) {
skip: true,
expectedError: xerrors.New("--skip-update cannot be specified with the old DB"),
},
{
name: "happy with old DownloadedAt",
light: false,
clock: clocktesting.NewFakeClock(time.Date(2019, 10, 1, 0, 0, 0, 0, time.UTC)),
metadata: db.Metadata{
Version: 1,
Type: db.TypeFull,
NextUpdate: timeNextUpdateDay1,
DownloadedAt: time.Date(2019, 9, 30, 22, 30, 0, 0, time.UTC),
},
expected: true,
},
{
name: "skip downloading DB with recent DownloadedAt",
light: false,
clock: clocktesting.NewFakeClock(time.Date(2019, 10, 1, 0, 0, 0, 0, time.UTC)),
metadata: db.Metadata{
Version: 1,
Type: db.TypeFull,
NextUpdate: timeNextUpdateDay1,
DownloadedAt: time.Date(2019, 9, 30, 23, 30, 0, 0, time.UTC),
},
expected: false,
},
}
if err := log.InitLogger(false, true); err != nil {
@@ -252,14 +276,17 @@ func TestClient_Download(t *testing.T) {
}
func TestClient_UpdateMetadata(t *testing.T) {
timeDownloadedAt := clocktesting.NewFakeClock(time.Date(2019, 10, 1, 0, 0, 0, 0, time.UTC))
testCases := []struct {
name string
clock clock.Clock
getMetadataExpectation dbOperationGetMetadataExpectation
storeMetadataExpectation dbOperationStoreMetadataExpectation
expectedError error
}{
{
name: "happy path",
clock: timeDownloadedAt,
getMetadataExpectation: dbOperationGetMetadataExpectation{
Returns: dbOperationGetMetadataReturns{
Metadata: db.Metadata{
@@ -277,11 +304,13 @@ func TestClient_UpdateMetadata(t *testing.T) {
Type: 1,
NextUpdate: time.Date(2020, 4, 30, 23, 59, 59, 0, time.UTC),
UpdatedAt: time.Date(2006, 4, 30, 23, 59, 59, 0, time.UTC),
DownloadedAt: timeDownloadedAt.Now(),
},
},
},
{
name: "sad path, get metadata fails",
clock: timeDownloadedAt,
getMetadataExpectation: dbOperationGetMetadataExpectation{
Returns: dbOperationGetMetadataReturns{
Err: errors.New("get metadata failed"),
@@ -291,6 +320,7 @@ func TestClient_UpdateMetadata(t *testing.T) {
},
{
name: "sad path, store metadata fails",
clock: timeDownloadedAt,
getMetadataExpectation: dbOperationGetMetadataExpectation{
Returns: dbOperationGetMetadataReturns{
Metadata: db.Metadata{
@@ -308,6 +338,7 @@ func TestClient_UpdateMetadata(t *testing.T) {
Type: 1,
NextUpdate: time.Date(2020, 4, 30, 23, 59, 59, 0, time.UTC),
UpdatedAt: time.Date(2006, 4, 30, 23, 59, 59, 0, time.UTC),
DownloadedAt: timeDownloadedAt.Now(),
},
Returns: dbOperationStoreMetadataReturns{
Err: errors.New("store metadata failed"),
@@ -334,7 +365,7 @@ func TestClient_UpdateMetadata(t *testing.T) {
defer os.RemoveAll(dir)
pb := indicator.NewProgressBar(true)
client := NewClient(mockConfig, nil, pb, nil, metadata)
client := NewClient(mockConfig, nil, pb, tc.clock, metadata)
err = client.UpdateMetadata(dir)
switch {

View File

@@ -4,50 +4,50 @@ import (
"fmt"
"strings"
"github.com/Masterminds/semver/v3"
"golang.org/x/xerrors"
"github.com/aquasecurity/trivy-db/pkg/db"
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
"github.com/aquasecurity/trivy/pkg/scanner/utils"
"github.com/aquasecurity/trivy/pkg/detector/library/comparer"
"github.com/aquasecurity/trivy/pkg/types"
)
// Advisory represents security advisories for each programming language
type Advisory struct {
lang string
comparer comparer
ecosystem string
comparer comparer.Comparer
}
func NewAdvisory(lang string) *Advisory {
// NewAdvisory is the factory method of Advisory
func NewAdvisory(ecosystem string, comparer comparer.Comparer) *Advisory {
return &Advisory{
lang: lang,
comparer: newComparer(lang),
ecosystem: ecosystem,
comparer: comparer,
}
}
// DetectVulnerabilities scans buckets with the prefix according to the programming language in "Advisory".
// If "lang" is python, it looks for buckets with "python::" and gets security advisories from those buckets.
// It allows us to add a new data source with the lang prefix (e.g. python::new-data-source)
// DetectVulnerabilities scans buckets with the prefix according to the ecosystem in "Advisory".
// If "ecosystem" is pip, it looks for buckets with "pip::" and gets security advisories from those buckets.
// It allows us to add a new data source with the ecosystem prefix (e.g. pip::new-data-source)
// and detect vulnerabilities without specifying a specific bucket name.
func (s *Advisory) DetectVulnerabilities(pkgName string, pkgVer *semver.Version) ([]types.DetectedVulnerability, error) {
// e.g. "python::"
prefix := fmt.Sprintf("%s::", s.lang)
func (s *Advisory) DetectVulnerabilities(pkgName, pkgVer string) ([]types.DetectedVulnerability, error) {
// e.g. "pip::", "npm::"
prefix := fmt.Sprintf("%s::", s.ecosystem)
advisories, err := db.Config{}.GetAdvisories(prefix, pkgName)
if err != nil {
return nil, xerrors.Errorf("failed to get %s advisories: %w", s.lang, err)
return nil, xerrors.Errorf("failed to get %s advisories: %w", s.ecosystem, err)
}
var vulns []types.DetectedVulnerability
for _, advisory := range advisories {
if !s.comparer.isVulnerable(pkgVer, advisory) {
if !s.comparer.IsVulnerable(pkgVer, advisory) {
continue
}
vuln := types.DetectedVulnerability{
VulnerabilityID: advisory.VulnerabilityID,
PkgName: pkgName,
InstalledVersion: pkgVer.String(),
InstalledVersion: pkgVer,
FixedVersion: s.createFixedVersions(advisory),
}
vulns = append(vulns, vuln)
@@ -73,29 +73,3 @@ func (s *Advisory) createFixedVersions(advisory dbTypes.Advisory) string {
}
return strings.Join(fixedVersions, ", ")
}
type comparer interface {
isVulnerable(pkgVer *semver.Version, advisory dbTypes.Advisory) bool
}
func newComparer(lang string) comparer {
switch lang {
// When another library is needed for version comparison, it can be added here.
}
return generalComparer{}
}
type generalComparer struct{}
func (c generalComparer) isVulnerable(pkgVer *semver.Version, advisory dbTypes.Advisory) bool {
if len(advisory.VulnerableVersions) != 0 {
return utils.MatchVersions(pkgVer, advisory.VulnerableVersions)
}
if utils.MatchVersions(pkgVer, advisory.PatchedVersions) ||
utils.MatchVersions(pkgVer, advisory.UnaffectedVersions) {
return false
}
return true
}

View File

@@ -4,29 +4,28 @@ import (
"os"
"testing"
"github.com/Masterminds/semver/v3"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/aquasecurity/trivy-db/pkg/db"
"github.com/aquasecurity/trivy-db/pkg/vulnsrc/vulnerability"
"github.com/aquasecurity/trivy/pkg/detector/library"
"github.com/aquasecurity/trivy/pkg/detector/library/bundler"
"github.com/aquasecurity/trivy/pkg/detector/library/comparer"
"github.com/aquasecurity/trivy/pkg/types"
"github.com/aquasecurity/trivy/pkg/utils"
)
func TestAdvisory_DetectVulnerabilities(t *testing.T) {
type fields struct {
lang string
}
type args struct {
pkgName string
pkgVer *semver.Version
pkgVer string
}
tests := []struct {
name string
fixtures []string
fields fields
ecosystem string
comparer comparer.Comparer
args args
want []types.DetectedVulnerability
wantErr string
@@ -34,10 +33,11 @@ func TestAdvisory_DetectVulnerabilities(t *testing.T) {
{
name: "happy path",
fixtures: []string{"testdata/fixtures/php.yaml"},
fields: fields{lang: vulnerability.PHP},
ecosystem: vulnerability.Composer,
comparer: comparer.GenericComparer{},
args: args{
pkgName: "symfony/symfony",
pkgVer: semver.MustParse("4.2.6"),
pkgVer: "4.2.6",
},
want: []types.DetectedVulnerability{
{
@@ -51,10 +51,11 @@ func TestAdvisory_DetectVulnerabilities(t *testing.T) {
{
name: "no patched versions in the advisory",
fixtures: []string{"testdata/fixtures/php.yaml"},
fields: fields{lang: vulnerability.PHP},
ecosystem: vulnerability.Composer,
comparer: comparer.GenericComparer{},
args: args{
pkgName: "symfony/symfony",
pkgVer: semver.MustParse("4.4.6"),
pkgVer: "4.4.6",
},
want: []types.DetectedVulnerability{
{
@@ -68,10 +69,11 @@ func TestAdvisory_DetectVulnerabilities(t *testing.T) {
{
name: "no vulnerable versions in the advisory",
fixtures: []string{"testdata/fixtures/ruby.yaml"},
fields: fields{lang: vulnerability.Ruby},
ecosystem: vulnerability.RubyGems,
comparer: bundler.RubyGemsComparer{},
args: args{
pkgName: "activesupport",
pkgVer: semver.MustParse("4.1.1"),
pkgVer: "4.1.1",
},
want: []types.DetectedVulnerability{
{
@@ -85,10 +87,11 @@ func TestAdvisory_DetectVulnerabilities(t *testing.T) {
{
name: "no vulnerability",
fixtures: []string{"testdata/fixtures/php.yaml"},
fields: fields{lang: vulnerability.PHP},
ecosystem: vulnerability.Composer,
comparer: comparer.GenericComparer{},
args: args{
pkgName: "symfony/symfony",
pkgVer: semver.MustParse("4.4.7"),
pkgVer: "4.4.7",
},
},
}
@@ -99,7 +102,7 @@ func TestAdvisory_DetectVulnerabilities(t *testing.T) {
defer os.RemoveAll(dir)
defer db.Close()
adv := library.NewAdvisory(tt.fields.lang)
adv := library.NewAdvisory(tt.ecosystem, tt.comparer)
got, err := adv.DetectVulnerabilities(tt.args.pkgName, tt.args.pkgVer)
switch {

View File

@@ -3,29 +3,34 @@ package bundler
import (
"strings"
"github.com/Masterminds/semver/v3"
"golang.org/x/xerrors"
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
bundlerSrc "github.com/aquasecurity/trivy-db/pkg/vulnsrc/bundler"
"github.com/aquasecurity/trivy/pkg/scanner/utils"
"github.com/aquasecurity/trivy/pkg/types"
)
// VulnSrc defines the operation on bundler vulnerability
type VulnSrc interface {
Get(pkgName string) ([]bundlerSrc.Advisory, error)
}
// Advisory implements the bundler VulnSrc
type Advisory struct {
comparer RubyGemsComparer
vs VulnSrc
}
// NewAdvisory is the factory method to return bundler.Advisory
func NewAdvisory() *Advisory {
return &Advisory{
vs: bundlerSrc.NewVulnSrc(),
comparer: RubyGemsComparer{},
}
}
func (a *Advisory) DetectVulnerabilities(pkgName string, pkgVer *semver.Version) ([]types.DetectedVulnerability, error) {
// DetectVulnerabilities scans and returns Vulnerability in bundler
func (a *Advisory) DetectVulnerabilities(pkgName, pkgVer string) ([]types.DetectedVulnerability, error) {
advisories, err := a.vs.Get(pkgName)
if err != nil {
return nil, xerrors.Errorf("failed to get bundler advisories: %w", err)
@@ -33,17 +38,18 @@ func (a *Advisory) DetectVulnerabilities(pkgName string, pkgVer *semver.Version)
var vulns []types.DetectedVulnerability
for _, advisory := range advisories {
if utils.MatchVersions(pkgVer, advisory.PatchedVersions) {
continue
adv := dbTypes.Advisory{
UnaffectedVersions: advisory.UnaffectedVersions,
PatchedVersions: advisory.PatchedVersions,
}
if utils.MatchVersions(pkgVer, advisory.UnaffectedVersions) {
if !a.comparer.IsVulnerable(pkgVer, adv) {
continue
}
vuln := types.DetectedVulnerability{
VulnerabilityID: advisory.VulnerabilityID,
PkgName: strings.TrimSpace(pkgName),
InstalledVersion: pkgVer.String(),
InstalledVersion: pkgVer,
FixedVersion: strings.Join(advisory.PatchedVersions, ", "),
}
vulns = append(vulns, vuln)

View File

@@ -1,62 +1,84 @@
package bundler
package bundler_test
import (
"os"
"testing"
"github.com/aquasecurity/trivy/pkg/log"
"github.com/Masterminds/semver/v3"
bundlerSrc "github.com/aquasecurity/trivy-db/pkg/vulnsrc/bundler"
"github.com/aquasecurity/trivy/pkg/detector/library/bundler"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
"github.com/aquasecurity/trivy/pkg/log"
"github.com/aquasecurity/trivy/pkg/types"
"github.com/aquasecurity/trivy/pkg/utils"
)
type MockVulnSrc struct {
mock.Mock
func TestAdvisory_DetectVulnerabilities(t *testing.T) {
type args struct {
pkgName string
pkgVer string
}
tests := []struct {
name string
args args
fixtures []string
want []types.DetectedVulnerability
wantErr string
}{
{
name: "detected",
args: args{
pkgName: "activesupport",
pkgVer: "4.1.1",
},
fixtures: []string{"testdata/fixtures/gem.yaml"},
want: []types.DetectedVulnerability{
{
PkgName: "activesupport",
InstalledVersion: "4.1.1",
VulnerabilityID: "CVE-2015-3226",
FixedVersion: ">= 4.2.2, ~> 4.1.11",
},
},
},
{
name: "not detected",
args: args{
pkgName: "activesupport",
pkgVer: "4.1.0.a",
},
fixtures: []string{"testdata/fixtures/gem.yaml"},
want: nil,
},
{
name: "invalid JSON",
args: args{
pkgName: "activesupport",
pkgVer: "4.1.0",
},
fixtures: []string{"testdata/fixtures/invalid-type.yaml"},
want: nil,
wantErr: "failed to unmarshal advisory JSON",
},
}
func (_m *MockVulnSrc) Get(pkgName string) ([]bundlerSrc.Advisory, error) {
ret := _m.Called(pkgName)
ret0 := ret.Get(0)
if ret0 == nil {
return nil, ret.Error(1)
}
advisories, ok := ret0.([]bundlerSrc.Advisory)
if !ok {
return nil, ret.Error(1)
}
return advisories, ret.Error(1)
}
func TestScanner_Detect(t *testing.T) {
log.InitLogger(false, true)
t.Run("Issue #108", func(t *testing.T) {
// https://github.com/aquasecurity/trivy/issues/108
// Validate that the massaging that happens when parsing the lockfile
// allows us to better handle the platform metadata
mockVulnSrc := new(MockVulnSrc)
mockVulnSrc.On("Get", "ffi").Return(
[]bundlerSrc.Advisory{
{
VulnerabilityID: "NotDetected",
PatchedVersions: []string{">= 1.9.24"},
},
{
VulnerabilityID: "Detected",
PatchedVersions: []string{">= 1.9.26"},
},
}, nil)
s := Advisory{
vs: mockVulnSrc,
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
dir := utils.InitTestDB(t, tt.fixtures)
defer os.RemoveAll(dir)
a := bundler.NewAdvisory()
got, err := a.DetectVulnerabilities(tt.args.pkgName, tt.args.pkgVer)
if tt.wantErr != "" {
require.NotNil(t, err)
assert.Contains(t, err.Error(), tt.wantErr)
return
} else {
assert.NoError(t, err)
}
versionStr := "1.9.25-x64-mingw32"
v, _ := semver.NewVersion(versionStr)
vulns, err := s.DetectVulnerabilities("ffi", v)
assert.Nil(t, err)
assert.Equal(t, 1, len(vulns))
assert.Equal(t, tt.want, got)
})
}
}

View File

@@ -0,0 +1,32 @@
package bundler
import (
"golang.org/x/xerrors"
"github.com/aquasecurity/go-gem-version"
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
"github.com/aquasecurity/trivy/pkg/detector/library/comparer"
)
// RubyGemsComparer represents a comparer for RubyGems
type RubyGemsComparer struct{}
// IsVulnerable checks if the package version is vulnerable to the advisory.
func (r RubyGemsComparer) IsVulnerable(ver string, advisory dbTypes.Advisory) bool {
return comparer.IsVulnerable(ver, advisory, r.matchVersion)
}
// matchVersion checks if the package version satisfies the given constraint.
func (r RubyGemsComparer) matchVersion(currentVersion, constraint string) (bool, error) {
v, err := gem.NewVersion(currentVersion)
if err != nil {
return false, xerrors.Errorf("RubyGems version error (%s): %s", currentVersion, err)
}
c, err := gem.NewConstraints(constraint)
if err != nil {
return false, xerrors.Errorf("RubyGems constraint error (%s): %s", constraint, err)
}
return c.Check(v), nil
}

View File

@@ -0,0 +1,104 @@
package bundler_test
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/aquasecurity/trivy-db/pkg/types"
"github.com/aquasecurity/trivy/pkg/detector/library/bundler"
"github.com/aquasecurity/trivy/pkg/log"
)
func TestRubyGemsComparer_IsVulnerable(t *testing.T) {
type args struct {
currentVersion string
advisory types.Advisory
}
tests := []struct {
name string
args args
want bool
}{
{
name: "happy path",
args: args{
currentVersion: "1.2.3",
advisory: types.Advisory{
PatchedVersions: []string{">=1.2.0"},
},
},
want: false,
},
{
name: "pre-release",
args: args{
currentVersion: "1.2.3.a",
advisory: types.Advisory{
PatchedVersions: []string{">=1.2.3"},
},
},
want: true,
},
{
name: "pre-release without dot",
args: args{
currentVersion: "4.1a",
advisory: types.Advisory{
UnaffectedVersions: []string{"< 4.2b1"},
},
},
want: false,
},
{
// https://github.com/aquasecurity/trivy/issues/108
name: "hyphen",
args: args{
currentVersion: "1.9.25-x86-mingw32",
advisory: types.Advisory{
PatchedVersions: []string{">=1.9.24"},
},
},
want: false,
},
{
// https://github.com/aquasecurity/trivy/issues/108
name: "pessimistic",
args: args{
currentVersion: "1.8.6-java",
advisory: types.Advisory{
PatchedVersions: []string{"~> 1.5.5", "~> 1.6.8", ">= 1.7.7"},
},
},
want: false,
},
{
name: "invalid version",
args: args{
currentVersion: "1.2..4",
advisory: types.Advisory{
PatchedVersions: []string{">=1.2.3"},
},
},
want: false,
},
{
name: "invalid constraint",
args: args{
currentVersion: "1.2.4",
advisory: types.Advisory{
PatchedVersions: []string{"!1.2.0"},
},
},
want: false,
},
}
log.InitLogger(false, false)
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
r := bundler.RubyGemsComparer{}
got := r.IsVulnerable(tt.args.currentVersion, tt.args.advisory)
assert.Equal(t, tt.want, got)
})
}
}

View File

@@ -0,0 +1,11 @@
- bucket: ruby-advisory-db
pairs:
- bucket: activesupport
pairs:
- key: CVE-2015-3226
value:
PatchedVersions:
- ">= 4.2.2"
- "~> 4.1.11"
UnaffectedVersions:
- "< 4.1.0"

View File

@@ -0,0 +1,7 @@
- bucket: ruby-advisory-db
pairs:
- bucket: activesupport
pairs:
- key: CVE-2015-3226
value:
PatchedVersions: dummy

View File

@@ -3,25 +3,30 @@ package cargo
import (
"strings"
"github.com/aquasecurity/trivy/pkg/types"
"github.com/Masterminds/semver/v3"
cargoSrc "github.com/aquasecurity/trivy-db/pkg/vulnsrc/cargo"
"github.com/aquasecurity/trivy/pkg/scanner/utils"
"golang.org/x/xerrors"
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
cargoSrc "github.com/aquasecurity/trivy-db/pkg/vulnsrc/cargo"
"github.com/aquasecurity/trivy/pkg/detector/library/comparer"
"github.com/aquasecurity/trivy/pkg/types"
)
// Advisory encapsulates the cargo vulnerability scanner
type Advisory struct {
vs cargoSrc.VulnSrc
comparer comparer.Comparer
}
// NewAdvisory is the factory method to return cargo Scanner
func NewAdvisory() *Advisory {
return &Advisory{
vs: cargoSrc.NewVulnSrc(),
comparer: comparer.GenericComparer{},
}
}
func (s *Advisory) DetectVulnerabilities(pkgName string, pkgVer *semver.Version) ([]types.DetectedVulnerability, error) {
// DetectVulnerabilities scans and returns the cargo vulnerabilities
func (s *Advisory) DetectVulnerabilities(pkgName, pkgVer string) ([]types.DetectedVulnerability, error) {
advisories, err := s.vs.Get(pkgName)
if err != nil {
return nil, xerrors.Errorf("failed to get cargo advisories: %w", err)
@@ -29,14 +34,23 @@ func (s *Advisory) DetectVulnerabilities(pkgName string, pkgVer *semver.Version)
var vulns []types.DetectedVulnerability
for _, advisory := range advisories {
if utils.MatchVersions(pkgVer, advisory.PatchedVersions) {
adv := dbTypes.Advisory{
UnaffectedVersions: advisory.UnaffectedVersions,
PatchedVersions: advisory.PatchedVersions,
}
if len(adv.UnaffectedVersions) == 0 && len(adv.PatchedVersions) == 0 {
// No patched version
adv.VulnerableVersions = []string{">=0.0.0"}
}
if !s.comparer.IsVulnerable(pkgVer, adv) {
continue
}
vuln := types.DetectedVulnerability{
VulnerabilityID: advisory.VulnerabilityID,
PkgName: strings.TrimSpace(pkgName),
InstalledVersion: pkgVer.String(),
InstalledVersion: pkgVer,
FixedVersion: strings.Join(advisory.PatchedVersions, ", "),
}
vulns = append(vulns, vuln)

View File

@@ -0,0 +1,100 @@
package cargo_test
import (
"os"
"testing"
"github.com/aquasecurity/trivy/pkg/detector/library/cargo"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/aquasecurity/trivy/pkg/log"
"github.com/aquasecurity/trivy/pkg/types"
"github.com/aquasecurity/trivy/pkg/utils"
)
func TestAdvisory_DetectVulnerabilities(t *testing.T) {
type args struct {
pkgName string
pkgVer string
}
tests := []struct {
name string
args args
fixtures []string
want []types.DetectedVulnerability
wantErr string
}{
{
name: "detected",
args: args{
pkgName: "bumpalo",
pkgVer: "3.2.0",
},
fixtures: []string{"testdata/fixtures/cargo.yaml"},
want: []types.DetectedVulnerability{
{
PkgName: "bumpalo",
InstalledVersion: "3.2.0",
VulnerabilityID: "RUSTSEC-2020-0006",
FixedVersion: ">= 3.2.1",
},
},
},
{
name: "not detected",
args: args{
pkgName: "bumpalo",
pkgVer: "3.2.1",
},
fixtures: []string{"testdata/fixtures/cargo.yaml"},
want: nil,
},
{
name: "no patched version",
args: args{
pkgName: "bumpalo",
pkgVer: "3.2.0",
},
fixtures: []string{"testdata/fixtures/no-patched-version.yaml"},
want: []types.DetectedVulnerability{
{
PkgName: "bumpalo",
InstalledVersion: "3.2.0",
VulnerabilityID: "RUSTSEC-2020-0006",
},
},
},
{
name: "invalid JSON",
args: args{
pkgName: "bumpalo",
pkgVer: "3.2.1",
},
fixtures: []string{"testdata/fixtures/invalid-type.yaml"},
want: nil,
wantErr: "failed to unmarshal advisory JSON",
},
}
log.InitLogger(false, true)
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
dir := utils.InitTestDB(t, tt.fixtures)
defer os.RemoveAll(dir)
a := cargo.NewAdvisory()
got, err := a.DetectVulnerabilities(tt.args.pkgName, tt.args.pkgVer)
if tt.wantErr != "" {
require.NotNil(t, err)
assert.Contains(t, err.Error(), tt.wantErr)
return
} else {
assert.NoError(t, err)
}
assert.Equal(t, tt.want, got)
})
}
}

View File

@@ -0,0 +1,10 @@
- bucket: rust-advisory-db
pairs:
- bucket: bumpalo
pairs:
- key: RUSTSEC-2020-0006
value:
PatchedVersions:
- ">= 3.2.1"
UnaffectedVersions:
- "< 3.0.0"

View File

@@ -0,0 +1,7 @@
- bucket: rust-advisory-db
pairs:
- bucket: bumpalo
pairs:
- key: RUSTSEC-2020-0006
value:
PatchedVersions: foo

View File

@@ -0,0 +1,8 @@
- bucket: rust-advisory-db
pairs:
- bucket: bumpalo
pairs:
- key: RUSTSEC-2020-0006
value:
PatchedVersions:
UnaffectedVersions:

View File

@@ -0,0 +1,72 @@
package comparer
import (
"strings"
"golang.org/x/xerrors"
"github.com/aquasecurity/go-version/pkg/version"
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
"github.com/aquasecurity/trivy/pkg/log"
)
// Comparer is an interface for version comparison
type Comparer interface {
IsVulnerable(currentVersion string, advisory dbTypes.Advisory) bool
}
type matchVersion func(currentVersion, constraint string) (bool, error)
// IsVulnerable checks if the package version is vulnerable to the advisory.
func IsVulnerable(pkgVer string, advisory dbTypes.Advisory, match matchVersion) bool {
var matched bool
var err error
if len(advisory.VulnerableVersions) != 0 {
matched, err = match(pkgVer, strings.Join(advisory.VulnerableVersions, " || "))
if err != nil {
log.Logger.Warn(err)
return false
} else if !matched {
// the version is not vulnerable
return false
}
}
secureVersions := append(advisory.PatchedVersions, advisory.UnaffectedVersions...)
if len(secureVersions) == 0 {
// the version matches vulnerable versions and patched/unaffected versions are not provided
// or all values are empty
return matched
}
matched, err = match(pkgVer, strings.Join(secureVersions, " || "))
if err != nil {
log.Logger.Warn(err)
return false
}
return !matched
}
// GenericComparer represents a comparer for semver-like versioning
type GenericComparer struct{}
// IsVulnerable checks if the package version is vulnerable to the advisory.
func (v GenericComparer) IsVulnerable(ver string, advisory dbTypes.Advisory) bool {
return IsVulnerable(ver, advisory, v.matchVersion)
}
// matchVersion checks if the package version satisfies the given constraint.
func (v GenericComparer) matchVersion(currentVersion, constraint string) (bool, error) {
ver, err := version.Parse(currentVersion)
if err != nil {
return false, xerrors.Errorf("version error (%s): %s", currentVersion, err)
}
c, err := version.NewConstraints(constraint)
if err != nil {
return false, xerrors.Errorf("constraint error (%s): %s", currentVersion, err)
}
return c.Check(ver), nil
}

View File

@@ -0,0 +1,96 @@
package comparer_test
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/aquasecurity/trivy-db/pkg/types"
"github.com/aquasecurity/trivy/pkg/detector/library/comparer"
"github.com/aquasecurity/trivy/pkg/log"
)
func TestGenericComparer_IsVulnerable(t *testing.T) {
type args struct {
ver string
advisory types.Advisory
}
tests := []struct {
name string
args args
want bool
}{
{
name: "happy path",
args: args{
ver: "1.2.3",
advisory: types.Advisory{
VulnerableVersions: []string{"<=1.0"},
PatchedVersions: []string{">=1.1"},
},
},
},
{
name: "no patch",
args: args{
ver: "1.2.3",
advisory: types.Advisory{
VulnerableVersions: []string{"<=99.999.99999"},
PatchedVersions: []string{"<0.0.0"},
},
},
want: true,
},
{
name: "pre-release",
args: args{
ver: "1.2.2-alpha",
advisory: types.Advisory{
VulnerableVersions: []string{"<=1.2.2"},
PatchedVersions: []string{">=1.2.2"},
},
},
want: true,
},
{
name: "multiple constraints",
args: args{
ver: "2.0.0",
advisory: types.Advisory{
VulnerableVersions: []string{">=1.7.0 <1.7.16", ">=1.8.0 <1.8.8", ">=2.0.0 <2.0.8", ">=3.0.0-beta.1 <3.0.0-beta.7"},
PatchedVersions: []string{">=3.0.0-beta.7", ">=2.0.8 <3.0.0-beta.1", ">=1.8.8 <2.0.0", ">=1.7.16 <1.8.0"},
},
},
want: true,
},
{
name: "invalid version",
args: args{
ver: "1.2..4",
advisory: types.Advisory{
VulnerableVersions: []string{"<1.0.0"},
},
},
want: false,
},
{
name: "improper constraint",
args: args{
ver: "1.2.3",
advisory: types.Advisory{
VulnerableVersions: []string{"*"},
PatchedVersions: nil,
},
},
want: false,
},
}
log.InitLogger(false, false)
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
v := comparer.GenericComparer{}
got := v.IsVulnerable(tt.args.ver, tt.args.advisory)
assert.Equal(t, tt.want, got)
})
}
}

View File

@@ -4,27 +4,30 @@ import (
"fmt"
"strings"
"github.com/aquasecurity/trivy/pkg/types"
"golang.org/x/xerrors"
"github.com/Masterminds/semver/v3"
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
composerSrc "github.com/aquasecurity/trivy-db/pkg/vulnsrc/composer"
"github.com/aquasecurity/trivy/pkg/scanner/utils"
"github.com/aquasecurity/trivy/pkg/detector/library/comparer"
"github.com/aquasecurity/trivy/pkg/types"
)
// Advisory encapsulates composer.VulnSrc
type Advisory struct {
vs composerSrc.VulnSrc
comparer comparer.Comparer // TODO: implement a comparer for Composer
}
// NewAdvisory is the factory method of Advisory
func NewAdvisory() *Advisory {
return &Advisory{
vs: composerSrc.NewVulnSrc(),
comparer: comparer.GenericComparer{},
}
}
func (s *Advisory) DetectVulnerabilities(pkgName string, pkgVer *semver.Version) ([]types.DetectedVulnerability, error) {
// DetectVulnerabilities returns the vulnerabilities in a package
func (s *Advisory) DetectVulnerabilities(pkgName, pkgVer string) ([]types.DetectedVulnerability, error) {
ref := fmt.Sprintf("composer://%s", pkgName)
advisories, err := s.vs.Get(ref)
if err != nil {
@@ -44,14 +47,15 @@ func (s *Advisory) DetectVulnerabilities(pkgName string, pkgVer *semver.Version)
affectedVersions = append(affectedVersions, strings.Join(branch.Versions, ", "))
}
if !utils.MatchVersions(pkgVer, affectedVersions) {
adv := dbTypes.Advisory{VulnerableVersions: affectedVersions}
if !s.comparer.IsVulnerable(pkgVer, adv) {
continue
}
vuln := types.DetectedVulnerability{
VulnerabilityID: advisory.VulnerabilityID,
PkgName: pkgName,
InstalledVersion: pkgVer.String(),
InstalledVersion: pkgVer,
FixedVersion: strings.Join(patchedVersions, ", "),
}
vulns = append(vulns, vuln)

View File

@@ -0,0 +1,84 @@
package composer_test
import (
"os"
"testing"
"github.com/aquasecurity/trivy/pkg/detector/library/composer"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/aquasecurity/trivy/pkg/log"
"github.com/aquasecurity/trivy/pkg/types"
"github.com/aquasecurity/trivy/pkg/utils"
)
func TestAdvisory_DetectVulnerabilities(t *testing.T) {
type args struct {
pkgName string
pkgVer string
}
tests := []struct {
name string
args args
fixtures []string
want []types.DetectedVulnerability
wantErr string
}{
{
name: "detected",
args: args{
pkgName: "aws/aws-sdk-php",
pkgVer: "3.2.0",
},
fixtures: []string{"testdata/fixtures/composer.yaml"},
want: []types.DetectedVulnerability{
{
PkgName: "aws/aws-sdk-php",
InstalledVersion: "3.2.0",
VulnerabilityID: "CVE-2015-5723",
FixedVersion: "3.2.1",
},
},
},
{
name: "not detected",
args: args{
pkgName: "guzzlehttp/guzzle",
pkgVer: "5.3.1",
},
fixtures: []string{"testdata/fixtures/composer.yaml"},
want: nil,
},
{
name: "malformed JSON",
args: args{
pkgName: "aws/aws-sdk-php",
pkgVer: "3.2.0",
},
fixtures: []string{"testdata/fixtures/invalid-type.yaml"},
wantErr: "failed to unmarshal advisory JSON",
},
}
log.InitLogger(false, true)
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
dir := utils.InitTestDB(t, tt.fixtures)
defer os.RemoveAll(dir)
a := composer.NewAdvisory()
got, err := a.DetectVulnerabilities(tt.args.pkgName, tt.args.pkgVer)
if tt.wantErr != "" {
require.NotNil(t, err)
assert.Contains(t, err.Error(), tt.wantErr)
return
} else {
assert.NoError(t, err)
}
assert.Equal(t, tt.want, got)
})
}
}

View File

@@ -0,0 +1,28 @@
- bucket: php-security-advisories
pairs:
- bucket: "composer://aws/aws-sdk-php"
pairs:
- key: CVE-2015-5723
value:
Branches:
3.x:
Versions:
- ">=3.0.0"
- "<3.2.1"
- bucket: "composer://guzzlehttp/guzzle"
pairs:
- key: CVE-2016-5385
value:
Branches:
4.x:
Versions:
- ">=4.0.0rc2"
- "<4.2.4"
5.3:
Versions:
- ">=5"
- "<5.3.1"
master:
Versions:
- ">=6"
- "<6.2.1"

View File

@@ -0,0 +1,7 @@
- bucket: php-security-advisories
pairs:
- bucket: "composer://aws/aws-sdk-php"
pairs:
- key: CVE-2015-5723
value:
Branches: invalid

View File

@@ -4,19 +4,15 @@ import (
"path/filepath"
"time"
ftypes "github.com/aquasecurity/fanal/types"
"github.com/google/wire"
"github.com/Masterminds/semver/v3"
"github.com/aquasecurity/trivy/pkg/log"
"golang.org/x/xerrors"
"github.com/aquasecurity/trivy/pkg/scanner/utils"
ftypes "github.com/aquasecurity/fanal/types"
"github.com/aquasecurity/trivy/pkg/log"
"github.com/aquasecurity/trivy/pkg/types"
)
// SuperSet binds the dependencies for library scan
var SuperSet = wire.NewSet(
wire.Struct(new(DriverFactory)),
wire.Bind(new(Factory), new(DriverFactory)),
@@ -24,18 +20,22 @@ var SuperSet = wire.NewSet(
wire.Bind(new(Operation), new(Detector)),
)
// Operation defines library scan operations
type Operation interface {
Detect(imageName string, filePath string, created time.Time, pkgs []ftypes.LibraryInfo) (vulns []types.DetectedVulnerability, err error)
}
// Detector implements driverFactory
type Detector struct {
driverFactory Factory
}
// NewDetector is the factory method for detector
func NewDetector(factory Factory) Detector {
return Detector{driverFactory: factory}
}
// Detect scans and returns vulnerabilities of library
func (d Detector) Detect(_, filePath string, _ time.Time, pkgs []ftypes.LibraryInfo) ([]types.DetectedVulnerability, error) {
log.Logger.Debugf("Detecting library vulnerabilities, path: %s", filePath)
driver, err := d.driverFactory.NewDriver(filepath.Base(filePath))
@@ -55,14 +55,7 @@ func detect(driver Driver, libs []ftypes.LibraryInfo) ([]types.DetectedVulnerabi
log.Logger.Infof("Detecting %s vulnerabilities...", driver.Type())
var vulnerabilities []types.DetectedVulnerability
for _, lib := range libs {
v, err := semver.NewVersion(utils.FormatPatchVersion(lib.Library.Version))
if err != nil {
log.Logger.Debugf("invalid version, library: %s, version: %s, error: %s\n",
lib.Library.Name, lib.Library.Version, err)
continue
}
vulns, err := driver.Detect(lib.Library.Name, v)
vulns, err := driver.Detect(lib.Library.Name, lib.Library.Version)
if err != nil {
return nil, xerrors.Errorf("failed to detect %s vulnerabilities: %w", driver.Type(), err)
}

View File

@@ -3,71 +3,77 @@ package library
import (
"fmt"
"github.com/Masterminds/semver/v3"
"golang.org/x/xerrors"
ecosystem "github.com/aquasecurity/trivy-db/pkg/vulnsrc/ghsa"
"github.com/aquasecurity/trivy-db/pkg/vulnsrc/vulnerability"
"github.com/aquasecurity/trivy/pkg/detector/library/bundler"
"github.com/aquasecurity/trivy/pkg/detector/library/cargo"
"github.com/aquasecurity/trivy/pkg/detector/library/comparer"
"github.com/aquasecurity/trivy/pkg/detector/library/composer"
"github.com/aquasecurity/trivy/pkg/detector/library/ghsa"
"github.com/aquasecurity/trivy/pkg/detector/library/node"
"github.com/aquasecurity/trivy/pkg/detector/library/python"
"github.com/aquasecurity/trivy/pkg/types"
"golang.org/x/xerrors"
)
// Factory defines library operations
type Factory interface {
NewDriver(filename string) (Driver, error)
}
type advisory interface {
DetectVulnerabilities(string, *semver.Version) ([]types.DetectedVulnerability, error)
DetectVulnerabilities(string, string) ([]types.DetectedVulnerability, error)
}
// DriverFactory implements Factory
type DriverFactory struct{}
// NewDriver factory method for driver
func (d DriverFactory) NewDriver(filename string) (Driver, error) {
// TODO: use DI
var driver Driver
switch filename {
case "Gemfile.lock":
driver = newRubyDriver()
driver = newRubyGemsDriver()
case "Cargo.lock":
driver = newRustDriver()
driver = newCargoDriver()
case "composer.lock":
driver = newPHPDriver()
driver = newComposerDriver()
case "package-lock.json", "yarn.lock":
driver = newNodejsDriver()
driver = newNpmDriver()
case "Pipfile.lock", "poetry.lock":
driver = newPythonDriver()
driver = newPipDriver()
default:
return Driver{}, xerrors.New(fmt.Sprintf("unsupport filename %s", filename))
}
return driver, nil
}
// Driver implements the advisory
type Driver struct {
lang string
ecosystem string
advisories []advisory
}
func NewDriver(lang string, advisories ...advisory) Driver {
return Driver{lang: lang, advisories: advisories}
// NewDriver is the factory method from drier
func NewDriver(advisories ...advisory) Driver {
return Driver{advisories: advisories}
}
func (d *Driver) Detect(pkgName string, pkgVer *semver.Version) ([]types.DetectedVulnerability, error) {
// Detect scans and returns vulnerabilities
func (d *Driver) Detect(pkgName string, pkgVer string) ([]types.DetectedVulnerability, error) {
var detectedVulnerabilities []types.DetectedVulnerability
uniqVulnIdMap := make(map[string]struct{})
for _, d := range append(d.advisories, NewAdvisory(d.lang)) {
uniqVulnIDMap := make(map[string]struct{})
for _, d := range d.advisories {
vulns, err := d.DetectVulnerabilities(pkgName, pkgVer)
if err != nil {
return nil, xerrors.Errorf("failed to detect vulnerabilities: %w", err)
}
for _, vuln := range vulns {
if _, ok := uniqVulnIdMap[vuln.VulnerabilityID]; ok {
if _, ok := uniqVulnIDMap[vuln.VulnerabilityID]; ok {
continue
}
uniqVulnIdMap[vuln.VulnerabilityID] = struct{}{}
uniqVulnIDMap[vuln.VulnerabilityID] = struct{}{}
detectedVulnerabilities = append(detectedVulnerabilities, vuln)
}
}
@@ -75,26 +81,36 @@ func (d *Driver) Detect(pkgName string, pkgVer *semver.Version) ([]types.Detecte
return detectedVulnerabilities, nil
}
// Type returns the driver ecosystem
func (d *Driver) Type() string {
return d.lang
return d.ecosystem
}
func newRubyDriver() Driver {
return NewDriver(vulnerability.Ruby, ghsa.NewAdvisory(ecosystem.Rubygems), bundler.NewAdvisory())
func newRubyGemsDriver() Driver {
c := bundler.RubyGemsComparer{}
return NewDriver(ghsa.NewAdvisory(ecosystem.Rubygems, c), bundler.NewAdvisory(),
NewAdvisory(vulnerability.RubyGems, c))
}
func newPHPDriver() Driver {
return NewDriver(vulnerability.PHP, ghsa.NewAdvisory(ecosystem.Composer), composer.NewAdvisory())
func newComposerDriver() Driver {
c := comparer.GenericComparer{}
return NewDriver(
ghsa.NewAdvisory(ecosystem.Composer, c), composer.NewAdvisory(),
NewAdvisory(vulnerability.Composer, c))
}
func newRustDriver() Driver {
return NewDriver(vulnerability.Rust, cargo.NewAdvisory())
func newCargoDriver() Driver {
return NewDriver(cargo.NewAdvisory(), NewAdvisory(vulnerability.Cargo, comparer.GenericComparer{}))
}
func newNodejsDriver() Driver {
return NewDriver(vulnerability.Nodejs, ghsa.NewAdvisory(ecosystem.Npm), node.NewAdvisory())
func newNpmDriver() Driver {
c := node.NpmComparer{}
return NewDriver(ghsa.NewAdvisory(ecosystem.Npm, c), node.NewAdvisory(),
NewAdvisory(vulnerability.Npm, c))
}
func newPythonDriver() Driver {
return NewDriver(vulnerability.Python, ghsa.NewAdvisory(ecosystem.Pip), python.NewAdvisory())
func newPipDriver() Driver {
c := comparer.GenericComparer{}
return NewDriver(ghsa.NewAdvisory(ecosystem.Pip, c), python.NewAdvisory(),
NewAdvisory(vulnerability.Pip, c))
}

View File

@@ -4,7 +4,6 @@ import (
"os"
"testing"
"github.com/Masterminds/semver/v3"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@@ -20,7 +19,7 @@ func TestDriver_Detect(t *testing.T) {
}
type args struct {
pkgName string
pkgVer *semver.Version
pkgVer string
}
tests := []struct {
name string
@@ -36,7 +35,7 @@ func TestDriver_Detect(t *testing.T) {
fields: fields{fileName: "composer.lock"},
args: args{
pkgName: "symfony/symfony",
pkgVer: semver.MustParse("4.2.6"),
pkgVer: "4.2.6",
},
want: []types.DetectedVulnerability{
{
@@ -53,7 +52,7 @@ func TestDriver_Detect(t *testing.T) {
fields: fields{fileName: "composer.lock"},
args: args{
pkgName: "symfony/symfony",
pkgVer: semver.MustParse("4.2.6"),
pkgVer: "4.2.6",
},
want: []types.DetectedVulnerability{
{
@@ -70,7 +69,7 @@ func TestDriver_Detect(t *testing.T) {
fields: fields{fileName: "composer.lock"},
args: args{
pkgName: "symfony/symfony",
pkgVer: semver.MustParse("4.4.6"),
pkgVer: "4.4.6",
},
want: []types.DetectedVulnerability{
{
@@ -87,7 +86,7 @@ func TestDriver_Detect(t *testing.T) {
fields: fields{fileName: "Gemfile.lock"},
args: args{
pkgName: "activesupport",
pkgVer: semver.MustParse("4.1.1"),
pkgVer: "4.1.1",
},
want: []types.DetectedVulnerability{
{
@@ -104,7 +103,7 @@ func TestDriver_Detect(t *testing.T) {
fields: fields{fileName: "composer.lock"},
args: args{
pkgName: "symfony/symfony",
pkgVer: semver.MustParse("4.4.7"),
pkgVer: "4.4.7",
},
},
}

View File

@@ -3,29 +3,35 @@ package ghsa
import (
"strings"
"github.com/Masterminds/semver/v3"
"golang.org/x/xerrors"
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
"github.com/aquasecurity/trivy-db/pkg/vulnsrc/ghsa"
"github.com/aquasecurity/trivy/pkg/scanner/utils"
"github.com/aquasecurity/trivy/pkg/detector/library/comparer"
"github.com/aquasecurity/trivy/pkg/types"
)
// VulnSrc defines the operations on vulnerability source
type VulnSrc interface {
Get(pkgName string) ([]ghsa.Advisory, error)
}
// Advisory implements VulnSrc
type Advisory struct {
vs VulnSrc
comparer comparer.Comparer
}
func NewAdvisory(ecosystem ghsa.Ecosystem) *Advisory {
// NewAdvisory is the factory method to return advisory
func NewAdvisory(ecosystem ghsa.Ecosystem, comparer comparer.Comparer) *Advisory {
return &Advisory{
vs: ghsa.NewVulnSrc(ecosystem),
comparer: comparer,
}
}
func (s *Advisory) DetectVulnerabilities(pkgName string, pkgVer *semver.Version) ([]types.DetectedVulnerability, error) {
// DetectVulnerabilities scans package for vulnerabilities
func (s *Advisory) DetectVulnerabilities(pkgName, pkgVer string) ([]types.DetectedVulnerability, error) {
advisories, err := s.vs.Get(pkgName)
if err != nil {
return nil, xerrors.Errorf("failed to get ghsa advisories: %w", err)
@@ -33,14 +39,15 @@ func (s *Advisory) DetectVulnerabilities(pkgName string, pkgVer *semver.Version)
var vulns []types.DetectedVulnerability
for _, advisory := range advisories {
if !utils.MatchVersions(pkgVer, advisory.VulnerableVersions) {
adv := dbTypes.Advisory{VulnerableVersions: advisory.VulnerableVersions}
if !s.comparer.IsVulnerable(pkgVer, adv) {
continue
}
vuln := types.DetectedVulnerability{
VulnerabilityID: advisory.VulnerabilityID,
PkgName: pkgName,
InstalledVersion: pkgVer.String(),
InstalledVersion: pkgVer,
FixedVersion: strings.Join(advisory.PatchedVersions, ", "),
}
vulns = append(vulns, vuln)

View File

@@ -0,0 +1,102 @@
package ghsa_test
import (
"os"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
ghsaSrc "github.com/aquasecurity/trivy-db/pkg/vulnsrc/ghsa"
"github.com/aquasecurity/trivy/pkg/detector/library/comparer"
"github.com/aquasecurity/trivy/pkg/detector/library/ghsa"
"github.com/aquasecurity/trivy/pkg/log"
"github.com/aquasecurity/trivy/pkg/types"
"github.com/aquasecurity/trivy/pkg/utils"
)
func TestAdvisory_DetectVulnerabilities(t *testing.T) {
type fields struct {
ecosystem ghsaSrc.Ecosystem
comparer comparer.Comparer
}
type args struct {
pkgName string
pkgVer string
}
tests := []struct {
name string
args args
fields fields
fixtures []string
want []types.DetectedVulnerability
wantErr string
}{
{
name: "detected",
fields: fields{
ecosystem: ghsaSrc.Composer,
comparer: comparer.GenericComparer{},
},
args: args{
pkgName: "symfony/symfony",
pkgVer: "5.1.5-alpha",
},
fixtures: []string{"testdata/fixtures/ghsa.yaml"},
want: []types.DetectedVulnerability{
{
PkgName: "symfony/symfony",
InstalledVersion: "5.1.5-alpha",
VulnerabilityID: "CVE-2020-15094",
FixedVersion: "5.1.5, 4.4.13",
},
},
},
{
name: "not detected",
fields: fields{
ecosystem: ghsaSrc.Composer,
comparer: comparer.GenericComparer{},
},
args: args{
pkgName: "symfony/symfony",
pkgVer: "5.1.5",
},
fixtures: []string{"testdata/fixtures/ghsa.yaml"},
want: nil,
},
{
name: "malformed JSON",
fields: fields{
ecosystem: ghsaSrc.Composer,
comparer: comparer.GenericComparer{},
},
args: args{
pkgName: "symfony/symfony",
pkgVer: "5.1.5",
},
fixtures: []string{"testdata/fixtures/invalid-type.yaml"},
wantErr: "failed to unmarshal advisory JSON",
},
}
log.InitLogger(false, true)
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
dir := utils.InitTestDB(t, tt.fixtures)
defer os.RemoveAll(dir)
a := ghsa.NewAdvisory(tt.fields.ecosystem, tt.fields.comparer)
got, err := a.DetectVulnerabilities(tt.args.pkgName, tt.args.pkgVer)
if tt.wantErr != "" {
require.NotNil(t, err)
assert.Contains(t, err.Error(), tt.wantErr)
return
} else {
assert.NoError(t, err)
}
assert.Equal(t, tt.want, got)
})
}
}

View File

@@ -0,0 +1,12 @@
- bucket: GitHub Security Advisory Composer
pairs:
- bucket: "symfony/symfony"
pairs:
- key: CVE-2020-15094
value:
PatchedVersions:
- 5.1.5
- 4.4.13
VulnerableVersions:
- ">= 5.0.0, < 5.1.5"
- ">= 4.4.0, < 4.4.13"

View File

@@ -0,0 +1,7 @@
- bucket: GitHub Security Advisory Composer
pairs:
- bucket: "symfony/symfony"
pairs:
- key: CVE-2020-15094
value:
PatchedVersions: malformed

View File

@@ -5,61 +5,69 @@ import (
"golang.org/x/xerrors"
"github.com/Masterminds/semver/v3"
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
"github.com/aquasecurity/trivy-db/pkg/vulnsrc/node"
"github.com/aquasecurity/trivy/pkg/scanner/utils"
"github.com/aquasecurity/trivy/pkg/types"
)
// Advisory encapsulate Node vulnerability source
type Advisory struct {
comparer NpmComparer
vs node.VulnSrc
}
// NewAdvisory is the factory method for Node Advisory
func NewAdvisory() *Advisory {
return &Advisory{
vs: node.NewVulnSrc(),
comparer: NpmComparer{},
}
}
func (s *Advisory) DetectVulnerabilities(pkgName string, pkgVer *semver.Version) ([]types.DetectedVulnerability, error) {
replacer := strings.NewReplacer(".alpha", "-alpha", ".beta", "-beta", ".rc", "-rc", " <", ", <", " >", ", >")
advisories, err := s.vs.Get(pkgName)
// DetectVulnerabilities scans and return vulnerability using Node package scanner
func (a *Advisory) DetectVulnerabilities(pkgName, pkgVer string) ([]types.DetectedVulnerability, error) {
advisories, err := a.vs.Get(pkgName)
if err != nil {
return nil, xerrors.Errorf("failed to get node advisories: %w", err)
}
var vulns []types.DetectedVulnerability
for _, advisory := range advisories {
// e.g. <= 2.15.0 || >= 3.0.0 <= 3.8.2
// => {"<=2.15.0", ">= 3.0.0, <= 3.8.2"}
var vulnerableVersions []string
for _, version := range strings.Split(advisory.VulnerableVersions, " || ") {
version = strings.TrimSpace(version)
vulnerableVersions = append(vulnerableVersions, replacer.Replace(version))
}
if !utils.MatchVersions(pkgVer, vulnerableVersions) {
continue
}
var patchedVersions []string
for _, version := range strings.Split(advisory.PatchedVersions, " || ") {
version = strings.TrimSpace(version)
patchedVersions = append(patchedVersions, replacer.Replace(version))
}
if utils.MatchVersions(pkgVer, patchedVersions) {
adv := convertToGenericAdvisory(advisory)
if !a.comparer.IsVulnerable(pkgVer, adv) {
continue
}
vuln := types.DetectedVulnerability{
VulnerabilityID: advisory.VulnerabilityID,
PkgName: pkgName,
InstalledVersion: pkgVer.String(),
FixedVersion: strings.Join(patchedVersions, ", "),
InstalledVersion: pkgVer,
FixedVersion: createFixedVersions(advisory.PatchedVersions),
}
vulns = append(vulns, vuln)
}
return vulns, nil
}
func convertToGenericAdvisory(advisory node.Advisory) dbTypes.Advisory {
var vulnerable, patched []string
if advisory.VulnerableVersions != "" {
vulnerable = strings.Split(advisory.VulnerableVersions, "||")
}
if advisory.PatchedVersions != "" {
patched = strings.Split(advisory.PatchedVersions, "||")
}
return dbTypes.Advisory{
VulnerableVersions: vulnerable,
PatchedVersions: patched,
}
}
func createFixedVersions(patchedVersions string) string {
var fixedVersions []string
for _, s := range strings.Split(patchedVersions, "||") {
fixedVersions = append(fixedVersions, strings.TrimSpace(s))
}
return strings.Join(fixedVersions, ", ")
}

View File

@@ -0,0 +1,91 @@
package node_test
import (
"os"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/aquasecurity/trivy/pkg/detector/library/node"
"github.com/aquasecurity/trivy/pkg/log"
"github.com/aquasecurity/trivy/pkg/types"
"github.com/aquasecurity/trivy/pkg/utils"
)
func TestAdvisory_DetectVulnerabilities(t *testing.T) {
type args struct {
pkgName string
pkgVer string
}
tests := []struct {
name string
args args
fixtures []string
want []types.DetectedVulnerability
wantErr string
}{
{
name: "detected",
args: args{
pkgName: "electron",
pkgVer: "2.0.17",
},
fixtures: []string{"testdata/fixtures/npm.yaml"},
want: []types.DetectedVulnerability{
{
PkgName: "electron",
InstalledVersion: "2.0.17",
VulnerabilityID: "CVE-2019-5786",
FixedVersion: "^2.0.18, ^3.0.16, ^3.1.6, ^4.0.8, ^5.0.0-beta.5",
},
},
},
{
name: "not detected",
args: args{
pkgName: "electron",
pkgVer: "2.0.18",
},
fixtures: []string{"testdata/fixtures/npm.yaml"},
want: nil,
},
{
name: "empty value",
args: args{
pkgName: "electron",
pkgVer: "2.0.18",
},
fixtures: []string{"testdata/fixtures/no-value.yaml"},
want: nil,
},
{name: "malformed JSON",
args: args{
pkgName: "electron",
pkgVer: "2.0.18",
},
fixtures: []string{"testdata/fixtures/invalid-type.yaml"},
wantErr: "failed to unmarshal advisory JSON",
},
}
log.InitLogger(false, true)
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
dir := utils.InitTestDB(t, tt.fixtures)
defer os.RemoveAll(dir)
a := node.NewAdvisory()
got, err := a.DetectVulnerabilities(tt.args.pkgName, tt.args.pkgVer)
if tt.wantErr != "" {
require.NotNil(t, err)
assert.Contains(t, err.Error(), tt.wantErr)
return
} else {
assert.NoError(t, err)
}
assert.Equal(t, tt.want, got)
})
}
}

View File

@@ -0,0 +1,32 @@
package node
import (
"golang.org/x/xerrors"
npm "github.com/aquasecurity/go-npm-version/pkg"
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
"github.com/aquasecurity/trivy/pkg/detector/library/comparer"
)
// NpmComparer represents a comparer for npm
type NpmComparer struct{}
// IsVulnerable checks if the package version is vulnerable to the advisory.
func (n NpmComparer) IsVulnerable(ver string, advisory dbTypes.Advisory) bool {
return comparer.IsVulnerable(ver, advisory, n.matchVersion)
}
// matchVersion checks if the package version satisfies the given constraint.
func (n NpmComparer) matchVersion(currentVersion, constraint string) (bool, error) {
v, err := npm.NewVersion(currentVersion)
if err != nil {
return false, xerrors.Errorf("npm version error (%s): %s", currentVersion, err)
}
c, err := npm.NewConstraints(constraint)
if err != nil {
return false, xerrors.Errorf("npm constraint error (%s): %s", constraint, err)
}
return c.Check(v), nil
}

View File

@@ -0,0 +1,140 @@
package node_test
import (
"testing"
"github.com/stretchr/testify/assert"
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
"github.com/aquasecurity/trivy/pkg/detector/library/node"
"github.com/aquasecurity/trivy/pkg/log"
)
func TestNpmComparer_MatchVersion(t *testing.T) {
type args struct {
currentVersion string
advisory dbTypes.Advisory
}
tests := []struct {
name string
args args
want bool
}{
{
name: "happy path",
args: args{
currentVersion: "1.0.0",
advisory: dbTypes.Advisory{
VulnerableVersions: []string{"<=1.0"},
PatchedVersions: []string{">=1.1"},
},
},
want: true,
},
{
name: "no patch",
args: args{
currentVersion: "1.2.3",
advisory: dbTypes.Advisory{
VulnerableVersions: []string{"<=99.999.99999"},
PatchedVersions: []string{"<0.0.0"},
},
},
want: true,
},
{
name: "no patch with wildcard",
args: args{
currentVersion: "1.2.3",
advisory: dbTypes.Advisory{
VulnerableVersions: []string{"*"},
PatchedVersions: nil,
},
},
want: true,
},
{
name: "pre-release",
args: args{
currentVersion: "1.2.3-alpha",
advisory: dbTypes.Advisory{
VulnerableVersions: []string{"<=1.2.2"},
PatchedVersions: []string{">=1.2.2"},
},
},
want: false,
},
{
name: "multiple constraints",
args: args{
currentVersion: "2.0.0",
advisory: dbTypes.Advisory{
VulnerableVersions: []string{">=1.7.0 <1.7.16", ">=1.8.0 <1.8.8", ">=2.0.0 <2.0.8", ">=3.0.0-beta.1 <3.0.0-beta.7"},
PatchedVersions: []string{">=3.0.0-beta.7", ">=2.0.8 <3.0.0-beta.1", ">=1.8.8 <2.0.0", ">=1.7.16 <1.8.0"},
},
},
want: true,
},
{
name: "x",
args: args{
currentVersion: "2.0.1",
advisory: dbTypes.Advisory{
VulnerableVersions: []string{"2.0.x", "2.1.x"},
PatchedVersions: []string{">=2.2.x"},
},
},
want: true,
},
{
name: "exact versions",
args: args{
currentVersion: "2.1.0-M1",
advisory: dbTypes.Advisory{
VulnerableVersions: []string{"2.1.0-M1", "2.1.0-M2"},
PatchedVersions: []string{">=2.1.0"},
},
},
want: true,
},
{
name: "caret",
args: args{
currentVersion: "2.0.18",
advisory: dbTypes.Advisory{
VulnerableVersions: []string{"<2.0.18", "<3.0.16"},
PatchedVersions: []string{"^2.0.18", "^3.0.16"},
},
},
want: false,
},
{
name: "invalid version",
args: args{
currentVersion: "1.2..4",
advisory: dbTypes.Advisory{
VulnerableVersions: []string{"<1.0.0"},
},
},
want: false,
},
{
name: "invalid constraint",
args: args{
currentVersion: "1.2.4",
advisory: dbTypes.Advisory{
VulnerableVersions: []string{"!1.0.0"},
},
},
want: false,
},
}
log.InitLogger(false, false)
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
c := node.NpmComparer{}
got := c.IsVulnerable(tt.args.currentVersion, tt.args.advisory)
assert.Equal(t, tt.want, got)
})
}
}

View File

@@ -0,0 +1,9 @@
- bucket: nodejs-security-wg
pairs:
- bucket: electron
pairs:
- key: CVE-2019-5786
value:
PatchedVersions:
- 1
- 2

View File

@@ -0,0 +1,6 @@
- bucket: nodejs-security-wg
pairs:
- bucket: electron
pairs:
- key: CVE-2019-5786
value:

View File

@@ -0,0 +1,8 @@
- bucket: nodejs-security-wg
pairs:
- bucket: electron
pairs:
- key: CVE-2019-5786
value:
PatchedVersions: "^2.0.18 || ^3.0.16 || ^3.1.6 || ^4.0.8 || ^5.0.0-beta.5"
VulnerableVersions: "<2.0.18 || <3.0.16 || <3.1.6 || <4.0.8 || <5.0.0-beta.5"

View File

@@ -3,26 +3,30 @@ package python
import (
"strings"
"github.com/aquasecurity/trivy-db/pkg/vulnsrc/python"
"github.com/aquasecurity/trivy/pkg/types"
"golang.org/x/xerrors"
"github.com/Masterminds/semver/v3"
"github.com/aquasecurity/trivy/pkg/scanner/utils"
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
"github.com/aquasecurity/trivy-db/pkg/vulnsrc/python"
"github.com/aquasecurity/trivy/pkg/detector/library/comparer"
"github.com/aquasecurity/trivy/pkg/types"
)
// Advisory encapsulates the python vulnerability scanner
type Advisory struct {
vs python.VulnSrc
comparer comparer.Comparer
}
// NewAdvisory is the factory method to return Python Advisory
func NewAdvisory() *Advisory {
return &Advisory{
vs: python.NewVulnSrc(),
comparer: comparer.GenericComparer{},
}
}
func (s *Advisory) DetectVulnerabilities(pkgName string, pkgVer *semver.Version) ([]types.DetectedVulnerability, error) {
// DetectVulnerabilities scans and returns python vulnerabilities
func (s *Advisory) DetectVulnerabilities(pkgName, pkgVer string) ([]types.DetectedVulnerability, error) {
advisories, err := s.vs.Get(pkgName)
if err != nil {
return nil, xerrors.Errorf("failed to get python advisories: %w", err)
@@ -30,14 +34,15 @@ func (s *Advisory) DetectVulnerabilities(pkgName string, pkgVer *semver.Version)
var vulns []types.DetectedVulnerability
for _, advisory := range advisories {
if !utils.MatchVersions(pkgVer, advisory.Specs) {
adv := dbTypes.Advisory{VulnerableVersions: advisory.Specs}
if !s.comparer.IsVulnerable(pkgVer, adv) {
continue
}
vuln := types.DetectedVulnerability{
VulnerabilityID: advisory.VulnerabilityID,
PkgName: pkgName,
InstalledVersion: pkgVer.String(),
InstalledVersion: pkgVer,
FixedVersion: createFixedVersions(advisory.Specs),
}
vulns = append(vulns, vuln)

View File

@@ -0,0 +1,84 @@
package python_test
import (
"os"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/aquasecurity/trivy/pkg/detector/library/python"
"github.com/aquasecurity/trivy/pkg/log"
"github.com/aquasecurity/trivy/pkg/types"
"github.com/aquasecurity/trivy/pkg/utils"
)
func TestAdvisory_DetectVulnerabilities(t *testing.T) {
type args struct {
pkgName string
pkgVer string
}
tests := []struct {
name string
args args
fixtures []string
want []types.DetectedVulnerability
wantErr string
}{
{
name: "detected",
args: args{
pkgName: "django",
pkgVer: "2.2.11-alpha",
},
fixtures: []string{"testdata/fixtures/pip.yaml"},
want: []types.DetectedVulnerability{
{
PkgName: "django",
InstalledVersion: "2.2.11-alpha",
VulnerabilityID: "CVE-2020-9402",
FixedVersion: "1.11.29, 2.2.11, 3.0.4",
},
},
},
{
// https://github.com/aquasecurity/trivy/issues/713
name: "not detected",
args: args{
pkgName: "django",
pkgVer: "3.0.10",
},
fixtures: []string{"testdata/fixtures/pip.yaml"},
want: nil,
},
{
name: "malformed JSON",
args: args{
pkgName: "django",
pkgVer: "2.0.18",
},
fixtures: []string{"testdata/fixtures/invalid-type.yaml"},
wantErr: "failed to unmarshal advisory JSON",
},
}
log.InitLogger(false, true)
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
dir := utils.InitTestDB(t, tt.fixtures)
defer os.RemoveAll(dir)
a := python.NewAdvisory()
got, err := a.DetectVulnerabilities(tt.args.pkgName, tt.args.pkgVer)
if tt.wantErr != "" {
require.NotNil(t, err)
assert.Contains(t, err.Error(), tt.wantErr)
return
} else {
assert.NoError(t, err)
}
assert.Equal(t, tt.want, got)
})
}
}

View File

@@ -0,0 +1,7 @@
- bucket: python-safety-db
pairs:
- bucket: django
pairs:
- key: CVE-2020-9402
value:
Specs: foo

View File

@@ -0,0 +1,14 @@
- bucket: python-safety-db
pairs:
- bucket: django
pairs:
- key: CVE-2019-19844
value:
Specs:
- "==3.0"
- key: CVE-2020-9402
value:
Specs:
- ">=1.11.0,<1.11.29"
- ">=2.2.0,<2.2.11"
- ">=3.0.0,<3.0.4"

View File

@@ -1,4 +1,4 @@
- bucket: "php::GitHub Security Advisory Composer"
- bucket: "composer::GitHub Security Advisory Composer"
pairs:
- bucket: symfony/symfony
pairs:
@@ -8,7 +8,7 @@
- 4.2.7
VulnerableVersions:
- ">= 4.2.0, < 4.2.7"
- bucket: "php::php-security-advisories"
- bucket: "composer::php-security-advisories"
pairs:
- bucket: symfony/symfony
pairs:

View File

@@ -1,4 +1,4 @@
- bucket: "ruby::ruby-advisory-db"
- bucket: "rubygems::ruby-advisory-db"
pairs:
- bucket: activesupport
pairs:

View File

@@ -41,16 +41,19 @@ var (
}
)
// Scanner implements the Alpine scanner
type Scanner struct {
vs dbTypes.VulnSrc
}
// NewScanner is the factory method for Scanner
func NewScanner() *Scanner {
return &Scanner{
vs: alpine.NewVulnSrc(),
}
}
// Detect vulnerabilities in package using Alpine scanner
func (s *Scanner) Detect(osVer string, pkgs []ftypes.Package) ([]types.DetectedVulnerability, error) {
log.Logger.Info("Detecting Alpine vulnerabilities...")
if strings.Count(osVer, ".") > 1 {
@@ -94,6 +97,7 @@ func (s *Scanner) Detect(osVer string, pkgs []ftypes.Package) ([]types.DetectedV
return vulns, nil
}
// IsSupportedVersion checks the OSFamily can be scanned using Alpine scanner
func (s *Scanner) IsSupportedVersion(osFamily, osVer string) bool {
now := time.Now()
return s.isSupportedVersion(now, osFamily, osVer)

View File

@@ -15,11 +15,13 @@ import (
"github.com/aquasecurity/trivy/pkg/types"
)
// Scanner to scan amazon vulnerabilities
type Scanner struct {
l *zap.SugaredLogger
ac dbTypes.VulnSrc
}
// NewScanner is the factory method to return Amazon scanner
func NewScanner() *Scanner {
return &Scanner{
l: log.Logger,
@@ -27,6 +29,7 @@ func NewScanner() *Scanner {
}
}
// Detect scans the packages using amazon scanner
func (s *Scanner) Detect(osVer string, pkgs []ftypes.Package) ([]types.DetectedVulnerability, error) {
log.Logger.Info("Detecting Amazon Linux vulnerabilities...")
@@ -77,6 +80,7 @@ func (s *Scanner) Detect(osVer string, pkgs []ftypes.Package) ([]types.DetectedV
return vulns, nil
}
// IsSupportedVersion checks if os can be scanned using amazon scanner
func (s *Scanner) IsSupportedVersion(osFamily, osVer string) bool {
return true
}

View File

@@ -40,11 +40,13 @@ var (
}
)
// Scanner implements the Debian scanner
type Scanner struct {
ovalVs dbTypes.VulnSrc
vs dbTypes.VulnSrc
}
// NewScanner is the factory method to return Scanner
func NewScanner() *Scanner {
return &Scanner{
ovalVs: debianoval.NewVulnSrc(),
@@ -52,6 +54,7 @@ func NewScanner() *Scanner {
}
}
// Detect scans and return vulnerabilities using Debian scanner
func (s *Scanner) Detect(osVer string, pkgs []ftypes.Package) ([]types.DetectedVulnerability, error) {
log.Logger.Info("Detecting Debian vulnerabilities...")
@@ -78,7 +81,8 @@ func (s *Scanner) Detect(osVer string, pkgs []ftypes.Package) ([]types.DetectedV
}
for _, adv := range advisories {
fixedVersion, err := version.NewVersion(adv.FixedVersion)
var fixedVersion version.Version
fixedVersion, err = version.NewVersion(adv.FixedVersion)
if err != nil {
log.Logger.Debugf("failed to parse Debian package version: %w", err)
continue
@@ -115,6 +119,7 @@ func (s *Scanner) Detect(osVer string, pkgs []ftypes.Package) ([]types.DetectedV
return vulns, nil
}
// IsSupportedVersion checks is OSFamily can be scanned using Debian
func (s *Scanner) IsSupportedVersion(osFamily, osVer string) bool {
now := time.Now()
return s.isSupportedVersion(now, osFamily, osVer)

View File

@@ -21,25 +21,31 @@ import (
)
var (
// ErrUnsupportedOS defines error for unsupported OS
ErrUnsupportedOS = xerrors.New("unsupported os")
// SuperSet binds dependencies for OS scan
SuperSet = wire.NewSet(
wire.Struct(new(Detector)),
wire.Bind(new(Operation), new(Detector)),
)
)
// Operation defines operation of OSpkg scan
type Operation interface {
Detect(string, string, string, time.Time, []ftypes.Package) ([]types.DetectedVulnerability, bool, error)
}
// Driver defines operations for OS package scan
type Driver interface {
Detect(string, []ftypes.Package) ([]types.DetectedVulnerability, error)
IsSupportedVersion(string, string) bool
}
// Detector implements Operation
type Detector struct{}
// Detect detects the vulnerabilities
func (d Detector) Detect(_, osFamily, osName string, _ time.Time, pkgs []ftypes.Package) ([]types.DetectedVulnerability, bool, error) {
driver := newDriver(osFamily, osName)
if driver == nil {
@@ -56,31 +62,31 @@ func (d Detector) Detect(_, osFamily, osName string, _ time.Time, pkgs []ftypes.
return vulns, eosl, nil
}
// nolint: gocyclo
// TODO: fix cyclometic complexity by removing default
func newDriver(osFamily, osName string) Driver {
// TODO: use DI and change struct names
var d Driver
switch osFamily {
case fos.Alpine:
d = alpine.NewScanner()
return alpine.NewScanner()
case fos.Debian:
d = debian.NewScanner()
return debian.NewScanner()
case fos.Ubuntu:
d = ubuntu.NewScanner()
return ubuntu.NewScanner()
case fos.RedHat, fos.CentOS:
d = redhat.NewScanner()
return redhat.NewScanner()
case fos.Amazon:
d = amazon.NewScanner()
return amazon.NewScanner()
case fos.Oracle:
d = oracle.NewScanner()
return oracle.NewScanner()
case fos.OpenSUSELeap:
d = suse.NewScanner(suse.OpenSUSE)
return suse.NewScanner(suse.OpenSUSE)
case fos.SLES:
d = suse.NewScanner(suse.SUSEEnterpriseLinux)
return suse.NewScanner(suse.SUSEEnterpriseLinux)
case fos.Photon:
d = photon.NewScanner()
return photon.NewScanner()
default:
log.Logger.Warnf("unsupported os : %s", osFamily)
return nil
}
return d
}

View File

@@ -4,18 +4,16 @@ import (
"strings"
"time"
oracleoval "github.com/aquasecurity/trivy-db/pkg/vulnsrc/oracle-oval"
version "github.com/knqyf263/go-rpm-version"
"golang.org/x/xerrors"
"k8s.io/utils/clock"
ftypes "github.com/aquasecurity/fanal/types"
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
oracleoval "github.com/aquasecurity/trivy-db/pkg/vulnsrc/oracle-oval"
"github.com/aquasecurity/trivy/pkg/log"
"github.com/aquasecurity/trivy/pkg/scanner/utils"
"github.com/aquasecurity/trivy/pkg/types"
"k8s.io/utils/clock"
)
var (
@@ -32,11 +30,13 @@ var (
}
)
// Scanner implements oracle vulnerability scanner
type Scanner struct {
vs dbTypes.VulnSrc
clock clock.Clock
}
// NewScanner is the factory method to return oracle vulnerabilities
func NewScanner() *Scanner {
return &Scanner{
vs: oracleoval.NewVulnSrc(),
@@ -44,6 +44,7 @@ func NewScanner() *Scanner {
}
}
// Detect scans and return vulnerability in Oracle scanner
func (s *Scanner) Detect(osVer string, pkgs []ftypes.Package) ([]types.DetectedVulnerability, error) {
log.Logger.Info("Detecting Oracle Linux vulnerabilities...")
@@ -64,7 +65,10 @@ func (s *Scanner) Detect(osVer string, pkgs []ftypes.Package) ([]types.DetectedV
installed := utils.FormatVersion(pkg)
installedVersion := version.NewVersion(installed)
for _, adv := range advisories {
// TODO: We don't seem to ignore advisories with no FixedVersion like we do elsewhere, expected?
// Skip if only one of them contains .ksplice1.
if strings.Contains(adv.FixedVersion, ".ksplice1.") != strings.Contains(pkg.Release, ".ksplice1.") {
continue
}
fixedVersion := version.NewVersion(adv.FixedVersion)
vuln := types.DetectedVulnerability{
VulnerabilityID: adv.VulnerabilityID,
@@ -81,6 +85,7 @@ func (s *Scanner) Detect(osVer string, pkgs []ftypes.Package) ([]types.DetectedV
return vulns, nil
}
// IsSupportedVersion checks is OSFamily can be scanned with Oracle scanner
func (s *Scanner) IsSupportedVersion(osFamily, osVer string) bool {
if strings.Count(osVer, ".") > 0 {
osVer = osVer[:strings.Index(osVer, ".")]

View File

@@ -6,9 +6,10 @@ import (
"time"
ftypes "github.com/aquasecurity/fanal/types"
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
"github.com/aquasecurity/trivy/pkg/types"
"github.com/aquasecurity/trivy/pkg/utils"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
oracleoval "github.com/aquasecurity/trivy-db/pkg/vulnsrc/oracle-oval"
"github.com/aquasecurity/trivy/pkg/log"
@@ -17,25 +18,6 @@ import (
clocktesting "k8s.io/utils/clock/testing"
)
type MockOracleConfig struct {
update func(string) error
get func(string, string) ([]dbTypes.Advisory, error)
}
func (moc MockOracleConfig) Update(a string) error {
if moc.update != nil {
return moc.update(a)
}
return nil
}
func (moc MockOracleConfig) Get(a string, b string) ([]dbTypes.Advisory, error) {
if moc.get != nil {
return moc.get(a, b)
}
return []dbTypes.Advisory{}, nil
}
func TestMain(m *testing.M) {
log.InitLogger(false, false)
os.Exit(m.Run())
@@ -120,45 +102,127 @@ func TestScanner_IsSupportedVersion(t *testing.T) {
}
func TestScanner_Detect(t *testing.T) {
t.Run("happy path", func(t *testing.T) {
s := &Scanner{
vs: MockOracleConfig{
get: func(s string, s2 string) (advisories []dbTypes.Advisory, err error) {
return []dbTypes.Advisory{
type args struct {
osVer string
pkgs []ftypes.Package
}
tests := []struct {
name string
args args
fixtures []string
want []types.DetectedVulnerability
wantErr string
}{
{
VulnerabilityID: "oracle-123",
FixedVersion: "3.0.0",
name: "detected",
fixtures: []string{"testdata/fixtures/oracle7.yaml"},
args: args{
osVer: "7",
pkgs: []ftypes.Package{
{
Name: "curl",
Version: "7.29.0",
Release: "59.0.1.el7",
Arch: "x86_64",
SrcName: "curl",
SrcVersion: "7.29.0",
SrcRelease: "59.0.1.el7",
},
}, nil
},
},
want: []types.DetectedVulnerability{
{
VulnerabilityID: "CVE-2020-8177",
PkgName: "curl",
InstalledVersion: "7.29.0-59.0.1.el7",
FixedVersion: "7.29.0-59.0.1.el7_9.1",
},
},
},
{
name: "without ksplice",
fixtures: []string{"testdata/fixtures/oracle7.yaml"},
args: args{
osVer: "7",
pkgs: []ftypes.Package{
{
Name: "glibc",
Version: "2.17",
Release: "317.0.1.el7",
Arch: "x86_64",
SrcName: "glibc",
SrcVersion: "2.17",
SrcRelease: "317.0.1.el7",
},
},
},
want: nil,
},
{
name: "with ksplice",
fixtures: []string{"testdata/fixtures/oracle7.yaml"},
args: args{
osVer: "7",
pkgs: []ftypes.Package{
{
Name: "glibc",
Epoch: 2,
Version: "2.17",
Release: "156.ksplice1.el7",
Arch: "x86_64",
SrcEpoch: 2,
SrcName: "glibc",
SrcVersion: "2.17",
SrcRelease: "156.ksplice1.el7",
},
},
},
want: []types.DetectedVulnerability{
{
VulnerabilityID: "CVE-2017-1000364",
PkgName: "glibc",
InstalledVersion: "2:2.17-156.ksplice1.el7",
FixedVersion: "2:2.17-157.ksplice1.el7_3.4",
},
},
},
{
name: "malformed",
fixtures: []string{"testdata/fixtures/invalid-type.yaml"},
args: args{
osVer: "7",
pkgs: []ftypes.Package{
{
Name: "curl",
Version: "7.29.0",
Release: "59.0.1.el7",
Arch: "x86_64",
SrcName: "curl",
SrcVersion: "7.29.0",
SrcRelease: "59.0.1.el7",
},
},
},
wantErr: "failed to unmarshal advisory JSON",
},
}
vuls, err := s.Detect("3.1.0", []ftypes.Package{
{
Name: "testpkg",
Version: "2.1.0",
Release: "hotfix",
SrcRelease: "test-hotfix",
SrcVersion: "2.1.0",
Layer: ftypes.Layer{
DiffID: "sha256:932da51564135c98a49a34a193d6cd363d8fa4184d957fde16c9d8527b3f3b02",
},
},
})
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
dir := utils.InitTestDB(t, tt.fixtures)
defer os.RemoveAll(dir)
s := NewScanner()
got, err := s.Detect(tt.args.osVer, tt.args.pkgs)
if tt.wantErr != "" {
require.NotNil(t, err)
assert.Contains(t, err.Error(), tt.wantErr)
return
} else {
assert.NoError(t, err)
assert.Equal(t, []types.DetectedVulnerability{
{
VulnerabilityID: "oracle-123",
PkgName: "testpkg",
InstalledVersion: "2.1.0-hotfix",
FixedVersion: "3.0.0",
Layer: ftypes.Layer{
DiffID: "sha256:932da51564135c98a49a34a193d6cd363d8fa4184d957fde16c9d8527b3f3b02",
},
},
}, vuls)
})
// TODO: Add unhappy paths
}
assert.Equal(t, tt.want, got)
})
}
}

View File

@@ -0,0 +1,9 @@
- bucket: Oracle Linux 7
pairs:
- bucket: curl
pairs:
- key: CVE-2020-8177
value:
FixedVersion:
- foo
- bar

View File

@@ -0,0 +1,12 @@
- bucket: Oracle Linux 7
pairs:
- bucket: curl
pairs:
- key: CVE-2020-8177
value:
FixedVersion: "7.29.0-59.0.1.el7_9.1"
- bucket: glibc
pairs:
- key: CVE-2017-1000364
value:
FixedVersion: "2:2.17-157.ksplice1.el7_3.4"

View File

@@ -1,31 +1,30 @@
package photon
import (
"time"
"github.com/aquasecurity/trivy-db/pkg/vulnsrc/photon"
version "github.com/knqyf263/go-rpm-version"
"golang.org/x/xerrors"
"k8s.io/utils/clock"
ftypes "github.com/aquasecurity/fanal/types"
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
"github.com/aquasecurity/trivy-db/pkg/vulnsrc/photon"
"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{}
)
// EOL can't be found for photon https://github.com/vmware/photon/issues/1031
//var (
// eolDates = map[string]time.Time{}
//)
// Scanner implements Photon scanner
type Scanner struct {
vs dbTypes.VulnSrc
clock clock.Clock
}
// NewScanner is the factory method for Scanner
func NewScanner() *Scanner {
return &Scanner{
vs: photon.NewVulnSrc(),
@@ -33,6 +32,7 @@ func NewScanner() *Scanner {
}
}
// Detect scans and returns vulnerabilities using photon scanner
func (s *Scanner) Detect(osVer string, pkgs []ftypes.Package) ([]types.DetectedVulnerability, error) {
log.Logger.Info("Detecting Photon Linux vulnerabilities...")
log.Logger.Debugf("Photon Linux: os version: %s", osVer)
@@ -64,6 +64,7 @@ func (s *Scanner) Detect(osVer string, pkgs []ftypes.Package) ([]types.DetectedV
return vulns, nil
}
// IsSupportedVersion checks is OSFamily can be scanned
func (s *Scanner) IsSupportedVersion(osFamily, osVer string) bool {
return true
}

View File

@@ -4,14 +4,13 @@ import (
"strings"
"time"
"github.com/aquasecurity/trivy-db/pkg/vulnsrc/redhat"
version "github.com/knqyf263/go-rpm-version"
"golang.org/x/xerrors"
"github.com/aquasecurity/fanal/analyzer/os"
ftypes "github.com/aquasecurity/fanal/types"
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
"github.com/aquasecurity/trivy-db/pkg/vulnsrc/redhat"
"github.com/aquasecurity/trivy/pkg/log"
"github.com/aquasecurity/trivy/pkg/scanner/utils"
"github.com/aquasecurity/trivy/pkg/types"
@@ -35,18 +34,24 @@ var (
// N/A
"8": time.Date(3000, 6, 30, 23, 59, 59, 0, time.UTC),
}
excludedVendorsSuffix = []string{
".remi",
}
)
// Scanner implements the Redhat scanner
type Scanner struct {
vs dbTypes.VulnSrc
}
// NewScanner is the factory method for Scanner
func NewScanner() *Scanner {
return &Scanner{
vs: redhat.NewVulnSrc(),
}
}
// Detect scans and returns redhat vulenrabilities
func (s *Scanner) Detect(osVer string, pkgs []ftypes.Package) ([]types.DetectedVulnerability, error) {
log.Logger.Info("Detecting RHEL/CentOS vulnerabilities...")
if strings.Count(osVer, ".") > 0 {
@@ -57,6 +62,11 @@ func (s *Scanner) Detect(osVer string, pkgs []ftypes.Package) ([]types.DetectedV
var vulns []types.DetectedVulnerability
for _, pkg := range pkgs {
if !s.isFromSupportedVendor(pkg) {
log.Logger.Debugf("Skipping %s: unsupported vendor", pkg.SrcName)
continue
}
// For Red Hat Security Data API containing only source package names
advisories, err := s.vs.Get(osVer, pkg.SrcName)
if err != nil {
@@ -102,6 +112,7 @@ func (s *Scanner) Detect(osVer string, pkgs []ftypes.Package) ([]types.DetectedV
return vulns, nil
}
// IsSupportedVersion checks is OSFamily can be scanned with Redhat scanner
func (s *Scanner) IsSupportedVersion(osFamily, osVer string) bool {
now := time.Now()
return s.isSupportedVersion(now, osFamily, osVer)
@@ -125,3 +136,12 @@ func (s *Scanner) isSupportedVersion(now time.Time, osFamily, osVer string) bool
}
return now.Before(eolDate)
}
func (s *Scanner) isFromSupportedVendor(pkg ftypes.Package) bool {
for _, s := range excludedVendorsSuffix {
if strings.HasSuffix(pkg.Release, s) {
return false
}
}
return true
}

View File

@@ -208,6 +208,45 @@ func TestScanner_Detect(t *testing.T) {
},
wantErr: true,
},
{
name: "happy path: packages from remi repository are skipped",
args: args{
osVer: "7.6",
pkgs: []ftypes.Package{
{
Name: "php",
Version: "7.3.23",
Release: "1.el7.remi",
Arch: "x86_64",
Epoch: 0,
SrcName: "php",
SrcVersion: "7.3.23",
SrcRelease: "1.el7.remi",
SrcEpoch: 0,
Layer: ftypes.Layer{
DiffID: "sha256:c27b3cf4d516baf5932d5df3a573c6a571ddace3ee2a577492292d2e849c112b",
},
},
},
},
get: []dbTypes.GetExpectation{
{
Args: dbTypes.GetArgs{
Release: "7",
PkgName: "php",
},
Returns: dbTypes.GetReturns{
Advisories: []dbTypes.Advisory{
{
VulnerabilityID: "CVE-2011-4718",
FixedVersion: "",
},
},
},
},
},
want: []types.DetectedVulnerability(nil),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {

View File

@@ -6,6 +6,8 @@ import (
"golang.org/x/xerrors"
"k8s.io/utils/clock"
version "github.com/knqyf263/go-rpm-version"
fos "github.com/aquasecurity/fanal/analyzer/os"
ftypes "github.com/aquasecurity/fanal/types"
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
@@ -13,7 +15,6 @@ import (
"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"
)
var (
@@ -38,7 +39,9 @@ var (
"15": time.Date(2019, 12, 31, 23, 59, 59, 0, time.UTC),
"15.1": time.Date(2021, 1, 31, 23, 59, 59, 0, time.UTC),
// 6 months after SLES 15 SP3 release
// "15.2": time.Date(2028, 7, 31, 23, 59, 59, 0, time.UTC),
"15.2": time.Date(2021, 10, 31, 23, 59, 59, 0, time.UTC),
// 6 months after SLES 15 SP4 release
// "15.3": time.Date(2028, 7, 31, 23, 59, 59, 0, time.UTC),
}
opensuseEolDates = map[string]time.Time{
@@ -52,20 +55,24 @@ var (
}
)
// Scanner implements suse scanner
type Scanner struct {
vs dbTypes.VulnSrc
clock clock.Clock
family string
}
type SUSEType int
// Type to define SUSE type
type Type int
const (
SUSEEnterpriseLinux SUSEType = iota
// SUSEEnterpriseLinux is Linux Enterprise version
SUSEEnterpriseLinux Type = iota
// OpenSUSE for open versions
OpenSUSE
)
func NewScanner(t SUSEType) *Scanner {
// NewScanner is the factory method for Scanner
func NewScanner(t Type) *Scanner {
switch t {
case SUSEEnterpriseLinux:
return &Scanner{
@@ -81,6 +88,7 @@ func NewScanner(t SUSEType) *Scanner {
return nil
}
// Detect scans and returns the vulnerabilities
func (s *Scanner) Detect(osVer string, pkgs []ftypes.Package) ([]types.DetectedVulnerability, error) {
log.Logger.Info("Detecting SUSE vulnerabilities...")
log.Logger.Debugf("SUSE: os version: %s", osVer)
@@ -112,6 +120,7 @@ func (s *Scanner) Detect(osVer string, pkgs []ftypes.Package) ([]types.DetectedV
return vulns, nil
}
// IsSupportedVersion checks if OSFamily can be scanned using SUSE scanner
func (s *Scanner) IsSupportedVersion(osFamily, osVer string) bool {
var eolDate time.Time
var ok bool

View File

@@ -51,16 +51,19 @@ var (
}
)
// Scanner implements the Ubuntu scanner
type Scanner struct {
vs dbTypes.VulnSrc
}
// NewScanner is the factory method for Scanner
func NewScanner() *Scanner {
return &Scanner{
vs: ubuntu.NewVulnSrc(),
}
}
// Detect scans and returns the vulnerabilities
func (s *Scanner) Detect(osVer string, pkgs []ftypes.Package) ([]types.DetectedVulnerability, error) {
log.Logger.Info("Detecting Ubuntu vulnerabilities...")
log.Logger.Debugf("ubuntu: os version: %s", osVer)
@@ -108,6 +111,7 @@ func (s *Scanner) Detect(osVer string, pkgs []ftypes.Package) ([]types.DetectedV
return vulns, nil
}
// IsSupportedVersion checks is OSFamily can be scanned using Ubuntu scanner
func (s *Scanner) IsSupportedVersion(osFamily, osVer string) bool {
now := time.Now()
return s.isSupportedVersion(now, osFamily, osVer)

View File

@@ -10,11 +10,12 @@ import (
"strconv"
"strings"
"github.com/aquasecurity/trivy-db/pkg/db"
"github.com/aquasecurity/trivy/pkg/log"
"github.com/google/go-github/v28/github"
"golang.org/x/oauth2"
"golang.org/x/xerrors"
"github.com/aquasecurity/trivy-db/pkg/db"
"github.com/aquasecurity/trivy/pkg/log"
)
const (
@@ -22,11 +23,13 @@ const (
repo = "trivy-db"
)
// RepositoryInterface defines the operations on repository
type RepositoryInterface interface {
ListReleases(ctx context.Context, opt *github.ListOptions) ([]*github.RepositoryRelease, *github.Response, error)
DownloadAsset(ctx context.Context, id int64) (io.ReadCloser, string, error)
}
// Repository implements RepositoryInterface
type Repository struct {
repository *github.RepositoriesService
git *github.GitService
@@ -34,22 +37,27 @@ type Repository struct {
repoName string
}
// ListReleases returns all github releases on repository
func (r Repository) ListReleases(ctx context.Context, opt *github.ListOptions) ([]*github.RepositoryRelease, *github.Response, error) {
return r.repository.ListReleases(ctx, r.owner, r.repoName, opt)
}
// DownloadAsset returns reader object of downloaded object
func (r Repository) DownloadAsset(ctx context.Context, id int64) (io.ReadCloser, string, error) {
return r.repository.DownloadReleaseAsset(ctx, r.owner, r.repoName, id)
}
// Operation defines the file operations
type Operation interface {
DownloadDB(ctx context.Context, fileName string) (io.ReadCloser, int, error)
}
// Client implements RepositoryInterface
type Client struct {
Repository RepositoryInterface
}
// NewClient is the factory method to return Client for RepositoryInterface operations
func NewClient() Client {
var client *http.Client
githubToken := os.Getenv("GITHUB_TOKEN")
@@ -73,6 +81,7 @@ func NewClient() Client {
}
}
// DownloadDB returns reader object of file content
func (c Client) DownloadDB(ctx context.Context, fileName string) (io.ReadCloser, int, error) {
options := github.ListOptions{}
releases, _, err := c.Repository.ListReleases(ctx, &options)
@@ -120,7 +129,7 @@ func (c Client) downloadAsset(ctx context.Context, asset github.ReleaseAsset, fi
}
log.Logger.Debugf("asset URL: %s", url)
resp, err := http.Get(url)
resp, err := http.Get(url) // nolint: gosec
if err != nil || resp.StatusCode != http.StatusOK {
return nil, 0, xerrors.Errorf("unable to download the asset via URL: %w", err)
}

View File

@@ -6,14 +6,17 @@ import (
"github.com/cheggaaa/pb/v3"
)
// ProgressBar exports method to track the progress of jobs
type ProgressBar struct {
quiet bool
}
// NewProgressBar is the factory method to return progressBar object
func NewProgressBar(quiet bool) ProgressBar {
return ProgressBar{quiet: quiet}
}
// Start starts the progress tracking
func (p ProgressBar) Start(total int64) Bar {
if p.quiet {
return Bar{}
@@ -22,16 +25,20 @@ func (p ProgressBar) Start(total int64) Bar {
return Bar{bar: bar}
}
// Bar is the proxy progress bar
type Bar struct {
bar *pb.ProgressBar
}
// NewProxyReader is the factory method to track the progress
func (b Bar) NewProxyReader(r io.Reader) io.Reader {
if b.bar == nil {
return r
}
return b.bar.NewProxyReader(r)
}
// Finish finishes the progress tracking
func (b Bar) Finish() {
if b.bar == nil {
return

View File

@@ -9,10 +9,12 @@ import (
)
var (
// Logger is the global variable for logging
Logger *zap.SugaredLogger
debugOption bool
)
// InitLogger initialize the logger variable
func InitLogger(debug, disable bool) (err error) {
debugOption = debug
Logger, err = NewLogger(debug, disable)
@@ -23,6 +25,7 @@ func InitLogger(debug, disable bool) (err error) {
}
// NewLogger is the factory method to return the instance of logger
func NewLogger(debug, disable bool) (*zap.SugaredLogger, error) {
// First, define our level-handling logic.
errorPriority := zap.LevelEnablerFunc(func(lvl zapcore.Level) bool {
@@ -78,6 +81,7 @@ func NewLogger(debug, disable bool) (*zap.SugaredLogger, error) {
return logger.Sugar(), nil
}
// Fatal for logging fatal errors
func Fatal(err error) {
if debugOption {
Logger.Fatalf("%+v", err)

View File

@@ -13,19 +13,22 @@ import (
"text/template"
"time"
"github.com/olekukonko/tablewriter"
"golang.org/x/xerrors"
ftypes "github.com/aquasecurity/fanal/types"
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
"github.com/aquasecurity/trivy/pkg/types"
"github.com/aquasecurity/trivy/pkg/utils"
"github.com/olekukonko/tablewriter"
)
// Now returns the current time
var Now = time.Now
// Results to hold list of Result
type Results []Result
// Result to hold image scan results
type Result struct {
Target string `json:"Target"`
Type string `json:"Type,omitempty"`
@@ -33,13 +36,14 @@ type Result struct {
Vulnerabilities []types.DetectedVulnerability `json:"Vulnerabilities"`
}
// WriteResults writes the result to output, format as passed in argument
func WriteResults(format string, output io.Writer, severities []dbTypes.Severity, results Results, outputTemplate string, light bool) error {
var writer Writer
switch format {
case "table":
writer = &TableWriter{Output: output, Light: light, Severities: severities}
case "json":
writer = &JsonWriter{Output: output}
writer = &JSONWriter{Output: output}
case "template":
var err error
if writer, err = NewTemplateWriter(output, outputTemplate); err != nil {
@@ -55,22 +59,28 @@ func WriteResults(format string, output io.Writer, severities []dbTypes.Severity
return nil
}
// Writer defines the result write operation
type Writer interface {
Write(Results) error
}
// TableWriter implements Writer and output in tabular form
type TableWriter struct {
Severities []dbTypes.Severity
Output io.Writer
Light bool
}
// Write writes the result on standard output
func (tw TableWriter) Write(results Results) error {
for _, result := range results {
tw.write(result)
}
return nil
}
// nolint: gocyclo
// TODO: refactror and fix cyclometic complexity
func (tw TableWriter) write(result Result) {
table := tablewriter.NewWriter(tw.Output)
header := []string{"Library", "Vulnerability ID", "Severity", "Installed Version", "Fixed Version"}
@@ -134,11 +144,13 @@ func (tw TableWriter) write(result Result) {
return
}
type JsonWriter struct {
// JSONWriter implements result Writer
type JSONWriter struct {
Output io.Writer
}
func (jw JsonWriter) Write(results Results) error {
// Write writes the results in JSON format
func (jw JSONWriter) Write(results Results) error {
output, err := json.MarshalIndent(results, "", " ")
if err != nil {
return xerrors.Errorf("failed to marshal json: %w", err)
@@ -150,11 +162,13 @@ func (jw JsonWriter) Write(results Results) error {
return nil
}
// TemplateWriter write result in custom format defined by user's template
type TemplateWriter struct {
Output io.Writer
Template *template.Template
}
// NewTemplateWriter is the factory method to return TemplateWriter object
func NewTemplateWriter(output io.Writer, outputTemplate string) (*TemplateWriter, error) {
if strings.HasPrefix(outputTemplate, "@") {
buf, err := ioutil.ReadFile(strings.TrimPrefix(outputTemplate, "@"))
@@ -197,6 +211,7 @@ func NewTemplateWriter(output io.Writer, outputTemplate string) (*TemplateWriter
return &TemplateWriter{Output: output, Template: tmpl}, nil
}
// Write writes result
func (tw TemplateWriter) Write(results Results) error {
err := tw.Template.Execute(tw.Output, results)
if err != nil {

View File

@@ -175,7 +175,7 @@ func TestReportWriter_JSON(t *testing.T) {
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
jw := report.JsonWriter{}
jw := report.JSONWriter{}
jsonWritten := bytes.Buffer{}
jw.Output = &jsonWritten

View File

@@ -16,28 +16,35 @@ import (
rpc "github.com/aquasecurity/trivy/rpc/scanner"
)
// SuperSet binds the dependencies for RPC client
var SuperSet = wire.NewSet(
NewProtobufClient,
NewScanner,
)
// RemoteURL for RPC remote host
type RemoteURL string
// NewProtobufClient is the factory method to return RPC scanner
func NewProtobufClient(remoteURL RemoteURL) rpc.Scanner {
return rpc.NewScannerProtobufClient(string(remoteURL), &http.Client{})
}
// CustomHeaders for holding HTTP headers
type CustomHeaders http.Header
// Scanner implements the RPC scanner
type Scanner struct {
customHeaders CustomHeaders
client rpc.Scanner
}
// NewScanner is the factory method to return RPC Scanner
func NewScanner(customHeaders CustomHeaders, s rpc.Scanner) Scanner {
return Scanner{customHeaders: customHeaders, client: s}
}
// Scan scans the image
func (s Scanner) Scan(target string, imageID string, layerIDs []string, options types.ScanOptions) (report.Results, *ftypes.OS, bool, error) {
ctx := WithCustomHeaders(context.Background(), http.Header(s.customHeaders))
@@ -58,5 +65,5 @@ func (s Scanner) Scan(target string, imageID string, layerIDs []string, options
return nil, nil, false, xerrors.Errorf("failed to detect vulnerabilities via RPC: %w", err)
}
return r.ConvertFromRpcResults(res.Results), r.ConvertFromRpcOS(res.Os), res.Eosl, nil
return r.ConvertFromRPCResults(res.Results), r.ConvertFromRPCOS(res.Os), res.Eosl, nil
}

View File

@@ -9,6 +9,7 @@ import (
"github.com/aquasecurity/trivy/pkg/log"
)
// WithCustomHeaders adds custom headers to request headers
func WithCustomHeaders(ctx context.Context, customHeaders http.Header) context.Context {
// Attach the headers to a context
ctxWithToken, err := twirp.WithHTTPRequestHeaders(ctx, customHeaders)

View File

@@ -14,7 +14,8 @@ import (
"github.com/aquasecurity/trivy/rpc/scanner"
)
func ConvertToRpcPkgs(pkgs []ftypes.Package) []*common.Package {
// ConvertToRPCPkgs returns the list of RPC package objects
func ConvertToRPCPkgs(pkgs []ftypes.Package) []*common.Package {
var rpcPkgs []*common.Package
for _, pkg := range pkgs {
rpcPkgs = append(rpcPkgs, &common.Package{
@@ -32,7 +33,8 @@ func ConvertToRpcPkgs(pkgs []ftypes.Package) []*common.Package {
return rpcPkgs
}
func ConvertFromRpcPkgs(rpcPkgs []*common.Package) []ftypes.Package {
// ConvertFromRPCPkgs returns list of Fanal package objects
func ConvertFromRPCPkgs(rpcPkgs []*common.Package) []ftypes.Package {
var pkgs []ftypes.Package
for _, pkg := range rpcPkgs {
pkgs = append(pkgs, ftypes.Package{
@@ -50,7 +52,8 @@ func ConvertFromRpcPkgs(rpcPkgs []*common.Package) []ftypes.Package {
return pkgs
}
func ConvertFromRpcLibraries(rpcLibs []*common.Library) []ftypes.LibraryInfo {
// ConvertFromRPCLibraries returns list of Fanal library
func ConvertFromRPCLibraries(rpcLibs []*common.Library) []ftypes.LibraryInfo {
var libs []ftypes.LibraryInfo
for _, l := range rpcLibs {
libs = append(libs, ftypes.LibraryInfo{
@@ -63,7 +66,8 @@ func ConvertFromRpcLibraries(rpcLibs []*common.Library) []ftypes.LibraryInfo {
return libs
}
func ConvertToRpcLibraries(libs []deptypes.Library) []*common.Library {
// ConvertToRPCLibraries returns list of libraries
func ConvertToRPCLibraries(libs []deptypes.Library) []*common.Library {
var rpcLibs []*common.Library
for _, l := range libs {
rpcLibs = append(rpcLibs, &common.Library{
@@ -74,7 +78,8 @@ func ConvertToRpcLibraries(libs []deptypes.Library) []*common.Library {
return rpcLibs
}
func ConvertFromRpcVulns(rpcVulns []*common.Vulnerability) []types.DetectedVulnerability {
// ConvertFromRPCVulns returns converted vulnerability from common vulnerability format
func ConvertFromRPCVulns(rpcVulns []*common.Vulnerability) []types.DetectedVulnerability {
var vulns []types.DetectedVulnerability
for _, vuln := range rpcVulns {
severity := dbTypes.Severity(vuln.Severity)
@@ -94,7 +99,8 @@ func ConvertFromRpcVulns(rpcVulns []*common.Vulnerability) []types.DetectedVulne
return vulns
}
func ConvertToRpcVulns(vulns []types.DetectedVulnerability) []*common.Vulnerability {
// ConvertToRPCVulns returns common.Vulnerability
func ConvertToRPCVulns(vulns []types.DetectedVulnerability) []*common.Vulnerability {
var rpcVulns []*common.Vulnerability
for _, vuln := range vulns {
severity, err := dbTypes.NewSeverity(vuln.Severity)
@@ -132,9 +138,9 @@ func ConvertToRpcVulns(vulns []types.DetectedVulnerability) []*common.Vulnerabil
return rpcVulns
}
func ConvertFromRpcResults(rpcResults []*scanner.Result) []report.Result {
// ConvertFromRPCResults converts scannel.Result to report.Result
func ConvertFromRPCResults(rpcResults []*scanner.Result) []report.Result {
var results []report.Result
for _, result := range rpcResults {
var vulns []types.DetectedVulnerability
for _, vuln := range result.Vulnerabilities {
@@ -178,7 +184,8 @@ func ConvertFromRpcResults(rpcResults []*scanner.Result) []report.Result {
return results
}
func ConvertFromRpcOS(rpcOS *common.OS) *ftypes.OS {
// ConvertFromRPCOS converts common.OS to fanal.OS
func ConvertFromRPCOS(rpcOS *common.OS) *ftypes.OS {
if rpcOS == nil {
return nil
}
@@ -188,55 +195,60 @@ func ConvertFromRpcOS(rpcOS *common.OS) *ftypes.OS {
}
}
func ConvertFromRpcPackageInfos(rpcPkgInfos []*common.PackageInfo) []ftypes.PackageInfo {
// ConvertFromRPCPackageInfos converts common.PackageInfo to fanal.PackageInfo
func ConvertFromRPCPackageInfos(rpcPkgInfos []*common.PackageInfo) []ftypes.PackageInfo {
var pkgInfos []ftypes.PackageInfo
for _, rpcPkgInfo := range rpcPkgInfos {
pkgInfos = append(pkgInfos, ftypes.PackageInfo{
FilePath: rpcPkgInfo.FilePath,
Packages: ConvertFromRpcPkgs(rpcPkgInfo.Packages),
Packages: ConvertFromRPCPkgs(rpcPkgInfo.Packages),
})
}
return pkgInfos
}
func ConvertFromRpcApplications(rpcApps []*common.Application) []ftypes.Application {
// ConvertFromRPCApplications converts common.Application to fanal.Application
func ConvertFromRPCApplications(rpcApps []*common.Application) []ftypes.Application {
var apps []ftypes.Application
for _, rpcApp := range rpcApps {
apps = append(apps, ftypes.Application{
Type: rpcApp.Type,
FilePath: rpcApp.FilePath,
Libraries: ConvertFromRpcLibraries(rpcApp.Libraries),
Libraries: ConvertFromRPCLibraries(rpcApp.Libraries),
})
}
return apps
}
func ConvertFromRpcPutArtifactRequest(req *cache.PutArtifactRequest) ftypes.ArtifactInfo {
created, _ := ptypes.Timestamp(req.ArtifactInfo.Created)
// ConvertFromRPCPutArtifactRequest converts cache.PutArtifactRequest to fanal.PutArtifactRequest
func ConvertFromRPCPutArtifactRequest(req *cache.PutArtifactRequest) ftypes.ArtifactInfo {
created, _ := ptypes.Timestamp(req.ArtifactInfo.Created) // nolint: errcheck
return ftypes.ArtifactInfo{
SchemaVersion: int(req.ArtifactInfo.SchemaVersion),
Architecture: req.ArtifactInfo.Architecture,
Created: created,
DockerVersion: req.ArtifactInfo.DockerVersion,
OS: req.ArtifactInfo.Os,
HistoryPackages: ConvertFromRpcPkgs(req.ArtifactInfo.HistoryPackages),
HistoryPackages: ConvertFromRPCPkgs(req.ArtifactInfo.HistoryPackages),
}
}
func ConvertFromRpcPutBlobRequest(req *cache.PutBlobRequest) ftypes.BlobInfo {
// ConvertFromRPCPutBlobRequest returns ftypes.BlobInfo
func ConvertFromRPCPutBlobRequest(req *cache.PutBlobRequest) ftypes.BlobInfo {
return ftypes.BlobInfo{
SchemaVersion: int(req.BlobInfo.SchemaVersion),
Digest: req.BlobInfo.Digest,
DiffID: req.BlobInfo.DiffId,
OS: ConvertFromRpcOS(req.BlobInfo.Os),
PackageInfos: ConvertFromRpcPackageInfos(req.BlobInfo.PackageInfos),
Applications: ConvertFromRpcApplications(req.BlobInfo.Applications),
OS: ConvertFromRPCOS(req.BlobInfo.Os),
PackageInfos: ConvertFromRPCPackageInfos(req.BlobInfo.PackageInfos),
Applications: ConvertFromRPCApplications(req.BlobInfo.Applications),
OpaqueDirs: req.BlobInfo.OpaqueDirs,
WhiteoutFiles: req.BlobInfo.WhiteoutFiles,
}
}
func ConvertToRpcOS(fos *ftypes.OS) *common.OS {
// ConvertToRPCOS returns common.OS
func ConvertToRPCOS(fos *ftypes.OS) *common.OS {
if fos == nil {
return nil
}
@@ -246,7 +258,8 @@ func ConvertToRpcOS(fos *ftypes.OS) *common.OS {
}
}
func ConvertToRpcArtifactInfo(imageID string, imageInfo ftypes.ArtifactInfo) *cache.PutArtifactRequest {
// ConvertToRPCArtifactInfo returns PutArtifactRequest
func ConvertToRPCArtifactInfo(imageID string, imageInfo ftypes.ArtifactInfo) *cache.PutArtifactRequest {
t, err := ptypes.TimestampProto(imageInfo.Created)
if err != nil {
log.Logger.Warnf("invalid timestamp: %s", err)
@@ -260,17 +273,18 @@ func ConvertToRpcArtifactInfo(imageID string, imageInfo ftypes.ArtifactInfo) *ca
Created: t,
DockerVersion: imageInfo.DockerVersion,
Os: imageInfo.OS,
HistoryPackages: ConvertToRpcPkgs(imageInfo.HistoryPackages),
HistoryPackages: ConvertToRPCPkgs(imageInfo.HistoryPackages),
},
}
}
func ConvertToRpcBlobInfo(diffID string, layerInfo ftypes.BlobInfo) *cache.PutBlobRequest {
// ConvertToRPCBlobInfo returns PutBlobRequest
func ConvertToRPCBlobInfo(diffID string, layerInfo ftypes.BlobInfo) *cache.PutBlobRequest {
var packageInfos []*common.PackageInfo
for _, pkgInfo := range layerInfo.PackageInfos {
packageInfos = append(packageInfos, &common.PackageInfo{
FilePath: pkgInfo.FilePath,
Packages: ConvertToRpcPkgs(pkgInfo.Packages),
Packages: ConvertToRPCPkgs(pkgInfo.Packages),
})
}
@@ -282,7 +296,6 @@ func ConvertToRpcBlobInfo(diffID string, layerInfo ftypes.BlobInfo) *cache.PutBl
Name: lib.Library.Name,
Version: lib.Library.Version,
})
}
applications = append(applications, &common.Application{
Type: app.Type,
@@ -297,7 +310,7 @@ func ConvertToRpcBlobInfo(diffID string, layerInfo ftypes.BlobInfo) *cache.PutBl
SchemaVersion: ftypes.BlobJSONSchemaVersion,
Digest: layerInfo.Digest,
DiffId: layerInfo.DiffID,
Os: ConvertToRpcOS(layerInfo.OS),
Os: ConvertToRPCOS(layerInfo.OS),
PackageInfos: packageInfos,
Applications: applications,
OpaqueDirs: layerInfo.OpaqueDirs,
@@ -306,6 +319,7 @@ func ConvertToRpcBlobInfo(diffID string, layerInfo ftypes.BlobInfo) *cache.PutBl
}
}
// ConvertToMissingBlobsRequest returns MissingBlobsRequest object
func ConvertToMissingBlobsRequest(imageID string, layerIDs []string) *cache.MissingBlobsRequest {
return &cache.MissingBlobsRequest{
ArtifactId: imageID,
@@ -313,7 +327,8 @@ func ConvertToMissingBlobsRequest(imageID string, layerIDs []string) *cache.Miss
}
}
func ConvertToRpcScanResponse(results report.Results, os *ftypes.OS, eosl bool) *scanner.ScanResponse {
// ConvertToRPCScanResponse converts report.Result to ScanResponse
func ConvertToRPCScanResponse(results report.Results, os *ftypes.OS, eosl bool) *scanner.ScanResponse {
rpcOS := &common.OS{}
if os != nil {
rpcOS.Family = os.Family
@@ -324,7 +339,7 @@ func ConvertToRpcScanResponse(results report.Results, os *ftypes.OS, eosl bool)
for _, result := range results {
rpcResults = append(rpcResults, &scanner.Result{
Target: result.Target,
Vulnerabilities: ConvertToRpcVulns(result.Vulnerabilities),
Vulnerabilities: ConvertToRPCVulns(result.Vulnerabilities),
Type: result.Type,
})
}

View File

@@ -65,7 +65,7 @@ func TestConvertToRpcPkgs(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := ConvertToRpcPkgs(tt.args.pkgs)
got := ConvertToRPCPkgs(tt.args.pkgs)
assert.Equal(t, tt.want, got, tt.name)
})
}
@@ -113,7 +113,7 @@ func TestConvertFromRpcPkgs(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := ConvertFromRpcPkgs(tt.args.rpcPkgs)
got := ConvertFromRPCPkgs(tt.args.rpcPkgs)
assert.Equal(t, tt.want, got, tt.name)
})
}
@@ -144,7 +144,7 @@ func TestConvertFromRpcLibraries(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := ConvertFromRpcLibraries(tt.args.rpcLibs)
got := ConvertFromRPCLibraries(tt.args.rpcLibs)
assert.Equal(t, got, tt.want, tt.name)
})
}
@@ -175,7 +175,7 @@ func TestConvertToRpcLibraries(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := ConvertToRpcLibraries(tt.args.libs)
got := ConvertToRPCLibraries(tt.args.libs)
assert.Equal(t, got, tt.want, tt.name)
})
}
@@ -224,7 +224,7 @@ func TestConvertFromRpcVulns(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := ConvertFromRpcVulns(tt.args.rpcVulns)
got := ConvertFromRPCVulns(tt.args.rpcVulns)
assert.Equal(t, got, tt.want, tt.name)
})
}
@@ -337,7 +337,7 @@ func TestConvertToRpcVulns(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := ConvertToRpcVulns(tt.args.vulns)
got := ConvertToRPCVulns(tt.args.vulns)
assert.Equal(t, got, tt.want, tt.name)
})
}

View File

@@ -3,15 +3,17 @@ package rpc
import (
"time"
"github.com/aquasecurity/trivy/pkg/log"
"github.com/cenkalti/backoff"
"github.com/twitchtv/twirp"
"github.com/aquasecurity/trivy/pkg/log"
)
const (
maxRetries = 10
)
// Retry executes the function again using backoff until maxRetries or success
func Retry(f func() error) error {
operation := func() error {
err := f()

View File

@@ -14,6 +14,7 @@ import (
proto "github.com/aquasecurity/trivy/rpc/detector"
)
// SuperSet binds the dependencies for library RPC server
var SuperSet = wire.NewSet(
detector.SuperSet,
vulnerability.SuperSet,
@@ -26,13 +27,14 @@ type Server struct {
vulnClient vulnerability.Operation
}
// NewServer is the facotry method for Server
func NewServer(detector detector.Operation, vulnClient vulnerability.Operation) *Server {
return &Server{detector: detector, vulnClient: vulnClient}
}
// Detect is for backward compatibility
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))
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)
@@ -41,5 +43,5 @@ func (s *Server) Detect(_ context.Context, req *proto.LibDetectRequest) (res *pr
s.vulnClient.FillInfo(vulns, "")
return &proto.DetectResponse{Vulnerabilities: rpc.ConvertToRpcVulns(vulns)}, nil
return &proto.DetectResponse{Vulnerabilities: rpc.ConvertToRPCVulns(vulns)}, nil
}

View File

@@ -24,11 +24,13 @@ import (
rpcScanner "github.com/aquasecurity/trivy/rpc/scanner"
)
// DBWorkerSuperSet binds the dependencies for Trivy DB worker
var DBWorkerSuperSet = wire.NewSet(
dbFile.SuperSet,
newDBWorker,
)
// ListenAndServe starts Trivy server
func ListenAndServe(c config.Config, fsCache cache.FSCache) error {
requestWg := &sync.WaitGroup{}
dbUpdateWg := &sync.WaitGroup{}
@@ -132,7 +134,7 @@ func (w dbWorker) hotUpdate(ctx context.Context, cacheDir string, dbUpdateWg, re
}
defer os.RemoveAll(tmpDir)
if err := w.dbClient.Download(ctx, tmpDir, false); err != nil {
if err = w.dbClient.Download(ctx, tmpDir, false); err != nil {
return xerrors.Errorf("failed to download vulnerability DB: %w", err)
}

Some files were not shown because too many files have changed in this diff Show More