mirror of
https://github.com/aquasecurity/trivy.git
synced 2025-12-18 02:09:32 -08:00
Compare commits
17 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1391b3bf47 | ||
|
|
b6d5b82c48 | ||
|
|
9dfb0fe3a9 | ||
|
|
455546975c | ||
|
|
c189aa6a0a | ||
|
|
8442528fa7 | ||
|
|
d09787e150 | ||
|
|
0285a89c7c | ||
|
|
7d7784fecb | ||
|
|
ca6f196001 | ||
|
|
e621cf2bc1 | ||
|
|
906ab5483e | ||
|
|
1549c25709 | ||
|
|
fe1d07e58c | ||
|
|
793a1aa3c8 | ||
|
|
4a94477532 | ||
|
|
9bc2b1949c |
12
.github/ISSUE_TEMPLATE/BUG_REPORT.md
vendored
12
.github/ISSUE_TEMPLATE/BUG_REPORT.md
vendored
@@ -4,28 +4,28 @@ labels: kind/bug
|
|||||||
about: If something isn't working as expected.
|
about: If something isn't working as expected.
|
||||||
---
|
---
|
||||||
|
|
||||||
**Description**
|
## Description
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
Briefly describe the problem you are having in a few paragraphs.
|
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)
|
(paste your output here)
|
||||||
```
|
```
|
||||||
|
|
||||||
**Output of `trivy -v`:**
|
## Output of `trivy -v`:
|
||||||
|
|
||||||
```
|
```
|
||||||
(paste your output here)
|
(paste your output here)
|
||||||
```
|
```
|
||||||
|
|
||||||
**Additional details (base image name, container registry info...):**
|
## Additional details (base image name, container registry info...):
|
||||||
|
|||||||
12
.github/workflows/test.yaml
vendored
12
.github/workflows/test.yaml
vendored
@@ -1,6 +1,17 @@
|
|||||||
name: Test
|
name: Test
|
||||||
on: pull_request
|
on: pull_request
|
||||||
jobs:
|
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:
|
integration:
|
||||||
name: Integration Test
|
name: Integration Test
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@@ -34,3 +45,4 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
version: latest
|
version: latest
|
||||||
args: release --snapshot --rm-dist --skip-publish
|
args: release --snapshot --rm-dist --skip-publish
|
||||||
|
|
||||||
|
|||||||
71
.golangci.yaml
Normal file
71
.golangci.yaml
Normal 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
|
||||||
14
README.md
14
README.md
@@ -106,7 +106,7 @@ See [here](#continuous-integration-ci) for details.
|
|||||||
- See [Quick Start](#quick-start) and [Examples](#examples)
|
- See [Quick Start](#quick-start) and [Examples](#examples)
|
||||||
- Fast
|
- Fast
|
||||||
- The first scan will finish within 10 seconds (depending on your network). Consequent scans will finish in single seconds.
|
- 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
|
- Easy installation
|
||||||
- `apt-get install`, `yum install` and `brew install` is possible (See [Installation](#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.)
|
- **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>
|
</details>
|
||||||
|
|
||||||
### Docker
|
### Docker
|
||||||
|
#### Docker Hub
|
||||||
|
|
||||||
Replace [YOUR_CACHE_DIR] with the cache directory on your machine.
|
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>
|
</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
|
## Filesystem
|
||||||
Scan a filesystem (such as a host machine, a virtual machine image, or an unpacked container image 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
|
||||||
|
|
||||||
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.
|
You don't need to set ENV vars when download from public repository.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
export TRIVY_AUTH_URL=https://registry.hub.docker.com
|
|
||||||
export TRIVY_USERNAME={DOCKERHUB_USERNAME}
|
export TRIVY_USERNAME={DOCKERHUB_USERNAME}
|
||||||
export TRIVY_PASSWORD={DOCKERHUB_PASSWORD}
|
export TRIVY_PASSWORD={DOCKERHUB_PASSWORD}
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ UBUNTU_RELEASES=$(ubuntu-distro-info --supported)
|
|||||||
|
|
||||||
cd trivy-repo/deb
|
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"
|
echo "Removing deb package of $release"
|
||||||
reprepro -A i386 remove $release trivy
|
reprepro -A i386 remove $release trivy
|
||||||
reprepro -A amd64 remove $release trivy
|
reprepro -A amd64 remove $release trivy
|
||||||
|
|||||||
@@ -72,6 +72,7 @@ get_binaries() {
|
|||||||
freebsd/armv7) BINARIES="trivy" ;;
|
freebsd/armv7) BINARIES="trivy" ;;
|
||||||
linux/386) BINARIES="trivy" ;;
|
linux/386) BINARIES="trivy" ;;
|
||||||
linux/amd64) BINARIES="trivy" ;;
|
linux/amd64) BINARIES="trivy" ;;
|
||||||
|
linux/ppc64le) BINARIES="trivy" ;;
|
||||||
linux/arm64) BINARIES="trivy" ;;
|
linux/arm64) BINARIES="trivy" ;;
|
||||||
linux/armv7) BINARIES="trivy" ;;
|
linux/armv7) BINARIES="trivy" ;;
|
||||||
openbsd/386) BINARIES="trivy" ;;
|
openbsd/386) BINARIES="trivy" ;;
|
||||||
@@ -110,6 +111,7 @@ adjust_os() {
|
|||||||
amd64) OS=64bit ;;
|
amd64) OS=64bit ;;
|
||||||
arm) OS=ARM ;;
|
arm) OS=ARM ;;
|
||||||
arm64) OS=ARM64 ;;
|
arm64) OS=ARM64 ;;
|
||||||
|
ppc64le) OS=PPC64LE ;;
|
||||||
darwin) OS=macOS ;;
|
darwin) OS=macOS ;;
|
||||||
dragonfly) OS=DragonFlyBSD ;;
|
dragonfly) OS=DragonFlyBSD ;;
|
||||||
freebsd) OS=FreeBSD ;;
|
freebsd) OS=FreeBSD ;;
|
||||||
@@ -126,6 +128,7 @@ adjust_arch() {
|
|||||||
amd64) ARCH=64bit ;;
|
amd64) ARCH=64bit ;;
|
||||||
arm) ARCH=ARM ;;
|
arm) ARCH=ARM ;;
|
||||||
arm64) ARCH=ARM64 ;;
|
arm64) ARCH=ARM64 ;;
|
||||||
|
ppc64le) OS=PPC64LE ;;
|
||||||
darwin) ARCH=macOS ;;
|
darwin) ARCH=macOS ;;
|
||||||
dragonfly) ARCH=DragonFlyBSD ;;
|
dragonfly) ARCH=DragonFlyBSD ;;
|
||||||
freebsd) ARCH=FreeBSD ;;
|
freebsd) ARCH=FreeBSD ;;
|
||||||
@@ -209,6 +212,7 @@ uname_arch() {
|
|||||||
x86) arch="386" ;;
|
x86) arch="386" ;;
|
||||||
i686) arch="386" ;;
|
i686) arch="386" ;;
|
||||||
i386) arch="386" ;;
|
i386) arch="386" ;;
|
||||||
|
ppc64le) arch="ppc64le" ;;
|
||||||
aarch64) arch="arm64" ;;
|
aarch64) arch="arm64" ;;
|
||||||
armv5*) arch="armv5" ;;
|
armv5*) arch="armv5" ;;
|
||||||
armv6*) arch="armv6" ;;
|
armv6*) arch="armv6" ;;
|
||||||
|
|||||||
@@ -185,11 +185,11 @@ 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)
|
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.
|
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
|
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.
|
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
|
Please note that adding the `good first issue` label must also
|
||||||
add the `help wanted` label.
|
add the `help wanted` label.
|
||||||
|
|
||||||
If an issue has these labels but does not satisfy the guidelines, please
|
If an issue has these labels but does not satisfy the guidelines, please
|
||||||
ask for more details to be added to the issue or remove the labels.
|
ask for more details to be added to the issue or remove the labels.
|
||||||
|
|||||||
16
go.mod
16
go.mod
@@ -3,17 +3,19 @@ module github.com/aquasecurity/trivy
|
|||||||
go 1.15
|
go 1.15
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/Masterminds/semver/v3 v3.1.0
|
github.com/aquasecurity/bolt-fixtures v0.0.0-20200903104109-d34e7f983986
|
||||||
github.com/aquasecurity/bolt-fixtures v0.0.0-20200825112230-c0f517aea2ed
|
|
||||||
github.com/aquasecurity/fanal v0.0.0-20200820074632-6de62ef86882
|
github.com/aquasecurity/fanal v0.0.0-20200820074632-6de62ef86882
|
||||||
github.com/aquasecurity/go-dep-parser v0.0.0-20190819075924-ea223f0ef24b
|
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/caarlos0/env/v6 v6.0.0
|
||||||
github.com/cenkalti/backoff v2.2.1+incompatible
|
github.com/cenkalti/backoff v2.2.1+incompatible
|
||||||
github.com/cheggaaa/pb/v3 v3.0.3
|
github.com/cheggaaa/pb/v3 v3.0.3
|
||||||
github.com/docker/docker v1.4.2-0.20190924003213-a8608b5b67c7
|
github.com/docker/docker v1.4.2-0.20190924003213-a8608b5b67c7
|
||||||
github.com/docker/go-connections v0.4.0
|
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-containerregistry v0.0.0-20200331213917-3d03ed9b1ca2
|
||||||
github.com/google/go-github/v28 v28.1.1
|
github.com/google/go-github/v28 v28.1.1
|
||||||
github.com/google/wire v0.3.0
|
github.com/google/wire v0.3.0
|
||||||
@@ -27,11 +29,11 @@ require (
|
|||||||
github.com/stretchr/testify v1.6.1
|
github.com/stretchr/testify v1.6.1
|
||||||
github.com/testcontainers/testcontainers-go v0.3.1
|
github.com/testcontainers/testcontainers-go v0.3.1
|
||||||
github.com/twitchtv/twirp v5.10.1+incompatible
|
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/atomic v1.5.1 // indirect
|
||||||
go.uber.org/multierr v1.4.0 // indirect
|
go.uber.org/multierr v1.4.0 // indirect
|
||||||
go.uber.org/zap v1.13.0
|
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
|
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
354
go.sum
@@ -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.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 h1:ROfEUZz+Gh5pa62DJWXSaonyu3StP6EA6lPEXPI6mCo=
|
||||||
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
|
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 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/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 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8=
|
||||||
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
|
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.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 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.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.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/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.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/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.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0=
|
||||||
github.com/Azure/go-autorest/autorest/mocks v0.2.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.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/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/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/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/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 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
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 h1:wykTgKwhVr2t2qs+xI020s6W5dt614QqCHV+7W9dg64=
|
||||||
github.com/GoogleCloudPlatform/docker-credential-gcr v1.5.0/go.mod h1:BB1eHdMLYEFuFdBlRMb0N7YGVdM5s6Pt0njxgvfbGGs=
|
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/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.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.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
|
||||||
github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5 h1:ygIc8M6trr62pF5DucadTWGdEB4mEyvzi0e2nbcmcyA=
|
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/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 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA=
|
||||||
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
|
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-20200903104109-d34e7f983986 h1:2a30xLN2sUZcMXl50hg+PJCIDdJgIvIbVcKqLJ/ZrtM=
|
||||||
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/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 h1:65VcAKqhkKwMpLr9Wz+wNnsk+U+lv+v/qfOK04uXT3E=
|
||||||
github.com/aquasecurity/fanal v0.0.0-20200820074632-6de62ef86882/go.mod h1:VP1+n6hMi6krpA0umEl0CkJp4hbg0R21kXWg0mjrekc=
|
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 h1:55Ulc/gvfWm4ylhVaR7MxOwujRjA6et7KhmUbSgUFf4=
|
||||||
github.com/aquasecurity/go-dep-parser v0.0.0-20190819075924-ea223f0ef24b/go.mod h1:BpNTD9vHfrejKsED9rx04ldM1WIbeyXGYxUrqTVwxVQ=
|
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 h1:hsw7PpiymXP64evn/K7gsj3hWzMqLrdoeE6JkqDocVg=
|
||||||
github.com/aquasecurity/testdocker v0.0.0-20200426142840-5f05bce6f12a/go.mod h1:psfu0MVaiTDLpNxCoNsTeILSKY2EICBwv345f3M+Ffs=
|
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-20201117092632-b09c30858fc2 h1:AXA9aW464copH1GTKv35yCwztJsqDVZWKfCtBuMpI9U=
|
||||||
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/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 h1:xbdUfr2KE4THsFx9CFWtWpU91lF+YhgP46moV94nYTA=
|
||||||
github.com/aquasecurity/vuln-list-update v0.0.0-20191016075347-3d158c2bf9a2/go.mod h1:6NhOP0CjZJL27bZZcaHECtzWdwDDm2g6yCY0QgXEGQQ=
|
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=
|
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/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||||
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
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/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 v1.11.1 h1:OixPqDEcX3juo5AjQZAnFPbeUA0jvkp2qzB5gOZJ/L0=
|
||||||
github.com/briandowns/spinner v0.0.0-20190319032542-ac46072a5a91/go.mod h1:hw/JEQBIE+c/BLI4aKM8UU8v+ZqrD3h7HC27kKt8JQU=
|
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 h1:NZt6FAoB8ieKO5lEwRdwCzYxWFx7ZYF2R7UcoyaWtyc=
|
||||||
github.com/caarlos0/env/v6 v6.0.0/go.mod h1:+wdyOmtjoZIW2GJOc2OYa5NoOFuWD/bIpWqm30NgtRk=
|
github.com/caarlos0/env/v6 v6.0.0/go.mod h1:+wdyOmtjoZIW2GJOc2OYa5NoOFuWD/bIpWqm30NgtRk=
|
||||||
github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4=
|
github.com/cenkalti/backoff v2.2.1+incompatible 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/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 h1:8WApbyUmgMOz7WIxJVNK0IRDcRfAmTxcEdi0TuxjdP4=
|
||||||
github.com/cheggaaa/pb/v3 v3.0.3/go.mod h1:Pp35CDuiEpHa/ZLGCtBbM6CBwMstv1bJlG884V+73Yc=
|
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/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/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=
|
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/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 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF22jk=
|
||||||
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
|
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-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.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
|
||||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
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=
|
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 v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||||
github.com/dustin/go-humanize v1.0.0/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-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 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-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 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/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 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg=
|
||||||
github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o=
|
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.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/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/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/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.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||||
github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s=
|
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=
|
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-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 h1:k5RWPm4iJwYtfWoxIJy4wJX9ON7ihPeZZYC1fLYDnpg=
|
||||||
github.com/go-git/go-git/v5 v5.0.0/go.mod h1:oYD8y9kWsGINPFJoLdaScGCN6dlKg23blmClfZwtUVA=
|
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-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||||
github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
|
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/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 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
|
||||||
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
|
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.1/go.mod h1:wS4gNoLalDSJxo/SpngzPQ2BN4uuZVLCmbM4S3vd4+Y=
|
||||||
github.com/goccy/go-yaml v1.8.0/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.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.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||||
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
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/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/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-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.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.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-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 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.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.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.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.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 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/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.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.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.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 h1:k2YJ1fw6LwICNNUQHZNp9vTtHMuVqHJtMjZOc5SDIJo=
|
||||||
github.com/google/go-containerregistry v0.0.0-20200331213917-3d03ed9b1ca2/go.mod h1:pD1UFYs7MCAx+ZLShBdttcaOSbyc8F9Na/9IZLNwJeA=
|
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=
|
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 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/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 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-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/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||||
github.com/google/subcommands v1.0.1/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=
|
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=
|
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 h1:imGQZGEVEHpje5056+K+cgdO72p0LQv2xIIFXNGUf60=
|
||||||
github.com/google/wire v0.3.0/go.mod h1:i1DMg/Lu8Sz5yYl25iOdmc5CT5qusaa+zmRWs16741s=
|
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.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.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
|
||||||
github.com/googleapis/gnostic v0.2.2/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/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-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/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 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=
|
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/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 h1:B9UzwGQJehnUY1yNrnwREHc3fGbC2xefo8g4TbElacI=
|
||||||
github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA=
|
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.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.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.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/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/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 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
|
||||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
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/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
|
||||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
|
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.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||||
github.com/json-iterator/go v1.1.8/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.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 h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
|
||||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
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=
|
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.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.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.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.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.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.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.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.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.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.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.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
|
||||||
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
|
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.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.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.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.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/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/maxbrunsfeld/counterfeiter/v6 v6.2.2/go.mod h1:eD9eIE7cdwcMi9rYluz88Jz2VyhSmden33/aXg4oVIY=
|
||||||
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
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.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||||
github.com/sirupsen/logrus v1.5.0 h1:1N5EYkVAPEywqZRJd7cwnRtCb6xJx7NH3T3WUTF980Q=
|
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/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/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 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/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 h1:cVre9QZvsDzS/v42PSOsf+GCaecvb/CWGX+diP232F8=
|
||||||
github.com/sosedoff/gitkit v0.2.0/go.mod h1:A+o6ZazfVJwetlcHz3ah6th66XcBdsyzLo+aBt/AsK4=
|
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/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.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.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.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
||||||
github.com/stretchr/objx v0.3.0 h1:NGXK3lHquSN08v5vWalVI/L8XU9hdzE/G6xsrze47As=
|
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/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 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.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
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.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.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||||
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
|
github.com/stretchr/testify v1.6.1 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 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 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/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.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 h1:JTTnM6wKzdA0Jqodd966MVj4vWbbquZykeX1sKbe2C4=
|
||||||
github.com/urfave/cli/v2 v2.2.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ=
|
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/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/vmware/govmomi v0.20.3/go.mod h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59bHWk6aFU=
|
||||||
github.com/xanzy/ssh-agent v0.2.1 h1:TCbipTQL2JiiCprBWx9frJ2eJlCYT00NmctrHxVAr70=
|
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/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 h1:vVRagRXf67ESqAb72hG2C/ZwI8NtJF2u2V76EsuOHGY=
|
||||||
github.com/yashtewari/glob-intersection v0.0.0-20180916065949-5c77d914dd0b/go.mod h1:HptNXiXVDcJjXe9SqMd0v2FsL9f8dz4GnXgltU6q/co=
|
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.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||||
go.etcd.io/bbolt v1.3.5 h1:XAzx9gjCb0Rxj7EoqcClPD1d5ZBxZJk0jbuoPHenBt0=
|
go.etcd.io/bbolt v1.3.5 h1:XAzx9gjCb0Rxj7EoqcClPD1d5ZBxZJk0jbuoPHenBt0=
|
||||||
go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
|
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.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.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.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.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
||||||
go.uber.org/atomic v1.5.1 h1:rsqfU5vBkVknbhUGbAUwQKR2H4ItV8tjJ+6kJX4cxHM=
|
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-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-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-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-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-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-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-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-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-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de h1:ikNHVSjEfnvz6sxdSPCaPt572qowuyMDMJLLm3Db3ig=
|
golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0 h1:hb9wdF1z5waM+dSIICn1l0DkLVDT3hqhhQsDNUmHPRE=
|
||||||
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
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-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-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-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-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-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-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-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-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-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-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-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-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.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.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-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-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-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-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-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-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-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-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-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-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-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-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-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-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-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-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-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-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-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-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-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-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-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-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 h1:qwRHBd0NqMbJxfbotnDhm2ByMI1Shq4Y6oRJo21SGJA=
|
||||||
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
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=
|
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-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-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-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-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-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-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-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-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-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-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-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-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-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-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-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-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-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-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-20200327173247-9dae0f8f5775/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200824131525-c12d262b63d8 h1:AvbQYmiaaaza3cW3QXRyPo5kYgpFIzOAfeAAN7m3qQ4=
|
golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200824131525-c12d262b63d8/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-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.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.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.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-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-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/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-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-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-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-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-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-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-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-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-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-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-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-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-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-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-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/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=
|
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.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.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.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.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.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-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-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-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-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-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-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.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.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
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.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||||
google.golang.org/grpc v1.23.1/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.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA=
|
||||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
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.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/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 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-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-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-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.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 h1:n1tBJnnK2r7g9OW2btFH91V92STTUevLXYFb8gy9EMk=
|
||||||
gopkg.in/cheggaaa/pb.v1 v1.0.28/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
|
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 h1:xoYuJVE7KT85PYWrN730RguIQO0ePzVRfFMXadIrXTM=
|
||||||
gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
|
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.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.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/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/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=
|
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.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.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.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.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.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
|
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-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-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.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-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/api v0.17.4/go.mod h1:5qxx6vjmwUVG2nHQTKGlLts8Tbok8PzHl4vHtVFuZCA=
|
||||||
k8s.io/apimachinery v0.17.4/go.mod h1:gxLnyZcGNdZTCLnq3fgzyg2A5BVCHTNDFrw8AmuJ+0g=
|
k8s.io/apimachinery v0.17.4/go.mod h1:gxLnyZcGNdZTCLnq3fgzyg2A5BVCHTNDFrw8AmuJ+0g=
|
||||||
k8s.io/apiserver v0.17.4/go.mod h1:5ZDQ6Xr5MNBxyi3iUZXS84QOhZl+W7Oq2us/29c0j9I=
|
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.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 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 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/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/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-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/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/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk=
|
||||||
modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k=
|
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=
|
modernc.org/xc v1.0.0/go.mod h1:mRNCo0bvLjGhHO9WsyuKVU4q0ceiDDDoEeWDJHrNx8I=
|
||||||
moul.io/http2curl v1.0.0 h1:6XwpyZOYsgZJrU8exnG87ncVkU1FVCcTRpwzOkTDUi8=
|
moul.io/http2curl v1.0.0 h1:6XwpyZOYsgZJrU8exnG87ncVkU1FVCcTRpwzOkTDUi8=
|
||||||
moul.io/http2curl v1.0.0/go.mod h1:f6cULg+e4Md/oW1cYmwW4IWQOVl2lGbmCNGOHvzX2kE=
|
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 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/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=
|
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
|
||||||
|
|||||||
@@ -12,11 +12,14 @@ builds:
|
|||||||
goos:
|
goos:
|
||||||
- darwin
|
- darwin
|
||||||
- linux
|
- linux
|
||||||
|
- freebsd
|
||||||
|
- openbsd
|
||||||
goarch:
|
goarch:
|
||||||
- amd64
|
- amd64
|
||||||
- 386
|
- 386
|
||||||
- arm
|
- arm
|
||||||
- arm64
|
- arm64
|
||||||
|
- ppc64le
|
||||||
goarm:
|
goarm:
|
||||||
- 7
|
- 7
|
||||||
ignore:
|
ignore:
|
||||||
@@ -41,6 +44,7 @@ nfpms:
|
|||||||
386: 32bit
|
386: 32bit
|
||||||
arm: ARM
|
arm: ARM
|
||||||
arm64: ARM64
|
arm64: ARM64
|
||||||
|
ppc64le: PPC64LE
|
||||||
darwin: macOS
|
darwin: macOS
|
||||||
linux: Linux
|
linux: Linux
|
||||||
openbsd: OpenBSD
|
openbsd: OpenBSD
|
||||||
@@ -57,6 +61,7 @@ archives:
|
|||||||
386: 32bit
|
386: 32bit
|
||||||
arm: ARM
|
arm: ARM
|
||||||
arm64: ARM64
|
arm64: ARM64
|
||||||
|
ppc64le: PPC64LE
|
||||||
darwin: macOS
|
darwin: macOS
|
||||||
linux: Linux
|
linux: Linux
|
||||||
openbsd: OpenBSD
|
openbsd: OpenBSD
|
||||||
|
|||||||
BIN
imgs/logo.png
BIN
imgs/logo.png
Binary file not shown.
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 8.7 KiB |
BIN
imgs/usage.gif
BIN
imgs/usage.gif
Binary file not shown.
|
Before Width: | Height: | Size: 3.9 MiB After Width: | Height: | Size: 3.6 MiB |
@@ -15,12 +15,14 @@ import (
|
|||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// RegistryConfig holds the config for docker registry
|
||||||
type RegistryConfig struct {
|
type RegistryConfig struct {
|
||||||
URL *url.URL
|
URL *url.URL
|
||||||
Username string
|
Username string
|
||||||
Password string
|
Password string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetAuthConfig returns the docker registry authConfig
|
||||||
func (c RegistryConfig) GetAuthConfig() types.AuthConfig {
|
func (c RegistryConfig) GetAuthConfig() types.AuthConfig {
|
||||||
return types.AuthConfig{
|
return types.AuthConfig{
|
||||||
Username: c.Username,
|
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) {
|
func (c RegistryConfig) GetRegistryAuth() (string, error) {
|
||||||
authConfig := types.AuthConfig{
|
authConfig := types.AuthConfig{
|
||||||
Username: c.Username,
|
Username: c.Username,
|
||||||
@@ -41,10 +44,12 @@ func (c RegistryConfig) GetRegistryAuth() (string, error) {
|
|||||||
return base64.URLEncoding.EncodeToString(encodedJSON), nil
|
return base64.URLEncoding.EncodeToString(encodedJSON), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Docker returns docker client
|
||||||
type Docker struct {
|
type Docker struct {
|
||||||
cli *client.Client
|
cli *client.Client
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// New is the factory method to return docker client
|
||||||
func New() (Docker, error) {
|
func New() (Docker, error) {
|
||||||
cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
|
cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -73,7 +78,7 @@ func (d Docker) ReplicateImage(ctx context.Context, imageRef, imagePath string,
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if _, err := io.Copy(ioutil.Discard, resp.Body); err != nil {
|
if _, err = io.Copy(ioutil.Discard, resp.Body); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|||||||
@@ -7,11 +7,12 @@
|
|||||||
"VulnerabilityID": "RUSTSEC-2019-0001",
|
"VulnerabilityID": "RUSTSEC-2019-0001",
|
||||||
"PkgName": "ammonia",
|
"PkgName": "ammonia",
|
||||||
"InstalledVersion": "1.9.0",
|
"InstalledVersion": "1.9.0",
|
||||||
|
"FixedVersion": "\u003e= 2.1.0",
|
||||||
"Layer": {
|
"Layer": {
|
||||||
"DiffID": "sha256:ea6f6933da66090da8bfe233d68f083792a68f944cd2d8f9fbb52da795813a4f"
|
"DiffID": "sha256:ea6f6933da66090da8bfe233d68f083792a68f944cd2d8f9fbb52da795813a4f"
|
||||||
},
|
},
|
||||||
"Title": "Uncontrolled recursion leads to abort in HTML serialization",
|
"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",
|
"Severity": "UNKNOWN",
|
||||||
"References": [
|
"References": [
|
||||||
"https://github.com/rust-ammonia/ammonia/blob/master/CHANGELOG.md#210"
|
"https://github.com/rust-ammonia/ammonia/blob/master/CHANGELOG.md#210"
|
||||||
@@ -21,53 +22,72 @@
|
|||||||
"VulnerabilityID": "RUSTSEC-2016-0001",
|
"VulnerabilityID": "RUSTSEC-2016-0001",
|
||||||
"PkgName": "openssl",
|
"PkgName": "openssl",
|
||||||
"InstalledVersion": "0.8.3",
|
"InstalledVersion": "0.8.3",
|
||||||
|
"FixedVersion": "\u003e= 0.9.0",
|
||||||
"Layer": {
|
"Layer": {
|
||||||
"DiffID": "sha256:ea6f6933da66090da8bfe233d68f083792a68f944cd2d8f9fbb52da795813a4f"
|
"DiffID": "sha256:ea6f6933da66090da8bfe233d68f083792a68f944cd2d8f9fbb52da795813a4f"
|
||||||
},
|
},
|
||||||
"Title": "SSL/TLS MitM vulnerability due to insecure defaults",
|
"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",
|
"Severity": "UNKNOWN",
|
||||||
"References": [
|
"References": [
|
||||||
"https://github.com/sfackler/rust-openssl/releases/tag/v0.9.0"
|
"https://github.com/sfackler/rust-openssl/releases/tag/v0.9.0"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"VulnerabilityID": "RUSTSEC-2018-0010",
|
"VulnerabilityID": "RUSTSEC-2019-0035",
|
||||||
"PkgName": "openssl",
|
"PkgName": "rand_core",
|
||||||
"InstalledVersion": "0.8.3",
|
"InstalledVersion": "0.3.1",
|
||||||
|
"FixedVersion": "\u003e= 0.4.2",
|
||||||
"Layer": {
|
"Layer": {
|
||||||
"DiffID": "sha256:ea6f6933da66090da8bfe233d68f083792a68f944cd2d8f9fbb52da795813a4f"
|
"DiffID": "sha256:ea6f6933da66090da8bfe233d68f083792a68f944cd2d8f9fbb52da795813a4f"
|
||||||
},
|
},
|
||||||
"Title": "Use after free in CMS Signing",
|
"Title": "Unaligned memory access",
|
||||||
"Description": "Affected versions of the OpenSSL crate used structures after they'd been freed.",
|
"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",
|
"Severity": "UNKNOWN",
|
||||||
"References": [
|
"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",
|
"VulnerabilityID": "RUSTSEC-2019-0035",
|
||||||
"PkgName": "smallvec",
|
"PkgName": "rand_core",
|
||||||
"InstalledVersion": "0.6.9",
|
"InstalledVersion": "0.4.0",
|
||||||
|
"FixedVersion": "\u003e= 0.4.2",
|
||||||
"Layer": {
|
"Layer": {
|
||||||
"DiffID": "sha256:ea6f6933da66090da8bfe233d68f083792a68f944cd2d8f9fbb52da795813a4f"
|
"DiffID": "sha256:ea6f6933da66090da8bfe233d68f083792a68f944cd2d8f9fbb52da795813a4f"
|
||||||
},
|
},
|
||||||
"Title": "Possible double free during unwinding in SmallVec::insert_many",
|
"Title": "Unaligned memory access",
|
||||||
"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",
|
"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",
|
"Severity": "UNKNOWN",
|
||||||
"References": [
|
"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",
|
"VulnerabilityID": "RUSTSEC-2019-0009",
|
||||||
"PkgName": "smallvec",
|
"PkgName": "smallvec",
|
||||||
"InstalledVersion": "0.6.9",
|
"InstalledVersion": "0.6.9",
|
||||||
|
"FixedVersion": "\u003e= 0.6.10",
|
||||||
"Layer": {
|
"Layer": {
|
||||||
"DiffID": "sha256:ea6f6933da66090da8bfe233d68f083792a68f944cd2d8f9fbb52da795813a4f"
|
"DiffID": "sha256:ea6f6933da66090da8bfe233d68f083792a68f944cd2d8f9fbb52da795813a4f"
|
||||||
},
|
},
|
||||||
"Title": "Double-free and use-after-free in SmallVec::grow()",
|
"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",
|
"Severity": "UNKNOWN",
|
||||||
"References": [
|
"References": [
|
||||||
"https://github.com/servo/rust-smallvec/issues/148"
|
"https://github.com/servo/rust-smallvec/issues/148"
|
||||||
@@ -77,15 +97,30 @@
|
|||||||
"VulnerabilityID": "RUSTSEC-2019-0012",
|
"VulnerabilityID": "RUSTSEC-2019-0012",
|
||||||
"PkgName": "smallvec",
|
"PkgName": "smallvec",
|
||||||
"InstalledVersion": "0.6.9",
|
"InstalledVersion": "0.6.9",
|
||||||
|
"FixedVersion": "\u003e= 0.6.10",
|
||||||
"Layer": {
|
"Layer": {
|
||||||
"DiffID": "sha256:ea6f6933da66090da8bfe233d68f083792a68f944cd2d8f9fbb52da795813a4f"
|
"DiffID": "sha256:ea6f6933da66090da8bfe233d68f083792a68f944cd2d8f9fbb52da795813a4f"
|
||||||
},
|
},
|
||||||
"Title": "Memory corruption in SmallVec::grow()",
|
"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",
|
"Severity": "UNKNOWN",
|
||||||
"References": [
|
"References": [
|
||||||
"https://github.com/servo/rust-smallvec/issues/149"
|
"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"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
BIN
integration/testdata/trivy.db.gz
vendored
BIN
integration/testdata/trivy.db.gz
vendored
Binary file not shown.
@@ -20,6 +20,7 @@ import (
|
|||||||
"github.com/aquasecurity/trivy/pkg/vulnerability"
|
"github.com/aquasecurity/trivy/pkg/vulnerability"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// VersionInfo holds the trivy DB version Info
|
||||||
type VersionInfo struct {
|
type VersionInfo struct {
|
||||||
Version string `json:",omitempty"`
|
Version string `json:",omitempty"`
|
||||||
VulnerabilityDB *db.Metadata `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 {
|
func NewApp(version string) *cli.App {
|
||||||
cli.VersionPrinter = func(c *cli.Context) {
|
cli.VersionPrinter = func(c *cli.Context) {
|
||||||
showVersion(c.String("cache-dir"), c.String("format"), c.App.Version, c.App.Writer)
|
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) {
|
func showVersion(cacheDir, outputFormat, version string, outputWriter io.Writer) {
|
||||||
var dbMeta *db.Metadata
|
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 {
|
if !metadata.UpdatedAt.IsZero() && !metadata.NextUpdate.IsZero() && metadata.Version != 0 {
|
||||||
dbMeta = &db.Metadata{
|
dbMeta = &db.Metadata{
|
||||||
Version: metadata.Version,
|
Version: metadata.Version,
|
||||||
Type: metadata.Type,
|
Type: metadata.Type,
|
||||||
NextUpdate: metadata.NextUpdate.UTC(),
|
NextUpdate: metadata.NextUpdate.UTC(),
|
||||||
UpdatedAt: metadata.UpdatedAt.UTC(),
|
UpdatedAt: metadata.UpdatedAt.UTC(),
|
||||||
|
DownloadedAt: metadata.DownloadedAt.UTC(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch outputFormat {
|
switch outputFormat {
|
||||||
case "json":
|
case "json":
|
||||||
b, _ := json.Marshal(VersionInfo{
|
b, _ := json.Marshal(VersionInfo{ // nolint: errcheck
|
||||||
Version: version,
|
Version: version,
|
||||||
VulnerabilityDB: dbMeta,
|
VulnerabilityDB: dbMeta,
|
||||||
})
|
})
|
||||||
@@ -339,12 +342,14 @@ func showVersion(cacheDir, outputFormat, version string, outputWriter io.Writer)
|
|||||||
Version: %d
|
Version: %d
|
||||||
UpdatedAt: %s
|
UpdatedAt: %s
|
||||||
NextUpdate: %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)
|
fmt.Fprintf(outputWriter, output)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewImageCommand is the factory method to add image command
|
||||||
func NewImageCommand() *cli.Command {
|
func NewImageCommand() *cli.Command {
|
||||||
return &cli.Command{
|
return &cli.Command{
|
||||||
Name: "image",
|
Name: "image",
|
||||||
@@ -356,6 +361,7 @@ func NewImageCommand() *cli.Command {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewFilesystemCommand is the factory method to add filesystem command
|
||||||
func NewFilesystemCommand() *cli.Command {
|
func NewFilesystemCommand() *cli.Command {
|
||||||
return &cli.Command{
|
return &cli.Command{
|
||||||
Name: "filesystem",
|
Name: "filesystem",
|
||||||
@@ -389,6 +395,7 @@ func NewFilesystemCommand() *cli.Command {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewRepositoryCommand is the factory method to add repository command
|
||||||
func NewRepositoryCommand() *cli.Command {
|
func NewRepositoryCommand() *cli.Command {
|
||||||
return &cli.Command{
|
return &cli.Command{
|
||||||
Name: "repository",
|
Name: "repository",
|
||||||
@@ -422,6 +429,7 @@ func NewRepositoryCommand() *cli.Command {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewClientCommand is the factory method to add client command
|
||||||
func NewClientCommand() *cli.Command {
|
func NewClientCommand() *cli.Command {
|
||||||
return &cli.Command{
|
return &cli.Command{
|
||||||
Name: "client",
|
Name: "client",
|
||||||
@@ -465,6 +473,7 @@ func NewClientCommand() *cli.Command {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewServerCommand is the factory method to add server command
|
||||||
func NewServerCommand() *cli.Command {
|
func NewServerCommand() *cli.Command {
|
||||||
return &cli.Command{
|
return &cli.Command{
|
||||||
Name: "server",
|
Name: "server",
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ Vulnerability DB:
|
|||||||
Version: 42
|
Version: 42
|
||||||
UpdatedAt: 2020-03-16 23:40:20 +0000 UTC
|
UpdatedAt: 2020-03-16 23:40:20 +0000 UTC
|
||||||
NextUpdate: 2020-03-16 23:57:00 +0000 UTC
|
NextUpdate: 2020-03-16 23:57:00 +0000 UTC
|
||||||
|
DownloadedAt: 2020-03-16 23:40:20 +0000 UTC
|
||||||
`,
|
`,
|
||||||
createDB: true,
|
createDB: true,
|
||||||
},
|
},
|
||||||
@@ -51,7 +52,7 @@ Vulnerability DB:
|
|||||||
outputFormat: "json",
|
outputFormat: "json",
|
||||||
version: "1.2.3",
|
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,
|
createDB: true,
|
||||||
},
|
},
|
||||||
@@ -93,10 +94,11 @@ Vulnerability DB:
|
|||||||
metadataFile := filepath.Join(cacheDir, "db", "metadata.json")
|
metadataFile := filepath.Join(cacheDir, "db", "metadata.json")
|
||||||
|
|
||||||
b, err := json.Marshal(db.Metadata{
|
b, err := json.Marshal(db.Metadata{
|
||||||
Version: 42,
|
Version: 42,
|
||||||
Type: 1,
|
Type: 1,
|
||||||
NextUpdate: time.Unix(1584403020, 0),
|
NextUpdate: time.Unix(1584403020, 0),
|
||||||
UpdatedAt: time.Unix(1584402020, 0),
|
UpdatedAt: time.Unix(1584402020, 0),
|
||||||
|
DownloadedAt: time.Unix(1584402020, 0),
|
||||||
})
|
})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
err = afero.WriteFile(fs, metadataFile, b, 0600)
|
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()
|
||||||
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
"github.com/aquasecurity/trivy/internal/config"
|
"github.com/aquasecurity/trivy/internal/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Config holds the artifact config
|
||||||
type Config struct {
|
type Config struct {
|
||||||
config.GlobalConfig
|
config.GlobalConfig
|
||||||
config.ArtifactConfig
|
config.ArtifactConfig
|
||||||
@@ -22,6 +23,7 @@ type Config struct {
|
|||||||
autoRefresh bool
|
autoRefresh bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// New is the factory method to return config
|
||||||
func New(c *cli.Context) (Config, error) {
|
func New(c *cli.Context) (Config, error) {
|
||||||
gc, err := config.NewGlobalConfig(c)
|
gc, err := config.NewGlobalConfig(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -41,6 +43,7 @@ func New(c *cli.Context) (Config, error) {
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Init initializes the artifact config
|
||||||
func (c *Config) Init(image bool) error {
|
func (c *Config) Init(image bool) error {
|
||||||
if err := c.ReportConfig.Init(c.Logger); err != nil {
|
if err := c.ReportConfig.Init(c.Logger); err != nil {
|
||||||
return err
|
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
|
// --clear-cache, --download-db-only and --reset don't conduct the scan
|
||||||
if c.ClearCache || c.DownloadDBOnly || c.Reset {
|
if c.skipScan() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -69,3 +72,10 @@ func (c *Config) Init(image bool) error {
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Config) skipScan() bool {
|
||||||
|
if c.ClearCache || c.DownloadDBOnly || c.Reset {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ func filesystemScanner(ctx context.Context, dir string, ac cache.ArtifactCache,
|
|||||||
return s, cleanup, nil
|
return s, cleanup, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FilesystemRun runs scan on filesystem
|
||||||
func FilesystemRun(cliCtx *cli.Context) error {
|
func FilesystemRun(cliCtx *cli.Context) error {
|
||||||
c, err := config.New(cliCtx)
|
c, err := config.New(cliCtx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ func dockerScanner(ctx context.Context, imageName string, ac cache.ArtifactCache
|
|||||||
return s, cleanup, nil
|
return s, cleanup, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ImageRun runs scan on docker image
|
||||||
func ImageRun(cliCtx *cli.Context) error {
|
func ImageRun(cliCtx *cli.Context) error {
|
||||||
c, err := config.New(cliCtx)
|
c, err := config.New(cliCtx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ func repositoryScanner(ctx context.Context, dir string, ac cache.ArtifactCache,
|
|||||||
return s, cleanup, nil
|
return s, cleanup, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RepositoryRun runs scan on repository
|
||||||
func RepositoryRun(cliCtx *cli.Context) error {
|
func RepositoryRun(cliCtx *cli.Context) error {
|
||||||
c, err := config.New(cliCtx)
|
c, err := config.New(cliCtx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -19,9 +19,12 @@ import (
|
|||||||
"github.com/aquasecurity/trivy/pkg/utils"
|
"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) (
|
type InitializeScanner func(context.Context, string, cache.ArtifactCache, cache.LocalArtifactCache, time.Duration) (
|
||||||
scanner.Scanner, func(), error)
|
scanner.Scanner, func(), error)
|
||||||
|
|
||||||
|
// nolint: gocyclo
|
||||||
|
// TODO: refactror and fix cyclometic complexity
|
||||||
func run(c config.Config, initializeScanner InitializeScanner) error {
|
func run(c config.Config, initializeScanner InitializeScanner) error {
|
||||||
if err := log.InitLogger(c.Debug, c.Quiet); err != nil {
|
if err := log.InitLogger(c.Debug, c.Quiet); err != nil {
|
||||||
l.Fatal(err)
|
l.Fatal(err)
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import (
|
|||||||
"github.com/aquasecurity/trivy/internal/config"
|
"github.com/aquasecurity/trivy/internal/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Config holds the Trivy client config
|
||||||
type Config struct {
|
type Config struct {
|
||||||
config.GlobalConfig
|
config.GlobalConfig
|
||||||
config.ArtifactConfig
|
config.ArtifactConfig
|
||||||
@@ -25,6 +26,7 @@ type Config struct {
|
|||||||
CustomHeaders http.Header
|
CustomHeaders http.Header
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// New is the factory method for Config
|
||||||
func New(c *cli.Context) (Config, error) {
|
func New(c *cli.Context) (Config, error) {
|
||||||
gc, err := config.NewGlobalConfig(c)
|
gc, err := config.NewGlobalConfig(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -43,6 +45,7 @@ func New(c *cli.Context) (Config, error) {
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Init initializes the config
|
||||||
func (c *Config) Init() (err error) {
|
func (c *Config) Init() (err error) {
|
||||||
// --clear-cache doesn't conduct the scan
|
// --clear-cache doesn't conduct the scan
|
||||||
if c.ClearCache {
|
if c.ClearCache {
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import (
|
|||||||
"github.com/aquasecurity/trivy/pkg/utils"
|
"github.com/aquasecurity/trivy/pkg/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Run runs the scan
|
||||||
func Run(cliCtx *cli.Context) error {
|
func Run(cliCtx *cli.Context) error {
|
||||||
c, err := config.New(cliCtx)
|
c, err := config.New(cliCtx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -25,6 +26,8 @@ func Run(cliCtx *cli.Context) error {
|
|||||||
return run(c)
|
return run(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// nolint: gocyclo
|
||||||
|
// TODO: refactror and fix cyclometic complexity
|
||||||
func run(c config.Config) (err error) {
|
func run(c config.Config) (err error) {
|
||||||
if err = log.InitLogger(c.Debug, c.Quiet); err != nil {
|
if err = log.InitLogger(c.Debug, c.Quiet); err != nil {
|
||||||
return xerrors.Errorf("failed to initialize a logger: %w", err)
|
return xerrors.Errorf("failed to initialize a logger: %w", err)
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import (
|
|||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// ArtifactConfig holds the config for a artifact scanning
|
||||||
type ArtifactConfig struct {
|
type ArtifactConfig struct {
|
||||||
Input string
|
Input string
|
||||||
Timeout time.Duration
|
Timeout time.Duration
|
||||||
@@ -24,6 +25,7 @@ type ArtifactConfig struct {
|
|||||||
Target string
|
Target string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewArtifactConfig is the factory method to return artifact config
|
||||||
func NewArtifactConfig(c *cli.Context) ArtifactConfig {
|
func NewArtifactConfig(c *cli.Context) ArtifactConfig {
|
||||||
return ArtifactConfig{
|
return ArtifactConfig{
|
||||||
Input: c.String("input"),
|
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) {
|
func (c *ArtifactConfig) Init(ctx *cli.Context, logger *zap.SugaredLogger) (err error) {
|
||||||
if c.Input == "" && ctx.Args().Len() == 0 {
|
if c.Input == "" && ctx.Args().Len() == 0 {
|
||||||
logger.Debug(`trivy requires at least 1 argument or --input option`)
|
logger.Debug(`trivy requires at least 1 argument or --input option`)
|
||||||
_ = cli.ShowSubcommandHelp(ctx)
|
_ = cli.ShowSubcommandHelp(ctx) // nolint: errcheck
|
||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
} else if ctx.Args().Len() > 1 {
|
} else if ctx.Args().Len() > 1 {
|
||||||
logger.Error(`multiple targets cannot be specified`)
|
logger.Error(`multiple targets cannot be specified`)
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// DBConfig holds the config for trivy DB
|
||||||
type DBConfig struct {
|
type DBConfig struct {
|
||||||
Reset bool
|
Reset bool
|
||||||
DownloadDBOnly bool
|
DownloadDBOnly bool
|
||||||
@@ -13,6 +14,7 @@ type DBConfig struct {
|
|||||||
NoProgress bool
|
NoProgress bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewDBConfig is the factory method to return the DBConfig
|
||||||
func NewDBConfig(c *cli.Context) DBConfig {
|
func NewDBConfig(c *cli.Context) DBConfig {
|
||||||
return DBConfig{
|
return DBConfig{
|
||||||
Reset: c.Bool("reset"),
|
Reset: c.Bool("reset"),
|
||||||
@@ -23,6 +25,7 @@ func NewDBConfig(c *cli.Context) DBConfig {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Init initialize the DBConfig
|
||||||
func (c *DBConfig) Init() (err error) {
|
func (c *DBConfig) Init() (err error) {
|
||||||
if c.SkipUpdate && c.DownloadDBOnly {
|
if c.SkipUpdate && c.DownloadDBOnly {
|
||||||
return xerrors.New("--skip-update and --download-db-only options can not be specified both")
|
return xerrors.New("--skip-update and --download-db-only options can not be specified both")
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import (
|
|||||||
"github.com/aquasecurity/trivy/pkg/log"
|
"github.com/aquasecurity/trivy/pkg/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// GlobalConfig holds the global config for trivy
|
||||||
type GlobalConfig struct {
|
type GlobalConfig struct {
|
||||||
Context *cli.Context
|
Context *cli.Context
|
||||||
Logger *zap.SugaredLogger
|
Logger *zap.SugaredLogger
|
||||||
@@ -18,6 +19,7 @@ type GlobalConfig struct {
|
|||||||
CacheDir string
|
CacheDir string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewGlobalConfig is the factory method to return GlobalConfig
|
||||||
func NewGlobalConfig(c *cli.Context) (GlobalConfig, error) {
|
func NewGlobalConfig(c *cli.Context) (GlobalConfig, error) {
|
||||||
quiet := c.Bool("quiet")
|
quiet := c.Bool("quiet")
|
||||||
debug := c.Bool("debug")
|
debug := c.Bool("debug")
|
||||||
|
|||||||
@@ -7,11 +7,13 @@ import (
|
|||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// ImageConfig holds the config for scanning images
|
||||||
type ImageConfig struct {
|
type ImageConfig struct {
|
||||||
ScanRemovedPkgs bool
|
ScanRemovedPkgs bool
|
||||||
ListAllPkgs bool
|
ListAllPkgs bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewImageConfig is the factory method to return imageConfig
|
||||||
func NewImageConfig(c *cli.Context) ImageConfig {
|
func NewImageConfig(c *cli.Context) ImageConfig {
|
||||||
return ImageConfig{
|
return ImageConfig{
|
||||||
ScanRemovedPkgs: c.Bool("removed-pkgs"),
|
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) {
|
func (c *ImageConfig) Init(args cli.Args, logger *zap.SugaredLogger) (err error) {
|
||||||
imageName := args.First()
|
imageName := args.First()
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import (
|
|||||||
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
|
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// ReportConfig holds the config for reporting scan results
|
||||||
type ReportConfig struct {
|
type ReportConfig struct {
|
||||||
Format string
|
Format string
|
||||||
Template string
|
Template string
|
||||||
@@ -31,6 +32,7 @@ type ReportConfig struct {
|
|||||||
Severities []dbTypes.Severity
|
Severities []dbTypes.Severity
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewReportConfig is the factory method to return ReportConfig
|
||||||
func NewReportConfig(c *cli.Context) ReportConfig {
|
func NewReportConfig(c *cli.Context) ReportConfig {
|
||||||
return ReportConfig{
|
return ReportConfig{
|
||||||
output: c.String("output"),
|
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) {
|
func (c *ReportConfig) Init(logger *zap.SugaredLogger) (err error) {
|
||||||
if c.Template != "" {
|
if c.Template != "" {
|
||||||
if c.Format == "" {
|
if c.Format == "" {
|
||||||
|
|||||||
@@ -15,20 +15,24 @@ import (
|
|||||||
"github.com/aquasecurity/trivy/pkg/utils"
|
"github.com/aquasecurity/trivy/pkg/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// SuperSet binds cache dependencies
|
||||||
var SuperSet = wire.NewSet(
|
var SuperSet = wire.NewSet(
|
||||||
cache.NewFSCache,
|
cache.NewFSCache,
|
||||||
wire.Bind(new(cache.LocalArtifactCache), new(cache.FSCache)),
|
wire.Bind(new(cache.LocalArtifactCache), new(cache.FSCache)),
|
||||||
NewCache,
|
NewCache,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Cache implements the local cache
|
||||||
type Cache struct {
|
type Cache struct {
|
||||||
client cache.LocalArtifactCache
|
client cache.LocalArtifactCache
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewCache is the factory method for Cache
|
||||||
func NewCache(client cache.LocalArtifactCache) Cache {
|
func NewCache(client cache.LocalArtifactCache) Cache {
|
||||||
return Cache{client: client}
|
return Cache{client: client}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reset resets the cache
|
||||||
func (c Cache) Reset() (err error) {
|
func (c Cache) Reset() (err error) {
|
||||||
if err := c.ClearDB(); err != nil {
|
if err := c.ClearDB(); err != nil {
|
||||||
return xerrors.Errorf("failed to clear the database: %w", err)
|
return xerrors.Errorf("failed to clear the database: %w", err)
|
||||||
@@ -39,6 +43,7 @@ func (c Cache) Reset() (err error) {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ClearDB clears the DB cache
|
||||||
func (c Cache) ClearDB() (err error) {
|
func (c Cache) ClearDB() (err error) {
|
||||||
log.Logger.Info("Removing DB file...")
|
log.Logger.Info("Removing DB file...")
|
||||||
if err = os.RemoveAll(utils.CacheDir()); err != nil {
|
if err = os.RemoveAll(utils.CacheDir()); err != nil {
|
||||||
@@ -47,6 +52,7 @@ func (c Cache) ClearDB() (err error) {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ClearImages clears the cache images
|
||||||
func (c Cache) ClearImages() error {
|
func (c Cache) ClearImages() error {
|
||||||
log.Logger.Info("Removing image caches...")
|
log.Logger.Info("Removing image caches...")
|
||||||
if err := c.client.Clear(); err != nil {
|
if err := c.client.Clear(); err != nil {
|
||||||
@@ -55,6 +61,7 @@ func (c Cache) ClearImages() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DownloadDB downloads the DB
|
||||||
func DownloadDB(appVersion, cacheDir string, quiet, light, skipUpdate bool) error {
|
func DownloadDB(appVersion, cacheDir string, quiet, light, skipUpdate bool) error {
|
||||||
client := initializeDBClient(cacheDir, quiet)
|
client := initializeDBClient(cacheDir, quiet)
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
@@ -66,7 +73,7 @@ func DownloadDB(appVersion, cacheDir string, quiet, light, skipUpdate bool) erro
|
|||||||
if needsUpdate {
|
if needsUpdate {
|
||||||
log.Logger.Info("Need to update DB")
|
log.Logger.Info("Need to update DB")
|
||||||
log.Logger.Info("Downloading 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)
|
return xerrors.Errorf("failed to download vulnerability DB: %w", err)
|
||||||
}
|
}
|
||||||
if err = client.UpdateMetadata(cacheDir); err != nil {
|
if err = client.UpdateMetadata(cacheDir); err != nil {
|
||||||
@@ -87,7 +94,7 @@ func showDBInfo(cacheDir string) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return xerrors.Errorf("something wrong with DB: %w", err)
|
return xerrors.Errorf("something wrong with DB: %w", err)
|
||||||
}
|
}
|
||||||
log.Logger.Debugf("DB Schema: %d, Type: %d, UpdatedAt: %s, NextUpdate: %s",
|
log.Logger.Debugf("DB Schema: %d, Type: %d, UpdatedAt: %s, NextUpdate: %s, DownloadedAt: %s",
|
||||||
metadata.Version, metadata.Type, metadata.UpdatedAt, metadata.NextUpdate)
|
metadata.Version, metadata.Type, metadata.UpdatedAt, metadata.NextUpdate, metadata.DownloadedAt)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
package config
|
package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/aquasecurity/trivy/internal/config"
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
|
|
||||||
|
"github.com/aquasecurity/trivy/internal/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Config holds the Trivy config
|
||||||
type Config struct {
|
type Config struct {
|
||||||
config.GlobalConfig
|
config.GlobalConfig
|
||||||
config.DBConfig
|
config.DBConfig
|
||||||
@@ -14,10 +16,10 @@ type Config struct {
|
|||||||
TokenHeader string
|
TokenHeader string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// New is the factory method to return cofig
|
||||||
func New(c *cli.Context) Config {
|
func New(c *cli.Context) Config {
|
||||||
// the error is ignored because logger is unnecessary
|
// the error is ignored because logger is unnecessary
|
||||||
gc, _ := config.NewGlobalConfig(c)
|
gc, _ := config.NewGlobalConfig(c) // nolint: errcheck
|
||||||
|
|
||||||
return Config{
|
return Config{
|
||||||
GlobalConfig: gc,
|
GlobalConfig: gc,
|
||||||
DBConfig: config.NewDBConfig(c),
|
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) {
|
func (c *Config) Init() (err error) {
|
||||||
if err := c.DBConfig.Init(); err != nil {
|
if err := c.DBConfig.Init(); err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import (
|
|||||||
"github.com/aquasecurity/trivy/pkg/utils"
|
"github.com/aquasecurity/trivy/pkg/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Run runs the scan
|
||||||
func Run(ctx *cli.Context) error {
|
func Run(ctx *cli.Context) error {
|
||||||
return run(config.New(ctx))
|
return run(config.New(ctx))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ func debianEOL() {
|
|||||||
if len(fields) < 6 && fields[0] != "" {
|
if len(fields) < 6 && fields[0] != "" {
|
||||||
fmt.Printf("\"%s\": time.Date(3000, 1, 1, 23, 59, 59, 0, time.UTC),\n", fields[0])
|
fmt.Printf("\"%s\": time.Date(3000, 1, 1, 23, 59, 59, 0, time.UTC),\n", fields[0])
|
||||||
} else if len(fields) == 6 {
|
} 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())
|
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() {
|
for scanner.Scan() {
|
||||||
line := scanner.Text()
|
line := scanner.Text()
|
||||||
fields := strings.Split(line, ",")
|
fields := strings.Split(line, ",")
|
||||||
|
eol, _ := time.Parse("2006-1-2", fields[len(fields)-1]) // nolint: errcheck
|
||||||
eol, _ := time.Parse("2006-1-2", fields[len(fields)-1])
|
|
||||||
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())
|
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
10
pkg/cache/remote.go
vendored
@@ -13,35 +13,41 @@ import (
|
|||||||
rpcCache "github.com/aquasecurity/trivy/rpc/cache"
|
rpcCache "github.com/aquasecurity/trivy/rpc/cache"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// RemoteCache implements remote cache
|
||||||
type RemoteCache struct {
|
type RemoteCache struct {
|
||||||
ctx context.Context // for custom header
|
ctx context.Context // for custom header
|
||||||
client rpcCache.Cache
|
client rpcCache.Cache
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RemoteURL to hold remote host
|
||||||
type RemoteURL string
|
type RemoteURL string
|
||||||
|
|
||||||
|
// NewRemoteCache is the factory method for RemoteCache
|
||||||
func NewRemoteCache(url RemoteURL, customHeaders http.Header) cache.ArtifactCache {
|
func NewRemoteCache(url RemoteURL, customHeaders http.Header) cache.ArtifactCache {
|
||||||
ctx := client.WithCustomHeaders(context.Background(), customHeaders)
|
ctx := client.WithCustomHeaders(context.Background(), customHeaders)
|
||||||
c := rpcCache.NewCacheProtobufClient(string(url), &http.Client{})
|
c := rpcCache.NewCacheProtobufClient(string(url), &http.Client{})
|
||||||
return &RemoteCache{ctx: ctx, client: c}
|
return &RemoteCache{ctx: ctx, client: c}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PutArtifact sends artifact to remote client
|
||||||
func (c RemoteCache) PutArtifact(imageID string, imageInfo types.ArtifactInfo) error {
|
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 {
|
if err != nil {
|
||||||
return xerrors.Errorf("unable to store cache on the server: %w", err)
|
return xerrors.Errorf("unable to store cache on the server: %w", err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PutBlob sends blobInfo to remote client
|
||||||
func (c RemoteCache) PutBlob(diffID string, layerInfo types.BlobInfo) error {
|
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 {
|
if err != nil {
|
||||||
return xerrors.Errorf("unable to store cache on the server: %w", err)
|
return xerrors.Errorf("unable to store cache on the server: %w", err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MissingBlobs fetches missing blobs from RemoteCache
|
||||||
func (c RemoteCache) MissingBlobs(imageID string, layerIDs []string) (bool, []string, error) {
|
func (c RemoteCache) MissingBlobs(imageID string, layerIDs []string) (bool, []string, error) {
|
||||||
layers, err := c.client.MissingBlobs(c.ctx, rpc.ConvertToMissingBlobsRequest(imageID, layerIDs))
|
layers, err := c.client.MissingBlobs(c.ctx, rpc.ConvertToMissingBlobsRequest(imageID, layerIDs))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
70
pkg/db/db.go
70
pkg/db/db.go
@@ -7,6 +7,7 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/google/wire"
|
"github.com/google/wire"
|
||||||
"github.com/spf13/afero"
|
"github.com/spf13/afero"
|
||||||
@@ -24,8 +25,11 @@ const (
|
|||||||
lightDB = "trivy-light.db.gz"
|
lightDB = "trivy-light.db.gz"
|
||||||
|
|
||||||
metadataFile = "metadata.json"
|
metadataFile = "metadata.json"
|
||||||
|
|
||||||
|
gb = 1024 * 1024 * 1024
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// SuperSet binds the dependencies
|
||||||
var SuperSet = wire.NewSet(
|
var SuperSet = wire.NewSet(
|
||||||
// indicator.ProgressBar
|
// indicator.ProgressBar
|
||||||
indicator.NewProgressBar,
|
indicator.NewProgressBar,
|
||||||
@@ -51,6 +55,7 @@ var SuperSet = wire.NewSet(
|
|||||||
wire.Bind(new(Operation), new(Client)),
|
wire.Bind(new(Operation), new(Client)),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Operation defines the DB operations
|
||||||
type Operation interface {
|
type Operation interface {
|
||||||
NeedsUpdate(cliVersion string, skip, light bool) (need bool, err error)
|
NeedsUpdate(cliVersion string, skip, light bool) (need bool, err error)
|
||||||
Download(ctx context.Context, cacheDir string, light 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)
|
StoreMetadata(metadata db.Metadata, dir string) (err error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Client implements DB operations
|
||||||
type Client struct {
|
type Client struct {
|
||||||
dbc dbOperation
|
dbc dbOperation
|
||||||
githubClient github.Operation
|
githubClient github.Operation
|
||||||
@@ -70,6 +76,7 @@ type Client struct {
|
|||||||
metadata Metadata
|
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 {
|
func NewClient(dbc dbOperation, githubClient github.Operation, pb indicator.ProgressBar, clock clock.Clock, metadata Metadata) Client {
|
||||||
return Client{
|
return Client{
|
||||||
dbc: dbc,
|
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) {
|
func (c Client) NeedsUpdate(cliVersion string, light, skip bool) (bool, error) {
|
||||||
dbType := db.TypeFull
|
dbType := db.TypeFull
|
||||||
if light {
|
if light {
|
||||||
@@ -103,28 +111,48 @@ func (c Client) NeedsUpdate(cliVersion string, light, skip bool) (bool, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if skip {
|
if skip {
|
||||||
if db.SchemaVersion != metadata.Version {
|
if err = c.validate(dbType, metadata); err != nil {
|
||||||
log.Logger.Error("The local DB is old and needs to be updated")
|
return false, err
|
||||||
return false, 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 false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if db.SchemaVersion == metadata.Version && metadata.Type == dbType &&
|
if db.SchemaVersion != metadata.Version || metadata.Type != dbType {
|
||||||
c.clock.Now().Before(metadata.NextUpdate) {
|
return true, nil
|
||||||
log.Logger.Debug("DB update was skipped because DB is the latest")
|
|
||||||
return false, nil
|
|
||||||
}
|
}
|
||||||
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 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 xerrors.New("--skip-update cannot be specified with the different schema DB")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
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 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 {
|
func (c Client) Download(ctx context.Context, cacheDir string, light bool) error {
|
||||||
// Remove the metadata file before downloading DB
|
// Remove the metadata file before downloading DB
|
||||||
if err := c.metadata.Delete(); err != nil {
|
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))
|
bar := c.pb.Start(int64(size))
|
||||||
barReader := bar.NewProxyReader(rc)
|
barReader := bar.NewProxyReader(rc)
|
||||||
defer bar.Finish()
|
defer bar.Finish()
|
||||||
|
|
||||||
gr, err := gzip.NewReader(barReader)
|
gr, err := gzip.NewReader(barReader)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return xerrors.Errorf("invalid gzip file: %w", err)
|
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()
|
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 xerrors.Errorf("failed to save DB file: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UpdateMetadata updates the DB metadata
|
||||||
func (c Client) UpdateMetadata(cacheDir string) error {
|
func (c Client) UpdateMetadata(cacheDir string) error {
|
||||||
log.Logger.Debug("Updating database metadata...")
|
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)
|
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 {
|
if err = c.dbc.StoreMetadata(metadata, filepath.Join(cacheDir, "db")); err != nil {
|
||||||
return xerrors.Errorf("failed to store metadata: %w", err)
|
return xerrors.Errorf("failed to store metadata: %w", err)
|
||||||
}
|
}
|
||||||
@@ -192,11 +222,13 @@ func (c Client) UpdateMetadata(cacheDir string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Metadata defines the file meta
|
||||||
type Metadata struct { // TODO: Move all Metadata things to trivy-db repo
|
type Metadata struct { // TODO: Move all Metadata things to trivy-db repo
|
||||||
fs afero.Fs
|
fs afero.Fs
|
||||||
filePath string
|
filePath string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewMetadata is the factory method for file Metadata
|
||||||
func NewMetadata(fs afero.Fs, cacheDir string) Metadata {
|
func NewMetadata(fs afero.Fs, cacheDir string) Metadata {
|
||||||
filePath := MetadataPath(cacheDir)
|
filePath := MetadataPath(cacheDir)
|
||||||
return Metadata{
|
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 {
|
func MetadataPath(cacheDir string) string {
|
||||||
dbPath := db.Path(cacheDir)
|
dbPath := db.Path(cacheDir)
|
||||||
dbDir := filepath.Dir(dbPath)
|
dbDir := filepath.Dir(dbPath)
|
||||||
return filepath.Join(dbDir, metadataFile)
|
return filepath.Join(dbDir, metadataFile)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteMetadata deletes the file of database metadata
|
// Delete deletes the file of database metadata
|
||||||
func (m Metadata) Delete() error {
|
func (m Metadata) Delete() error {
|
||||||
if err := m.fs.Remove(m.filePath); err != nil {
|
if err := m.fs.Remove(m.filePath); err != nil {
|
||||||
return xerrors.Errorf("unable to remove the metadata file: %w", err)
|
return xerrors.Errorf("unable to remove the metadata file: %w", err)
|
||||||
@@ -219,6 +252,7 @@ func (m Metadata) Delete() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get returns the file metadata
|
||||||
func (m Metadata) Get() (db.Metadata, error) {
|
func (m Metadata) Get() (db.Metadata, error) {
|
||||||
f, err := m.fs.Open(m.filePath)
|
f, err := m.fs.Open(m.filePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -133,6 +133,30 @@ func TestClient_NeedsUpdate(t *testing.T) {
|
|||||||
skip: true,
|
skip: true,
|
||||||
expectedError: xerrors.New("--skip-update cannot be specified with the old DB"),
|
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 {
|
if err := log.InitLogger(false, true); err != nil {
|
||||||
@@ -252,14 +276,17 @@ func TestClient_Download(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestClient_UpdateMetadata(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 {
|
testCases := []struct {
|
||||||
name string
|
name string
|
||||||
|
clock clock.Clock
|
||||||
getMetadataExpectation dbOperationGetMetadataExpectation
|
getMetadataExpectation dbOperationGetMetadataExpectation
|
||||||
storeMetadataExpectation dbOperationStoreMetadataExpectation
|
storeMetadataExpectation dbOperationStoreMetadataExpectation
|
||||||
expectedError error
|
expectedError error
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "happy path",
|
name: "happy path",
|
||||||
|
clock: timeDownloadedAt,
|
||||||
getMetadataExpectation: dbOperationGetMetadataExpectation{
|
getMetadataExpectation: dbOperationGetMetadataExpectation{
|
||||||
Returns: dbOperationGetMetadataReturns{
|
Returns: dbOperationGetMetadataReturns{
|
||||||
Metadata: db.Metadata{
|
Metadata: db.Metadata{
|
||||||
@@ -273,15 +300,17 @@ func TestClient_UpdateMetadata(t *testing.T) {
|
|||||||
},
|
},
|
||||||
storeMetadataExpectation: dbOperationStoreMetadataExpectation{
|
storeMetadataExpectation: dbOperationStoreMetadataExpectation{
|
||||||
Metadata: db.Metadata{
|
Metadata: db.Metadata{
|
||||||
Version: 1,
|
Version: 1,
|
||||||
Type: 1,
|
Type: 1,
|
||||||
NextUpdate: time.Date(2020, 4, 30, 23, 59, 59, 0, time.UTC),
|
NextUpdate: time.Date(2020, 4, 30, 23, 59, 59, 0, time.UTC),
|
||||||
UpdatedAt: time.Date(2006, 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",
|
name: "sad path, get metadata fails",
|
||||||
|
clock: timeDownloadedAt,
|
||||||
getMetadataExpectation: dbOperationGetMetadataExpectation{
|
getMetadataExpectation: dbOperationGetMetadataExpectation{
|
||||||
Returns: dbOperationGetMetadataReturns{
|
Returns: dbOperationGetMetadataReturns{
|
||||||
Err: errors.New("get metadata failed"),
|
Err: errors.New("get metadata failed"),
|
||||||
@@ -290,7 +319,8 @@ func TestClient_UpdateMetadata(t *testing.T) {
|
|||||||
expectedError: errors.New("unable to get metadata: get metadata failed"),
|
expectedError: errors.New("unable to get metadata: get metadata failed"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "sad path, store metadata fails",
|
name: "sad path, store metadata fails",
|
||||||
|
clock: timeDownloadedAt,
|
||||||
getMetadataExpectation: dbOperationGetMetadataExpectation{
|
getMetadataExpectation: dbOperationGetMetadataExpectation{
|
||||||
Returns: dbOperationGetMetadataReturns{
|
Returns: dbOperationGetMetadataReturns{
|
||||||
Metadata: db.Metadata{
|
Metadata: db.Metadata{
|
||||||
@@ -304,10 +334,11 @@ func TestClient_UpdateMetadata(t *testing.T) {
|
|||||||
},
|
},
|
||||||
storeMetadataExpectation: dbOperationStoreMetadataExpectation{
|
storeMetadataExpectation: dbOperationStoreMetadataExpectation{
|
||||||
Metadata: db.Metadata{
|
Metadata: db.Metadata{
|
||||||
Version: 1,
|
Version: 1,
|
||||||
Type: 1,
|
Type: 1,
|
||||||
NextUpdate: time.Date(2020, 4, 30, 23, 59, 59, 0, time.UTC),
|
NextUpdate: time.Date(2020, 4, 30, 23, 59, 59, 0, time.UTC),
|
||||||
UpdatedAt: time.Date(2006, 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{
|
Returns: dbOperationStoreMetadataReturns{
|
||||||
Err: errors.New("store metadata failed"),
|
Err: errors.New("store metadata failed"),
|
||||||
@@ -334,7 +365,7 @@ func TestClient_UpdateMetadata(t *testing.T) {
|
|||||||
defer os.RemoveAll(dir)
|
defer os.RemoveAll(dir)
|
||||||
|
|
||||||
pb := indicator.NewProgressBar(true)
|
pb := indicator.NewProgressBar(true)
|
||||||
client := NewClient(mockConfig, nil, pb, nil, metadata)
|
client := NewClient(mockConfig, nil, pb, tc.clock, metadata)
|
||||||
|
|
||||||
err = client.UpdateMetadata(dir)
|
err = client.UpdateMetadata(dir)
|
||||||
switch {
|
switch {
|
||||||
|
|||||||
@@ -4,50 +4,50 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/Masterminds/semver/v3"
|
|
||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
"github.com/aquasecurity/trivy-db/pkg/db"
|
"github.com/aquasecurity/trivy-db/pkg/db"
|
||||||
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
|
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"
|
"github.com/aquasecurity/trivy/pkg/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Advisory represents security advisories for each programming language
|
// Advisory represents security advisories for each programming language
|
||||||
type Advisory struct {
|
type Advisory struct {
|
||||||
lang string
|
ecosystem string
|
||||||
comparer comparer
|
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{
|
return &Advisory{
|
||||||
lang: lang,
|
ecosystem: ecosystem,
|
||||||
comparer: newComparer(lang),
|
comparer: comparer,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// DetectVulnerabilities scans buckets with the prefix according to the programming language in "Advisory".
|
// DetectVulnerabilities scans buckets with the prefix according to the ecosystem in "Advisory".
|
||||||
// If "lang" is python, it looks for buckets with "python::" and gets security advisories from those buckets.
|
// 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 lang prefix (e.g. python::new-data-source)
|
// 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.
|
// and detect vulnerabilities without specifying a specific bucket name.
|
||||||
func (s *Advisory) DetectVulnerabilities(pkgName string, pkgVer *semver.Version) ([]types.DetectedVulnerability, error) {
|
func (s *Advisory) DetectVulnerabilities(pkgName, pkgVer string) ([]types.DetectedVulnerability, error) {
|
||||||
// e.g. "python::"
|
// e.g. "pip::", "npm::"
|
||||||
prefix := fmt.Sprintf("%s::", s.lang)
|
prefix := fmt.Sprintf("%s::", s.ecosystem)
|
||||||
advisories, err := db.Config{}.GetAdvisories(prefix, pkgName)
|
advisories, err := db.Config{}.GetAdvisories(prefix, pkgName)
|
||||||
if err != nil {
|
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
|
var vulns []types.DetectedVulnerability
|
||||||
for _, advisory := range advisories {
|
for _, advisory := range advisories {
|
||||||
if !s.comparer.isVulnerable(pkgVer, advisory) {
|
if !s.comparer.IsVulnerable(pkgVer, advisory) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
vuln := types.DetectedVulnerability{
|
vuln := types.DetectedVulnerability{
|
||||||
VulnerabilityID: advisory.VulnerabilityID,
|
VulnerabilityID: advisory.VulnerabilityID,
|
||||||
PkgName: pkgName,
|
PkgName: pkgName,
|
||||||
InstalledVersion: pkgVer.String(),
|
InstalledVersion: pkgVer,
|
||||||
FixedVersion: s.createFixedVersions(advisory),
|
FixedVersion: s.createFixedVersions(advisory),
|
||||||
}
|
}
|
||||||
vulns = append(vulns, vuln)
|
vulns = append(vulns, vuln)
|
||||||
@@ -73,29 +73,3 @@ func (s *Advisory) createFixedVersions(advisory dbTypes.Advisory) string {
|
|||||||
}
|
}
|
||||||
return strings.Join(fixedVersions, ", ")
|
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
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -4,40 +4,40 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/Masterminds/semver/v3"
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
"github.com/aquasecurity/trivy-db/pkg/db"
|
"github.com/aquasecurity/trivy-db/pkg/db"
|
||||||
"github.com/aquasecurity/trivy-db/pkg/vulnsrc/vulnerability"
|
"github.com/aquasecurity/trivy-db/pkg/vulnsrc/vulnerability"
|
||||||
"github.com/aquasecurity/trivy/pkg/detector/library"
|
"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/types"
|
||||||
"github.com/aquasecurity/trivy/pkg/utils"
|
"github.com/aquasecurity/trivy/pkg/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestAdvisory_DetectVulnerabilities(t *testing.T) {
|
func TestAdvisory_DetectVulnerabilities(t *testing.T) {
|
||||||
type fields struct {
|
|
||||||
lang string
|
|
||||||
}
|
|
||||||
type args struct {
|
type args struct {
|
||||||
pkgName string
|
pkgName string
|
||||||
pkgVer *semver.Version
|
pkgVer string
|
||||||
}
|
}
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
fixtures []string
|
fixtures []string
|
||||||
fields fields
|
ecosystem string
|
||||||
args args
|
comparer comparer.Comparer
|
||||||
want []types.DetectedVulnerability
|
args args
|
||||||
wantErr string
|
want []types.DetectedVulnerability
|
||||||
|
wantErr string
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "happy path",
|
name: "happy path",
|
||||||
fixtures: []string{"testdata/fixtures/php.yaml"},
|
fixtures: []string{"testdata/fixtures/php.yaml"},
|
||||||
fields: fields{lang: vulnerability.PHP},
|
ecosystem: vulnerability.Composer,
|
||||||
|
comparer: comparer.GenericComparer{},
|
||||||
args: args{
|
args: args{
|
||||||
pkgName: "symfony/symfony",
|
pkgName: "symfony/symfony",
|
||||||
pkgVer: semver.MustParse("4.2.6"),
|
pkgVer: "4.2.6",
|
||||||
},
|
},
|
||||||
want: []types.DetectedVulnerability{
|
want: []types.DetectedVulnerability{
|
||||||
{
|
{
|
||||||
@@ -49,12 +49,13 @@ func TestAdvisory_DetectVulnerabilities(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "no patched versions in the advisory",
|
name: "no patched versions in the advisory",
|
||||||
fixtures: []string{"testdata/fixtures/php.yaml"},
|
fixtures: []string{"testdata/fixtures/php.yaml"},
|
||||||
fields: fields{lang: vulnerability.PHP},
|
ecosystem: vulnerability.Composer,
|
||||||
|
comparer: comparer.GenericComparer{},
|
||||||
args: args{
|
args: args{
|
||||||
pkgName: "symfony/symfony",
|
pkgName: "symfony/symfony",
|
||||||
pkgVer: semver.MustParse("4.4.6"),
|
pkgVer: "4.4.6",
|
||||||
},
|
},
|
||||||
want: []types.DetectedVulnerability{
|
want: []types.DetectedVulnerability{
|
||||||
{
|
{
|
||||||
@@ -66,12 +67,13 @@ func TestAdvisory_DetectVulnerabilities(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "no vulnerable versions in the advisory",
|
name: "no vulnerable versions in the advisory",
|
||||||
fixtures: []string{"testdata/fixtures/ruby.yaml"},
|
fixtures: []string{"testdata/fixtures/ruby.yaml"},
|
||||||
fields: fields{lang: vulnerability.Ruby},
|
ecosystem: vulnerability.RubyGems,
|
||||||
|
comparer: bundler.RubyGemsComparer{},
|
||||||
args: args{
|
args: args{
|
||||||
pkgName: "activesupport",
|
pkgName: "activesupport",
|
||||||
pkgVer: semver.MustParse("4.1.1"),
|
pkgVer: "4.1.1",
|
||||||
},
|
},
|
||||||
want: []types.DetectedVulnerability{
|
want: []types.DetectedVulnerability{
|
||||||
{
|
{
|
||||||
@@ -83,12 +85,13 @@ func TestAdvisory_DetectVulnerabilities(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "no vulnerability",
|
name: "no vulnerability",
|
||||||
fixtures: []string{"testdata/fixtures/php.yaml"},
|
fixtures: []string{"testdata/fixtures/php.yaml"},
|
||||||
fields: fields{lang: vulnerability.PHP},
|
ecosystem: vulnerability.Composer,
|
||||||
|
comparer: comparer.GenericComparer{},
|
||||||
args: args{
|
args: args{
|
||||||
pkgName: "symfony/symfony",
|
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 os.RemoveAll(dir)
|
||||||
defer db.Close()
|
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)
|
got, err := adv.DetectVulnerabilities(tt.args.pkgName, tt.args.pkgVer)
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
|
|||||||
@@ -3,29 +3,34 @@ package bundler
|
|||||||
import (
|
import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/Masterminds/semver/v3"
|
|
||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
|
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
|
||||||
bundlerSrc "github.com/aquasecurity/trivy-db/pkg/vulnsrc/bundler"
|
bundlerSrc "github.com/aquasecurity/trivy-db/pkg/vulnsrc/bundler"
|
||||||
"github.com/aquasecurity/trivy/pkg/scanner/utils"
|
|
||||||
"github.com/aquasecurity/trivy/pkg/types"
|
"github.com/aquasecurity/trivy/pkg/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// VulnSrc defines the operation on bundler vulnerability
|
||||||
type VulnSrc interface {
|
type VulnSrc interface {
|
||||||
Get(pkgName string) ([]bundlerSrc.Advisory, error)
|
Get(pkgName string) ([]bundlerSrc.Advisory, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Advisory implements the bundler VulnSrc
|
||||||
type Advisory struct {
|
type Advisory struct {
|
||||||
vs VulnSrc
|
comparer RubyGemsComparer
|
||||||
|
vs VulnSrc
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewAdvisory is the factory method to return bundler.Advisory
|
||||||
func NewAdvisory() *Advisory {
|
func NewAdvisory() *Advisory {
|
||||||
return &Advisory{
|
return &Advisory{
|
||||||
vs: bundlerSrc.NewVulnSrc(),
|
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)
|
advisories, err := a.vs.Get(pkgName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, xerrors.Errorf("failed to get bundler advisories: %w", err)
|
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
|
var vulns []types.DetectedVulnerability
|
||||||
for _, advisory := range advisories {
|
for _, advisory := range advisories {
|
||||||
if utils.MatchVersions(pkgVer, advisory.PatchedVersions) {
|
adv := dbTypes.Advisory{
|
||||||
continue
|
UnaffectedVersions: advisory.UnaffectedVersions,
|
||||||
|
PatchedVersions: advisory.PatchedVersions,
|
||||||
}
|
}
|
||||||
if utils.MatchVersions(pkgVer, advisory.UnaffectedVersions) {
|
if !a.comparer.IsVulnerable(pkgVer, adv) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
vuln := types.DetectedVulnerability{
|
vuln := types.DetectedVulnerability{
|
||||||
VulnerabilityID: advisory.VulnerabilityID,
|
VulnerabilityID: advisory.VulnerabilityID,
|
||||||
PkgName: strings.TrimSpace(pkgName),
|
PkgName: strings.TrimSpace(pkgName),
|
||||||
InstalledVersion: pkgVer.String(),
|
InstalledVersion: pkgVer,
|
||||||
FixedVersion: strings.Join(advisory.PatchedVersions, ", "),
|
FixedVersion: strings.Join(advisory.PatchedVersions, ", "),
|
||||||
}
|
}
|
||||||
vulns = append(vulns, vuln)
|
vulns = append(vulns, vuln)
|
||||||
|
|||||||
@@ -1,62 +1,84 @@
|
|||||||
package bundler
|
package bundler_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/aquasecurity/trivy/pkg/log"
|
"github.com/aquasecurity/trivy/pkg/detector/library/bundler"
|
||||||
|
|
||||||
"github.com/Masterminds/semver/v3"
|
|
||||||
|
|
||||||
bundlerSrc "github.com/aquasecurity/trivy-db/pkg/vulnsrc/bundler"
|
|
||||||
"github.com/stretchr/testify/assert"
|
"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 {
|
func TestAdvisory_DetectVulnerabilities(t *testing.T) {
|
||||||
mock.Mock
|
type args struct {
|
||||||
}
|
pkgName string
|
||||||
|
pkgVer string
|
||||||
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)
|
tests := []struct {
|
||||||
if !ok {
|
name string
|
||||||
return nil, ret.Error(1)
|
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",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
return advisories, ret.Error(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestScanner_Detect(t *testing.T) {
|
|
||||||
log.InitLogger(false, true)
|
log.InitLogger(false, true)
|
||||||
t.Run("Issue #108", func(t *testing.T) {
|
for _, tt := range tests {
|
||||||
// https://github.com/aquasecurity/trivy/issues/108
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
// Validate that the massaging that happens when parsing the lockfile
|
dir := utils.InitTestDB(t, tt.fixtures)
|
||||||
// allows us to better handle the platform metadata
|
defer os.RemoveAll(dir)
|
||||||
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,
|
|
||||||
}
|
|
||||||
|
|
||||||
versionStr := "1.9.25-x64-mingw32"
|
a := bundler.NewAdvisory()
|
||||||
v, _ := semver.NewVersion(versionStr)
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
vulns, err := s.DetectVulnerabilities("ffi", v)
|
assert.Equal(t, tt.want, got)
|
||||||
|
})
|
||||||
assert.Nil(t, err)
|
}
|
||||||
assert.Equal(t, 1, len(vulns))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|||||||
32
pkg/detector/library/bundler/compare.go
Normal file
32
pkg/detector/library/bundler/compare.go
Normal 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
|
||||||
|
}
|
||||||
104
pkg/detector/library/bundler/compare_test.go
Normal file
104
pkg/detector/library/bundler/compare_test.go
Normal 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)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
11
pkg/detector/library/bundler/testdata/fixtures/gem.yaml
vendored
Normal file
11
pkg/detector/library/bundler/testdata/fixtures/gem.yaml
vendored
Normal 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"
|
||||||
7
pkg/detector/library/bundler/testdata/fixtures/invalid-type.yaml
vendored
Normal file
7
pkg/detector/library/bundler/testdata/fixtures/invalid-type.yaml
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
- bucket: ruby-advisory-db
|
||||||
|
pairs:
|
||||||
|
- bucket: activesupport
|
||||||
|
pairs:
|
||||||
|
- key: CVE-2015-3226
|
||||||
|
value:
|
||||||
|
PatchedVersions: dummy
|
||||||
@@ -3,25 +3,30 @@ package cargo
|
|||||||
import (
|
import (
|
||||||
"strings"
|
"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"
|
"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 {
|
type Advisory struct {
|
||||||
vs cargoSrc.VulnSrc
|
vs cargoSrc.VulnSrc
|
||||||
|
comparer comparer.Comparer
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewAdvisory is the factory method to return cargo Scanner
|
||||||
func NewAdvisory() *Advisory {
|
func NewAdvisory() *Advisory {
|
||||||
return &Advisory{
|
return &Advisory{
|
||||||
vs: cargoSrc.NewVulnSrc(),
|
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)
|
advisories, err := s.vs.Get(pkgName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, xerrors.Errorf("failed to get cargo advisories: %w", err)
|
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
|
var vulns []types.DetectedVulnerability
|
||||||
for _, advisory := range advisories {
|
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
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
vuln := types.DetectedVulnerability{
|
vuln := types.DetectedVulnerability{
|
||||||
VulnerabilityID: advisory.VulnerabilityID,
|
VulnerabilityID: advisory.VulnerabilityID,
|
||||||
PkgName: strings.TrimSpace(pkgName),
|
PkgName: strings.TrimSpace(pkgName),
|
||||||
InstalledVersion: pkgVer.String(),
|
InstalledVersion: pkgVer,
|
||||||
FixedVersion: strings.Join(advisory.PatchedVersions, ", "),
|
FixedVersion: strings.Join(advisory.PatchedVersions, ", "),
|
||||||
}
|
}
|
||||||
vulns = append(vulns, vuln)
|
vulns = append(vulns, vuln)
|
||||||
|
|||||||
100
pkg/detector/library/cargo/advisory_test.go
Normal file
100
pkg/detector/library/cargo/advisory_test.go
Normal 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)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
10
pkg/detector/library/cargo/testdata/fixtures/cargo.yaml
vendored
Normal file
10
pkg/detector/library/cargo/testdata/fixtures/cargo.yaml
vendored
Normal 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"
|
||||||
7
pkg/detector/library/cargo/testdata/fixtures/invalid-type.yaml
vendored
Normal file
7
pkg/detector/library/cargo/testdata/fixtures/invalid-type.yaml
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
- bucket: rust-advisory-db
|
||||||
|
pairs:
|
||||||
|
- bucket: bumpalo
|
||||||
|
pairs:
|
||||||
|
- key: RUSTSEC-2020-0006
|
||||||
|
value:
|
||||||
|
PatchedVersions: foo
|
||||||
8
pkg/detector/library/cargo/testdata/fixtures/no-patched-version.yaml
vendored
Normal file
8
pkg/detector/library/cargo/testdata/fixtures/no-patched-version.yaml
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
- bucket: rust-advisory-db
|
||||||
|
pairs:
|
||||||
|
- bucket: bumpalo
|
||||||
|
pairs:
|
||||||
|
- key: RUSTSEC-2020-0006
|
||||||
|
value:
|
||||||
|
PatchedVersions:
|
||||||
|
UnaffectedVersions:
|
||||||
72
pkg/detector/library/comparer/compare.go
Normal file
72
pkg/detector/library/comparer/compare.go
Normal 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
|
||||||
|
}
|
||||||
96
pkg/detector/library/comparer/compare_test.go
Normal file
96
pkg/detector/library/comparer/compare_test.go
Normal 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)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,27 +4,30 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/aquasecurity/trivy/pkg/types"
|
|
||||||
|
|
||||||
"golang.org/x/xerrors"
|
"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"
|
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 {
|
type Advisory struct {
|
||||||
vs composerSrc.VulnSrc
|
vs composerSrc.VulnSrc
|
||||||
|
comparer comparer.Comparer // TODO: implement a comparer for Composer
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewAdvisory is the factory method of Advisory
|
||||||
func NewAdvisory() *Advisory {
|
func NewAdvisory() *Advisory {
|
||||||
return &Advisory{
|
return &Advisory{
|
||||||
vs: composerSrc.NewVulnSrc(),
|
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)
|
ref := fmt.Sprintf("composer://%s", pkgName)
|
||||||
advisories, err := s.vs.Get(ref)
|
advisories, err := s.vs.Get(ref)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -44,14 +47,15 @@ func (s *Advisory) DetectVulnerabilities(pkgName string, pkgVer *semver.Version)
|
|||||||
affectedVersions = append(affectedVersions, strings.Join(branch.Versions, ", "))
|
affectedVersions = append(affectedVersions, strings.Join(branch.Versions, ", "))
|
||||||
}
|
}
|
||||||
|
|
||||||
if !utils.MatchVersions(pkgVer, affectedVersions) {
|
adv := dbTypes.Advisory{VulnerableVersions: affectedVersions}
|
||||||
|
if !s.comparer.IsVulnerable(pkgVer, adv) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
vuln := types.DetectedVulnerability{
|
vuln := types.DetectedVulnerability{
|
||||||
VulnerabilityID: advisory.VulnerabilityID,
|
VulnerabilityID: advisory.VulnerabilityID,
|
||||||
PkgName: pkgName,
|
PkgName: pkgName,
|
||||||
InstalledVersion: pkgVer.String(),
|
InstalledVersion: pkgVer,
|
||||||
FixedVersion: strings.Join(patchedVersions, ", "),
|
FixedVersion: strings.Join(patchedVersions, ", "),
|
||||||
}
|
}
|
||||||
vulns = append(vulns, vuln)
|
vulns = append(vulns, vuln)
|
||||||
|
|||||||
84
pkg/detector/library/composer/advisory_test.go
Normal file
84
pkg/detector/library/composer/advisory_test.go
Normal 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)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
28
pkg/detector/library/composer/testdata/fixtures/composer.yaml
vendored
Normal file
28
pkg/detector/library/composer/testdata/fixtures/composer.yaml
vendored
Normal 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"
|
||||||
7
pkg/detector/library/composer/testdata/fixtures/invalid-type.yaml
vendored
Normal file
7
pkg/detector/library/composer/testdata/fixtures/invalid-type.yaml
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
- bucket: php-security-advisories
|
||||||
|
pairs:
|
||||||
|
- bucket: "composer://aws/aws-sdk-php"
|
||||||
|
pairs:
|
||||||
|
- key: CVE-2015-5723
|
||||||
|
value:
|
||||||
|
Branches: invalid
|
||||||
@@ -4,19 +4,15 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
ftypes "github.com/aquasecurity/fanal/types"
|
|
||||||
|
|
||||||
"github.com/google/wire"
|
"github.com/google/wire"
|
||||||
|
|
||||||
"github.com/Masterminds/semver/v3"
|
|
||||||
"github.com/aquasecurity/trivy/pkg/log"
|
|
||||||
|
|
||||||
"golang.org/x/xerrors"
|
"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"
|
"github.com/aquasecurity/trivy/pkg/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// SuperSet binds the dependencies for library scan
|
||||||
var SuperSet = wire.NewSet(
|
var SuperSet = wire.NewSet(
|
||||||
wire.Struct(new(DriverFactory)),
|
wire.Struct(new(DriverFactory)),
|
||||||
wire.Bind(new(Factory), new(DriverFactory)),
|
wire.Bind(new(Factory), new(DriverFactory)),
|
||||||
@@ -24,18 +20,22 @@ var SuperSet = wire.NewSet(
|
|||||||
wire.Bind(new(Operation), new(Detector)),
|
wire.Bind(new(Operation), new(Detector)),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Operation defines library scan operations
|
||||||
type Operation interface {
|
type Operation interface {
|
||||||
Detect(imageName string, filePath string, created time.Time, pkgs []ftypes.LibraryInfo) (vulns []types.DetectedVulnerability, err error)
|
Detect(imageName string, filePath string, created time.Time, pkgs []ftypes.LibraryInfo) (vulns []types.DetectedVulnerability, err error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Detector implements driverFactory
|
||||||
type Detector struct {
|
type Detector struct {
|
||||||
driverFactory Factory
|
driverFactory Factory
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewDetector is the factory method for detector
|
||||||
func NewDetector(factory Factory) Detector {
|
func NewDetector(factory Factory) Detector {
|
||||||
return Detector{driverFactory: factory}
|
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) {
|
func (d Detector) Detect(_, filePath string, _ time.Time, pkgs []ftypes.LibraryInfo) ([]types.DetectedVulnerability, error) {
|
||||||
log.Logger.Debugf("Detecting library vulnerabilities, path: %s", filePath)
|
log.Logger.Debugf("Detecting library vulnerabilities, path: %s", filePath)
|
||||||
driver, err := d.driverFactory.NewDriver(filepath.Base(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())
|
log.Logger.Infof("Detecting %s vulnerabilities...", driver.Type())
|
||||||
var vulnerabilities []types.DetectedVulnerability
|
var vulnerabilities []types.DetectedVulnerability
|
||||||
for _, lib := range libs {
|
for _, lib := range libs {
|
||||||
v, err := semver.NewVersion(utils.FormatPatchVersion(lib.Library.Version))
|
vulns, err := driver.Detect(lib.Library.Name, 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)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, xerrors.Errorf("failed to detect %s vulnerabilities: %w", driver.Type(), err)
|
return nil, xerrors.Errorf("failed to detect %s vulnerabilities: %w", driver.Type(), err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,71 +3,77 @@ package library
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/Masterminds/semver/v3"
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
ecosystem "github.com/aquasecurity/trivy-db/pkg/vulnsrc/ghsa"
|
ecosystem "github.com/aquasecurity/trivy-db/pkg/vulnsrc/ghsa"
|
||||||
"github.com/aquasecurity/trivy-db/pkg/vulnsrc/vulnerability"
|
"github.com/aquasecurity/trivy-db/pkg/vulnsrc/vulnerability"
|
||||||
"github.com/aquasecurity/trivy/pkg/detector/library/bundler"
|
"github.com/aquasecurity/trivy/pkg/detector/library/bundler"
|
||||||
"github.com/aquasecurity/trivy/pkg/detector/library/cargo"
|
"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/composer"
|
||||||
"github.com/aquasecurity/trivy/pkg/detector/library/ghsa"
|
"github.com/aquasecurity/trivy/pkg/detector/library/ghsa"
|
||||||
"github.com/aquasecurity/trivy/pkg/detector/library/node"
|
"github.com/aquasecurity/trivy/pkg/detector/library/node"
|
||||||
"github.com/aquasecurity/trivy/pkg/detector/library/python"
|
"github.com/aquasecurity/trivy/pkg/detector/library/python"
|
||||||
"github.com/aquasecurity/trivy/pkg/types"
|
"github.com/aquasecurity/trivy/pkg/types"
|
||||||
"golang.org/x/xerrors"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Factory defines library operations
|
||||||
type Factory interface {
|
type Factory interface {
|
||||||
NewDriver(filename string) (Driver, error)
|
NewDriver(filename string) (Driver, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type advisory interface {
|
type advisory interface {
|
||||||
DetectVulnerabilities(string, *semver.Version) ([]types.DetectedVulnerability, error)
|
DetectVulnerabilities(string, string) ([]types.DetectedVulnerability, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DriverFactory implements Factory
|
||||||
type DriverFactory struct{}
|
type DriverFactory struct{}
|
||||||
|
|
||||||
|
// NewDriver factory method for driver
|
||||||
func (d DriverFactory) NewDriver(filename string) (Driver, error) {
|
func (d DriverFactory) NewDriver(filename string) (Driver, error) {
|
||||||
// TODO: use DI
|
|
||||||
var driver Driver
|
var driver Driver
|
||||||
switch filename {
|
switch filename {
|
||||||
case "Gemfile.lock":
|
case "Gemfile.lock":
|
||||||
driver = newRubyDriver()
|
driver = newRubyGemsDriver()
|
||||||
case "Cargo.lock":
|
case "Cargo.lock":
|
||||||
driver = newRustDriver()
|
driver = newCargoDriver()
|
||||||
case "composer.lock":
|
case "composer.lock":
|
||||||
driver = newPHPDriver()
|
driver = newComposerDriver()
|
||||||
case "package-lock.json", "yarn.lock":
|
case "package-lock.json", "yarn.lock":
|
||||||
driver = newNodejsDriver()
|
driver = newNpmDriver()
|
||||||
case "Pipfile.lock", "poetry.lock":
|
case "Pipfile.lock", "poetry.lock":
|
||||||
driver = newPythonDriver()
|
driver = newPipDriver()
|
||||||
default:
|
default:
|
||||||
return Driver{}, xerrors.New(fmt.Sprintf("unsupport filename %s", filename))
|
return Driver{}, xerrors.New(fmt.Sprintf("unsupport filename %s", filename))
|
||||||
}
|
}
|
||||||
return driver, nil
|
return driver, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Driver implements the advisory
|
||||||
type Driver struct {
|
type Driver struct {
|
||||||
lang string
|
ecosystem string
|
||||||
advisories []advisory
|
advisories []advisory
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewDriver(lang string, advisories ...advisory) Driver {
|
// NewDriver is the factory method from drier
|
||||||
return Driver{lang: lang, advisories: advisories}
|
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
|
var detectedVulnerabilities []types.DetectedVulnerability
|
||||||
uniqVulnIdMap := make(map[string]struct{})
|
uniqVulnIDMap := make(map[string]struct{})
|
||||||
for _, d := range append(d.advisories, NewAdvisory(d.lang)) {
|
for _, d := range d.advisories {
|
||||||
vulns, err := d.DetectVulnerabilities(pkgName, pkgVer)
|
vulns, err := d.DetectVulnerabilities(pkgName, pkgVer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, xerrors.Errorf("failed to detect vulnerabilities: %w", err)
|
return nil, xerrors.Errorf("failed to detect vulnerabilities: %w", err)
|
||||||
}
|
}
|
||||||
for _, vuln := range vulns {
|
for _, vuln := range vulns {
|
||||||
if _, ok := uniqVulnIdMap[vuln.VulnerabilityID]; ok {
|
if _, ok := uniqVulnIDMap[vuln.VulnerabilityID]; ok {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
uniqVulnIdMap[vuln.VulnerabilityID] = struct{}{}
|
uniqVulnIDMap[vuln.VulnerabilityID] = struct{}{}
|
||||||
detectedVulnerabilities = append(detectedVulnerabilities, vuln)
|
detectedVulnerabilities = append(detectedVulnerabilities, vuln)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -75,26 +81,36 @@ func (d *Driver) Detect(pkgName string, pkgVer *semver.Version) ([]types.Detecte
|
|||||||
return detectedVulnerabilities, nil
|
return detectedVulnerabilities, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Type returns the driver ecosystem
|
||||||
func (d *Driver) Type() string {
|
func (d *Driver) Type() string {
|
||||||
return d.lang
|
return d.ecosystem
|
||||||
}
|
}
|
||||||
|
|
||||||
func newRubyDriver() Driver {
|
func newRubyGemsDriver() Driver {
|
||||||
return NewDriver(vulnerability.Ruby, ghsa.NewAdvisory(ecosystem.Rubygems), bundler.NewAdvisory())
|
c := bundler.RubyGemsComparer{}
|
||||||
|
return NewDriver(ghsa.NewAdvisory(ecosystem.Rubygems, c), bundler.NewAdvisory(),
|
||||||
|
NewAdvisory(vulnerability.RubyGems, c))
|
||||||
}
|
}
|
||||||
|
|
||||||
func newPHPDriver() Driver {
|
func newComposerDriver() Driver {
|
||||||
return NewDriver(vulnerability.PHP, ghsa.NewAdvisory(ecosystem.Composer), composer.NewAdvisory())
|
c := comparer.GenericComparer{}
|
||||||
|
return NewDriver(
|
||||||
|
ghsa.NewAdvisory(ecosystem.Composer, c), composer.NewAdvisory(),
|
||||||
|
NewAdvisory(vulnerability.Composer, c))
|
||||||
}
|
}
|
||||||
|
|
||||||
func newRustDriver() Driver {
|
func newCargoDriver() Driver {
|
||||||
return NewDriver(vulnerability.Rust, cargo.NewAdvisory())
|
return NewDriver(cargo.NewAdvisory(), NewAdvisory(vulnerability.Cargo, comparer.GenericComparer{}))
|
||||||
}
|
}
|
||||||
|
|
||||||
func newNodejsDriver() Driver {
|
func newNpmDriver() Driver {
|
||||||
return NewDriver(vulnerability.Nodejs, ghsa.NewAdvisory(ecosystem.Npm), node.NewAdvisory())
|
c := node.NpmComparer{}
|
||||||
|
return NewDriver(ghsa.NewAdvisory(ecosystem.Npm, c), node.NewAdvisory(),
|
||||||
|
NewAdvisory(vulnerability.Npm, c))
|
||||||
}
|
}
|
||||||
|
|
||||||
func newPythonDriver() Driver {
|
func newPipDriver() Driver {
|
||||||
return NewDriver(vulnerability.Python, ghsa.NewAdvisory(ecosystem.Pip), python.NewAdvisory())
|
c := comparer.GenericComparer{}
|
||||||
|
return NewDriver(ghsa.NewAdvisory(ecosystem.Pip, c), python.NewAdvisory(),
|
||||||
|
NewAdvisory(vulnerability.Pip, c))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/Masterminds/semver/v3"
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
@@ -20,7 +19,7 @@ func TestDriver_Detect(t *testing.T) {
|
|||||||
}
|
}
|
||||||
type args struct {
|
type args struct {
|
||||||
pkgName string
|
pkgName string
|
||||||
pkgVer *semver.Version
|
pkgVer string
|
||||||
}
|
}
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
@@ -36,7 +35,7 @@ func TestDriver_Detect(t *testing.T) {
|
|||||||
fields: fields{fileName: "composer.lock"},
|
fields: fields{fileName: "composer.lock"},
|
||||||
args: args{
|
args: args{
|
||||||
pkgName: "symfony/symfony",
|
pkgName: "symfony/symfony",
|
||||||
pkgVer: semver.MustParse("4.2.6"),
|
pkgVer: "4.2.6",
|
||||||
},
|
},
|
||||||
want: []types.DetectedVulnerability{
|
want: []types.DetectedVulnerability{
|
||||||
{
|
{
|
||||||
@@ -53,7 +52,7 @@ func TestDriver_Detect(t *testing.T) {
|
|||||||
fields: fields{fileName: "composer.lock"},
|
fields: fields{fileName: "composer.lock"},
|
||||||
args: args{
|
args: args{
|
||||||
pkgName: "symfony/symfony",
|
pkgName: "symfony/symfony",
|
||||||
pkgVer: semver.MustParse("4.2.6"),
|
pkgVer: "4.2.6",
|
||||||
},
|
},
|
||||||
want: []types.DetectedVulnerability{
|
want: []types.DetectedVulnerability{
|
||||||
{
|
{
|
||||||
@@ -70,7 +69,7 @@ func TestDriver_Detect(t *testing.T) {
|
|||||||
fields: fields{fileName: "composer.lock"},
|
fields: fields{fileName: "composer.lock"},
|
||||||
args: args{
|
args: args{
|
||||||
pkgName: "symfony/symfony",
|
pkgName: "symfony/symfony",
|
||||||
pkgVer: semver.MustParse("4.4.6"),
|
pkgVer: "4.4.6",
|
||||||
},
|
},
|
||||||
want: []types.DetectedVulnerability{
|
want: []types.DetectedVulnerability{
|
||||||
{
|
{
|
||||||
@@ -87,7 +86,7 @@ func TestDriver_Detect(t *testing.T) {
|
|||||||
fields: fields{fileName: "Gemfile.lock"},
|
fields: fields{fileName: "Gemfile.lock"},
|
||||||
args: args{
|
args: args{
|
||||||
pkgName: "activesupport",
|
pkgName: "activesupport",
|
||||||
pkgVer: semver.MustParse("4.1.1"),
|
pkgVer: "4.1.1",
|
||||||
},
|
},
|
||||||
want: []types.DetectedVulnerability{
|
want: []types.DetectedVulnerability{
|
||||||
{
|
{
|
||||||
@@ -104,7 +103,7 @@ func TestDriver_Detect(t *testing.T) {
|
|||||||
fields: fields{fileName: "composer.lock"},
|
fields: fields{fileName: "composer.lock"},
|
||||||
args: args{
|
args: args{
|
||||||
pkgName: "symfony/symfony",
|
pkgName: "symfony/symfony",
|
||||||
pkgVer: semver.MustParse("4.4.7"),
|
pkgVer: "4.4.7",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,29 +3,35 @@ package ghsa
|
|||||||
import (
|
import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/Masterminds/semver/v3"
|
|
||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
|
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
|
||||||
"github.com/aquasecurity/trivy-db/pkg/vulnsrc/ghsa"
|
"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"
|
"github.com/aquasecurity/trivy/pkg/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// VulnSrc defines the operations on vulnerability source
|
||||||
type VulnSrc interface {
|
type VulnSrc interface {
|
||||||
Get(pkgName string) ([]ghsa.Advisory, error)
|
Get(pkgName string) ([]ghsa.Advisory, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Advisory implements VulnSrc
|
||||||
type Advisory struct {
|
type Advisory struct {
|
||||||
vs VulnSrc
|
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{
|
return &Advisory{
|
||||||
vs: ghsa.NewVulnSrc(ecosystem),
|
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)
|
advisories, err := s.vs.Get(pkgName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, xerrors.Errorf("failed to get ghsa advisories: %w", err)
|
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
|
var vulns []types.DetectedVulnerability
|
||||||
for _, advisory := range advisories {
|
for _, advisory := range advisories {
|
||||||
if !utils.MatchVersions(pkgVer, advisory.VulnerableVersions) {
|
adv := dbTypes.Advisory{VulnerableVersions: advisory.VulnerableVersions}
|
||||||
|
if !s.comparer.IsVulnerable(pkgVer, adv) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
vuln := types.DetectedVulnerability{
|
vuln := types.DetectedVulnerability{
|
||||||
VulnerabilityID: advisory.VulnerabilityID,
|
VulnerabilityID: advisory.VulnerabilityID,
|
||||||
PkgName: pkgName,
|
PkgName: pkgName,
|
||||||
InstalledVersion: pkgVer.String(),
|
InstalledVersion: pkgVer,
|
||||||
FixedVersion: strings.Join(advisory.PatchedVersions, ", "),
|
FixedVersion: strings.Join(advisory.PatchedVersions, ", "),
|
||||||
}
|
}
|
||||||
vulns = append(vulns, vuln)
|
vulns = append(vulns, vuln)
|
||||||
|
|||||||
102
pkg/detector/library/ghsa/advisory_test.go
Normal file
102
pkg/detector/library/ghsa/advisory_test.go
Normal 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)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
12
pkg/detector/library/ghsa/testdata/fixtures/ghsa.yaml
vendored
Normal file
12
pkg/detector/library/ghsa/testdata/fixtures/ghsa.yaml
vendored
Normal 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"
|
||||||
7
pkg/detector/library/ghsa/testdata/fixtures/invalid-type.yaml
vendored
Normal file
7
pkg/detector/library/ghsa/testdata/fixtures/invalid-type.yaml
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
- bucket: GitHub Security Advisory Composer
|
||||||
|
pairs:
|
||||||
|
- bucket: "symfony/symfony"
|
||||||
|
pairs:
|
||||||
|
- key: CVE-2020-15094
|
||||||
|
value:
|
||||||
|
PatchedVersions: malformed
|
||||||
@@ -5,61 +5,69 @@ import (
|
|||||||
|
|
||||||
"golang.org/x/xerrors"
|
"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-db/pkg/vulnsrc/node"
|
||||||
"github.com/aquasecurity/trivy/pkg/scanner/utils"
|
|
||||||
"github.com/aquasecurity/trivy/pkg/types"
|
"github.com/aquasecurity/trivy/pkg/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Advisory encapsulate Node vulnerability source
|
||||||
type Advisory struct {
|
type Advisory struct {
|
||||||
vs node.VulnSrc
|
comparer NpmComparer
|
||||||
|
vs node.VulnSrc
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewAdvisory is the factory method for Node Advisory
|
||||||
func NewAdvisory() *Advisory {
|
func NewAdvisory() *Advisory {
|
||||||
return &Advisory{
|
return &Advisory{
|
||||||
vs: node.NewVulnSrc(),
|
vs: node.NewVulnSrc(),
|
||||||
|
comparer: NpmComparer{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Advisory) DetectVulnerabilities(pkgName string, pkgVer *semver.Version) ([]types.DetectedVulnerability, error) {
|
// DetectVulnerabilities scans and return vulnerability using Node package scanner
|
||||||
replacer := strings.NewReplacer(".alpha", "-alpha", ".beta", "-beta", ".rc", "-rc", " <", ", <", " >", ", >")
|
func (a *Advisory) DetectVulnerabilities(pkgName, pkgVer string) ([]types.DetectedVulnerability, error) {
|
||||||
advisories, err := s.vs.Get(pkgName)
|
advisories, err := a.vs.Get(pkgName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, xerrors.Errorf("failed to get node advisories: %w", err)
|
return nil, xerrors.Errorf("failed to get node advisories: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var vulns []types.DetectedVulnerability
|
var vulns []types.DetectedVulnerability
|
||||||
for _, advisory := range advisories {
|
for _, advisory := range advisories {
|
||||||
// e.g. <= 2.15.0 || >= 3.0.0 <= 3.8.2
|
adv := convertToGenericAdvisory(advisory)
|
||||||
// => {"<=2.15.0", ">= 3.0.0, <= 3.8.2"}
|
if !a.comparer.IsVulnerable(pkgVer, adv) {
|
||||||
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) {
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
vuln := types.DetectedVulnerability{
|
vuln := types.DetectedVulnerability{
|
||||||
VulnerabilityID: advisory.VulnerabilityID,
|
VulnerabilityID: advisory.VulnerabilityID,
|
||||||
PkgName: pkgName,
|
PkgName: pkgName,
|
||||||
InstalledVersion: pkgVer.String(),
|
InstalledVersion: pkgVer,
|
||||||
FixedVersion: strings.Join(patchedVersions, ", "),
|
FixedVersion: createFixedVersions(advisory.PatchedVersions),
|
||||||
}
|
}
|
||||||
vulns = append(vulns, vuln)
|
vulns = append(vulns, vuln)
|
||||||
}
|
}
|
||||||
return vulns, nil
|
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, ", ")
|
||||||
|
}
|
||||||
|
|||||||
91
pkg/detector/library/node/advisory_test.go
Normal file
91
pkg/detector/library/node/advisory_test.go
Normal 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)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
32
pkg/detector/library/node/compare.go
Normal file
32
pkg/detector/library/node/compare.go
Normal 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
|
||||||
|
}
|
||||||
140
pkg/detector/library/node/compare_test.go
Normal file
140
pkg/detector/library/node/compare_test.go
Normal 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)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
9
pkg/detector/library/node/testdata/fixtures/invalid-type.yaml
vendored
Normal file
9
pkg/detector/library/node/testdata/fixtures/invalid-type.yaml
vendored
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
- bucket: nodejs-security-wg
|
||||||
|
pairs:
|
||||||
|
- bucket: electron
|
||||||
|
pairs:
|
||||||
|
- key: CVE-2019-5786
|
||||||
|
value:
|
||||||
|
PatchedVersions:
|
||||||
|
- 1
|
||||||
|
- 2
|
||||||
6
pkg/detector/library/node/testdata/fixtures/no-value.yaml
vendored
Normal file
6
pkg/detector/library/node/testdata/fixtures/no-value.yaml
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
- bucket: nodejs-security-wg
|
||||||
|
pairs:
|
||||||
|
- bucket: electron
|
||||||
|
pairs:
|
||||||
|
- key: CVE-2019-5786
|
||||||
|
value:
|
||||||
8
pkg/detector/library/node/testdata/fixtures/npm.yaml
vendored
Normal file
8
pkg/detector/library/node/testdata/fixtures/npm.yaml
vendored
Normal 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"
|
||||||
@@ -3,26 +3,30 @@ package python
|
|||||||
import (
|
import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/aquasecurity/trivy-db/pkg/vulnsrc/python"
|
|
||||||
"github.com/aquasecurity/trivy/pkg/types"
|
|
||||||
|
|
||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
"github.com/Masterminds/semver/v3"
|
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
|
||||||
"github.com/aquasecurity/trivy/pkg/scanner/utils"
|
"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 {
|
type Advisory struct {
|
||||||
vs python.VulnSrc
|
vs python.VulnSrc
|
||||||
|
comparer comparer.Comparer
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewAdvisory is the factory method to return Python Advisory
|
||||||
func NewAdvisory() *Advisory {
|
func NewAdvisory() *Advisory {
|
||||||
return &Advisory{
|
return &Advisory{
|
||||||
vs: python.NewVulnSrc(),
|
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)
|
advisories, err := s.vs.Get(pkgName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, xerrors.Errorf("failed to get python advisories: %w", err)
|
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
|
var vulns []types.DetectedVulnerability
|
||||||
for _, advisory := range advisories {
|
for _, advisory := range advisories {
|
||||||
if !utils.MatchVersions(pkgVer, advisory.Specs) {
|
adv := dbTypes.Advisory{VulnerableVersions: advisory.Specs}
|
||||||
|
if !s.comparer.IsVulnerable(pkgVer, adv) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
vuln := types.DetectedVulnerability{
|
vuln := types.DetectedVulnerability{
|
||||||
VulnerabilityID: advisory.VulnerabilityID,
|
VulnerabilityID: advisory.VulnerabilityID,
|
||||||
PkgName: pkgName,
|
PkgName: pkgName,
|
||||||
InstalledVersion: pkgVer.String(),
|
InstalledVersion: pkgVer,
|
||||||
FixedVersion: createFixedVersions(advisory.Specs),
|
FixedVersion: createFixedVersions(advisory.Specs),
|
||||||
}
|
}
|
||||||
vulns = append(vulns, vuln)
|
vulns = append(vulns, vuln)
|
||||||
|
|||||||
84
pkg/detector/library/python/advisory_test.go
Normal file
84
pkg/detector/library/python/advisory_test.go
Normal 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)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
7
pkg/detector/library/python/testdata/fixtures/invalid-type.yaml
vendored
Normal file
7
pkg/detector/library/python/testdata/fixtures/invalid-type.yaml
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
- bucket: python-safety-db
|
||||||
|
pairs:
|
||||||
|
- bucket: django
|
||||||
|
pairs:
|
||||||
|
- key: CVE-2020-9402
|
||||||
|
value:
|
||||||
|
Specs: foo
|
||||||
14
pkg/detector/library/python/testdata/fixtures/pip.yaml
vendored
Normal file
14
pkg/detector/library/python/testdata/fixtures/pip.yaml
vendored
Normal 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"
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
- bucket: "php::GitHub Security Advisory Composer"
|
- bucket: "composer::GitHub Security Advisory Composer"
|
||||||
pairs:
|
pairs:
|
||||||
- bucket: symfony/symfony
|
- bucket: symfony/symfony
|
||||||
pairs:
|
pairs:
|
||||||
@@ -8,7 +8,7 @@
|
|||||||
- 4.2.7
|
- 4.2.7
|
||||||
VulnerableVersions:
|
VulnerableVersions:
|
||||||
- ">= 4.2.0, < 4.2.7"
|
- ">= 4.2.0, < 4.2.7"
|
||||||
- bucket: "php::php-security-advisories"
|
- bucket: "composer::php-security-advisories"
|
||||||
pairs:
|
pairs:
|
||||||
- bucket: symfony/symfony
|
- bucket: symfony/symfony
|
||||||
pairs:
|
pairs:
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
- bucket: "ruby::ruby-advisory-db"
|
- bucket: "rubygems::ruby-advisory-db"
|
||||||
pairs:
|
pairs:
|
||||||
- bucket: activesupport
|
- bucket: activesupport
|
||||||
pairs:
|
pairs:
|
||||||
|
|||||||
@@ -41,16 +41,19 @@ var (
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Scanner implements the Alpine scanner
|
||||||
type Scanner struct {
|
type Scanner struct {
|
||||||
vs dbTypes.VulnSrc
|
vs dbTypes.VulnSrc
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewScanner is the factory method for Scanner
|
||||||
func NewScanner() *Scanner {
|
func NewScanner() *Scanner {
|
||||||
return &Scanner{
|
return &Scanner{
|
||||||
vs: alpine.NewVulnSrc(),
|
vs: alpine.NewVulnSrc(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Detect vulnerabilities in package using Alpine scanner
|
||||||
func (s *Scanner) Detect(osVer string, pkgs []ftypes.Package) ([]types.DetectedVulnerability, error) {
|
func (s *Scanner) Detect(osVer string, pkgs []ftypes.Package) ([]types.DetectedVulnerability, error) {
|
||||||
log.Logger.Info("Detecting Alpine vulnerabilities...")
|
log.Logger.Info("Detecting Alpine vulnerabilities...")
|
||||||
if strings.Count(osVer, ".") > 1 {
|
if strings.Count(osVer, ".") > 1 {
|
||||||
@@ -94,6 +97,7 @@ func (s *Scanner) Detect(osVer string, pkgs []ftypes.Package) ([]types.DetectedV
|
|||||||
return vulns, nil
|
return vulns, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsSupportedVersion checks the OSFamily can be scanned using Alpine scanner
|
||||||
func (s *Scanner) IsSupportedVersion(osFamily, osVer string) bool {
|
func (s *Scanner) IsSupportedVersion(osFamily, osVer string) bool {
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
return s.isSupportedVersion(now, osFamily, osVer)
|
return s.isSupportedVersion(now, osFamily, osVer)
|
||||||
|
|||||||
@@ -15,11 +15,13 @@ import (
|
|||||||
"github.com/aquasecurity/trivy/pkg/types"
|
"github.com/aquasecurity/trivy/pkg/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Scanner to scan amazon vulnerabilities
|
||||||
type Scanner struct {
|
type Scanner struct {
|
||||||
l *zap.SugaredLogger
|
l *zap.SugaredLogger
|
||||||
ac dbTypes.VulnSrc
|
ac dbTypes.VulnSrc
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewScanner is the factory method to return Amazon scanner
|
||||||
func NewScanner() *Scanner {
|
func NewScanner() *Scanner {
|
||||||
return &Scanner{
|
return &Scanner{
|
||||||
l: log.Logger,
|
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) {
|
func (s *Scanner) Detect(osVer string, pkgs []ftypes.Package) ([]types.DetectedVulnerability, error) {
|
||||||
log.Logger.Info("Detecting Amazon Linux vulnerabilities...")
|
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
|
return vulns, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsSupportedVersion checks if os can be scanned using amazon scanner
|
||||||
func (s *Scanner) IsSupportedVersion(osFamily, osVer string) bool {
|
func (s *Scanner) IsSupportedVersion(osFamily, osVer string) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,11 +40,13 @@ var (
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Scanner implements the Debian scanner
|
||||||
type Scanner struct {
|
type Scanner struct {
|
||||||
ovalVs dbTypes.VulnSrc
|
ovalVs dbTypes.VulnSrc
|
||||||
vs dbTypes.VulnSrc
|
vs dbTypes.VulnSrc
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewScanner is the factory method to return Scanner
|
||||||
func NewScanner() *Scanner {
|
func NewScanner() *Scanner {
|
||||||
return &Scanner{
|
return &Scanner{
|
||||||
ovalVs: debianoval.NewVulnSrc(),
|
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) {
|
func (s *Scanner) Detect(osVer string, pkgs []ftypes.Package) ([]types.DetectedVulnerability, error) {
|
||||||
log.Logger.Info("Detecting Debian vulnerabilities...")
|
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 {
|
for _, adv := range advisories {
|
||||||
fixedVersion, err := version.NewVersion(adv.FixedVersion)
|
var fixedVersion version.Version
|
||||||
|
fixedVersion, err = version.NewVersion(adv.FixedVersion)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Logger.Debugf("failed to parse Debian package version: %w", err)
|
log.Logger.Debugf("failed to parse Debian package version: %w", err)
|
||||||
continue
|
continue
|
||||||
@@ -115,6 +119,7 @@ func (s *Scanner) Detect(osVer string, pkgs []ftypes.Package) ([]types.DetectedV
|
|||||||
return vulns, nil
|
return vulns, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsSupportedVersion checks is OSFamily can be scanned using Debian
|
||||||
func (s *Scanner) IsSupportedVersion(osFamily, osVer string) bool {
|
func (s *Scanner) IsSupportedVersion(osFamily, osVer string) bool {
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
return s.isSupportedVersion(now, osFamily, osVer)
|
return s.isSupportedVersion(now, osFamily, osVer)
|
||||||
|
|||||||
@@ -21,25 +21,31 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
// ErrUnsupportedOS defines error for unsupported OS
|
||||||
ErrUnsupportedOS = xerrors.New("unsupported os")
|
ErrUnsupportedOS = xerrors.New("unsupported os")
|
||||||
|
|
||||||
|
// SuperSet binds dependencies for OS scan
|
||||||
SuperSet = wire.NewSet(
|
SuperSet = wire.NewSet(
|
||||||
wire.Struct(new(Detector)),
|
wire.Struct(new(Detector)),
|
||||||
wire.Bind(new(Operation), new(Detector)),
|
wire.Bind(new(Operation), new(Detector)),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Operation defines operation of OSpkg scan
|
||||||
type Operation interface {
|
type Operation interface {
|
||||||
Detect(string, string, string, time.Time, []ftypes.Package) ([]types.DetectedVulnerability, bool, error)
|
Detect(string, string, string, time.Time, []ftypes.Package) ([]types.DetectedVulnerability, bool, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Driver defines operations for OS package scan
|
||||||
type Driver interface {
|
type Driver interface {
|
||||||
Detect(string, []ftypes.Package) ([]types.DetectedVulnerability, error)
|
Detect(string, []ftypes.Package) ([]types.DetectedVulnerability, error)
|
||||||
IsSupportedVersion(string, string) bool
|
IsSupportedVersion(string, string) bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Detector implements Operation
|
||||||
type Detector struct{}
|
type Detector struct{}
|
||||||
|
|
||||||
|
// Detect detects the vulnerabilities
|
||||||
func (d Detector) Detect(_, osFamily, osName string, _ time.Time, pkgs []ftypes.Package) ([]types.DetectedVulnerability, bool, error) {
|
func (d Detector) Detect(_, osFamily, osName string, _ time.Time, pkgs []ftypes.Package) ([]types.DetectedVulnerability, bool, error) {
|
||||||
driver := newDriver(osFamily, osName)
|
driver := newDriver(osFamily, osName)
|
||||||
if driver == nil {
|
if driver == nil {
|
||||||
@@ -56,31 +62,31 @@ func (d Detector) Detect(_, osFamily, osName string, _ time.Time, pkgs []ftypes.
|
|||||||
return vulns, eosl, nil
|
return vulns, eosl, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// nolint: gocyclo
|
||||||
|
// TODO: fix cyclometic complexity by removing default
|
||||||
func newDriver(osFamily, osName string) Driver {
|
func newDriver(osFamily, osName string) Driver {
|
||||||
// TODO: use DI and change struct names
|
// TODO: use DI and change struct names
|
||||||
var d Driver
|
|
||||||
switch osFamily {
|
switch osFamily {
|
||||||
case fos.Alpine:
|
case fos.Alpine:
|
||||||
d = alpine.NewScanner()
|
return alpine.NewScanner()
|
||||||
case fos.Debian:
|
case fos.Debian:
|
||||||
d = debian.NewScanner()
|
return debian.NewScanner()
|
||||||
case fos.Ubuntu:
|
case fos.Ubuntu:
|
||||||
d = ubuntu.NewScanner()
|
return ubuntu.NewScanner()
|
||||||
case fos.RedHat, fos.CentOS:
|
case fos.RedHat, fos.CentOS:
|
||||||
d = redhat.NewScanner()
|
return redhat.NewScanner()
|
||||||
case fos.Amazon:
|
case fos.Amazon:
|
||||||
d = amazon.NewScanner()
|
return amazon.NewScanner()
|
||||||
case fos.Oracle:
|
case fos.Oracle:
|
||||||
d = oracle.NewScanner()
|
return oracle.NewScanner()
|
||||||
case fos.OpenSUSELeap:
|
case fos.OpenSUSELeap:
|
||||||
d = suse.NewScanner(suse.OpenSUSE)
|
return suse.NewScanner(suse.OpenSUSE)
|
||||||
case fos.SLES:
|
case fos.SLES:
|
||||||
d = suse.NewScanner(suse.SUSEEnterpriseLinux)
|
return suse.NewScanner(suse.SUSEEnterpriseLinux)
|
||||||
case fos.Photon:
|
case fos.Photon:
|
||||||
d = photon.NewScanner()
|
return photon.NewScanner()
|
||||||
default:
|
default:
|
||||||
log.Logger.Warnf("unsupported os : %s", osFamily)
|
log.Logger.Warnf("unsupported os : %s", osFamily)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return d
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,18 +4,16 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
oracleoval "github.com/aquasecurity/trivy-db/pkg/vulnsrc/oracle-oval"
|
|
||||||
version "github.com/knqyf263/go-rpm-version"
|
version "github.com/knqyf263/go-rpm-version"
|
||||||
|
|
||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
|
"k8s.io/utils/clock"
|
||||||
|
|
||||||
ftypes "github.com/aquasecurity/fanal/types"
|
ftypes "github.com/aquasecurity/fanal/types"
|
||||||
dbTypes "github.com/aquasecurity/trivy-db/pkg/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/log"
|
||||||
"github.com/aquasecurity/trivy/pkg/scanner/utils"
|
"github.com/aquasecurity/trivy/pkg/scanner/utils"
|
||||||
"github.com/aquasecurity/trivy/pkg/types"
|
"github.com/aquasecurity/trivy/pkg/types"
|
||||||
|
|
||||||
"k8s.io/utils/clock"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -32,11 +30,13 @@ var (
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Scanner implements oracle vulnerability scanner
|
||||||
type Scanner struct {
|
type Scanner struct {
|
||||||
vs dbTypes.VulnSrc
|
vs dbTypes.VulnSrc
|
||||||
clock clock.Clock
|
clock clock.Clock
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewScanner is the factory method to return oracle vulnerabilities
|
||||||
func NewScanner() *Scanner {
|
func NewScanner() *Scanner {
|
||||||
return &Scanner{
|
return &Scanner{
|
||||||
vs: oracleoval.NewVulnSrc(),
|
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) {
|
func (s *Scanner) Detect(osVer string, pkgs []ftypes.Package) ([]types.DetectedVulnerability, error) {
|
||||||
log.Logger.Info("Detecting Oracle Linux vulnerabilities...")
|
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)
|
installed := utils.FormatVersion(pkg)
|
||||||
installedVersion := version.NewVersion(installed)
|
installedVersion := version.NewVersion(installed)
|
||||||
for _, adv := range advisories {
|
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)
|
fixedVersion := version.NewVersion(adv.FixedVersion)
|
||||||
vuln := types.DetectedVulnerability{
|
vuln := types.DetectedVulnerability{
|
||||||
VulnerabilityID: adv.VulnerabilityID,
|
VulnerabilityID: adv.VulnerabilityID,
|
||||||
@@ -81,6 +85,7 @@ func (s *Scanner) Detect(osVer string, pkgs []ftypes.Package) ([]types.DetectedV
|
|||||||
return vulns, nil
|
return vulns, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsSupportedVersion checks is OSFamily can be scanned with Oracle scanner
|
||||||
func (s *Scanner) IsSupportedVersion(osFamily, osVer string) bool {
|
func (s *Scanner) IsSupportedVersion(osFamily, osVer string) bool {
|
||||||
if strings.Count(osVer, ".") > 0 {
|
if strings.Count(osVer, ".") > 0 {
|
||||||
osVer = osVer[:strings.Index(osVer, ".")]
|
osVer = osVer[:strings.Index(osVer, ".")]
|
||||||
|
|||||||
@@ -6,9 +6,10 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
ftypes "github.com/aquasecurity/fanal/types"
|
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/types"
|
||||||
|
"github.com/aquasecurity/trivy/pkg/utils"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
oracleoval "github.com/aquasecurity/trivy-db/pkg/vulnsrc/oracle-oval"
|
oracleoval "github.com/aquasecurity/trivy-db/pkg/vulnsrc/oracle-oval"
|
||||||
"github.com/aquasecurity/trivy/pkg/log"
|
"github.com/aquasecurity/trivy/pkg/log"
|
||||||
@@ -17,25 +18,6 @@ import (
|
|||||||
clocktesting "k8s.io/utils/clock/testing"
|
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) {
|
func TestMain(m *testing.M) {
|
||||||
log.InitLogger(false, false)
|
log.InitLogger(false, false)
|
||||||
os.Exit(m.Run())
|
os.Exit(m.Run())
|
||||||
@@ -120,45 +102,127 @@ func TestScanner_IsSupportedVersion(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestScanner_Detect(t *testing.T) {
|
func TestScanner_Detect(t *testing.T) {
|
||||||
t.Run("happy path", func(t *testing.T) {
|
type args struct {
|
||||||
s := &Scanner{
|
osVer string
|
||||||
vs: MockOracleConfig{
|
pkgs []ftypes.Package
|
||||||
get: func(s string, s2 string) (advisories []dbTypes.Advisory, err error) {
|
}
|
||||||
return []dbTypes.Advisory{
|
tests := []struct {
|
||||||
{
|
name string
|
||||||
VulnerabilityID: "oracle-123",
|
args args
|
||||||
FixedVersion: "3.0.0",
|
fixtures []string
|
||||||
},
|
want []types.DetectedVulnerability
|
||||||
}, nil
|
wantErr string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
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",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
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{
|
for _, tt := range tests {
|
||||||
{
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
Name: "testpkg",
|
dir := utils.InitTestDB(t, tt.fixtures)
|
||||||
Version: "2.1.0",
|
defer os.RemoveAll(dir)
|
||||||
Release: "hotfix",
|
|
||||||
SrcRelease: "test-hotfix",
|
s := NewScanner()
|
||||||
SrcVersion: "2.1.0",
|
got, err := s.Detect(tt.args.osVer, tt.args.pkgs)
|
||||||
Layer: ftypes.Layer{
|
if tt.wantErr != "" {
|
||||||
DiffID: "sha256:932da51564135c98a49a34a193d6cd363d8fa4184d957fde16c9d8527b3f3b02",
|
require.NotNil(t, err)
|
||||||
},
|
assert.Contains(t, err.Error(), tt.wantErr)
|
||||||
},
|
return
|
||||||
|
} else {
|
||||||
|
assert.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Equal(t, tt.want, got)
|
||||||
})
|
})
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|||||||
9
pkg/detector/ospkg/oracle/testdata/fixtures/invalid-type.yaml
vendored
Normal file
9
pkg/detector/ospkg/oracle/testdata/fixtures/invalid-type.yaml
vendored
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
- bucket: Oracle Linux 7
|
||||||
|
pairs:
|
||||||
|
- bucket: curl
|
||||||
|
pairs:
|
||||||
|
- key: CVE-2020-8177
|
||||||
|
value:
|
||||||
|
FixedVersion:
|
||||||
|
- foo
|
||||||
|
- bar
|
||||||
12
pkg/detector/ospkg/oracle/testdata/fixtures/oracle7.yaml
vendored
Normal file
12
pkg/detector/ospkg/oracle/testdata/fixtures/oracle7.yaml
vendored
Normal 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"
|
||||||
@@ -1,31 +1,30 @@
|
|||||||
package photon
|
package photon
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/aquasecurity/trivy-db/pkg/vulnsrc/photon"
|
|
||||||
version "github.com/knqyf263/go-rpm-version"
|
version "github.com/knqyf263/go-rpm-version"
|
||||||
|
|
||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
|
"k8s.io/utils/clock"
|
||||||
|
|
||||||
ftypes "github.com/aquasecurity/fanal/types"
|
ftypes "github.com/aquasecurity/fanal/types"
|
||||||
dbTypes "github.com/aquasecurity/trivy-db/pkg/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/log"
|
||||||
"github.com/aquasecurity/trivy/pkg/scanner/utils"
|
"github.com/aquasecurity/trivy/pkg/scanner/utils"
|
||||||
"github.com/aquasecurity/trivy/pkg/types"
|
"github.com/aquasecurity/trivy/pkg/types"
|
||||||
|
|
||||||
"k8s.io/utils/clock"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
// EOL can't be found for photon https://github.com/vmware/photon/issues/1031
|
||||||
eolDates = map[string]time.Time{}
|
//var (
|
||||||
)
|
// eolDates = map[string]time.Time{}
|
||||||
|
//)
|
||||||
|
|
||||||
|
// Scanner implements Photon scanner
|
||||||
type Scanner struct {
|
type Scanner struct {
|
||||||
vs dbTypes.VulnSrc
|
vs dbTypes.VulnSrc
|
||||||
clock clock.Clock
|
clock clock.Clock
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewScanner is the factory method for Scanner
|
||||||
func NewScanner() *Scanner {
|
func NewScanner() *Scanner {
|
||||||
return &Scanner{
|
return &Scanner{
|
||||||
vs: photon.NewVulnSrc(),
|
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) {
|
func (s *Scanner) Detect(osVer string, pkgs []ftypes.Package) ([]types.DetectedVulnerability, error) {
|
||||||
log.Logger.Info("Detecting Photon Linux vulnerabilities...")
|
log.Logger.Info("Detecting Photon Linux vulnerabilities...")
|
||||||
log.Logger.Debugf("Photon Linux: os version: %s", osVer)
|
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
|
return vulns, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsSupportedVersion checks is OSFamily can be scanned
|
||||||
func (s *Scanner) IsSupportedVersion(osFamily, osVer string) bool {
|
func (s *Scanner) IsSupportedVersion(osFamily, osVer string) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,14 +4,13 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/aquasecurity/trivy-db/pkg/vulnsrc/redhat"
|
|
||||||
|
|
||||||
version "github.com/knqyf263/go-rpm-version"
|
version "github.com/knqyf263/go-rpm-version"
|
||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
"github.com/aquasecurity/fanal/analyzer/os"
|
"github.com/aquasecurity/fanal/analyzer/os"
|
||||||
ftypes "github.com/aquasecurity/fanal/types"
|
ftypes "github.com/aquasecurity/fanal/types"
|
||||||
dbTypes "github.com/aquasecurity/trivy-db/pkg/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/log"
|
||||||
"github.com/aquasecurity/trivy/pkg/scanner/utils"
|
"github.com/aquasecurity/trivy/pkg/scanner/utils"
|
||||||
"github.com/aquasecurity/trivy/pkg/types"
|
"github.com/aquasecurity/trivy/pkg/types"
|
||||||
@@ -35,18 +34,24 @@ var (
|
|||||||
// N/A
|
// N/A
|
||||||
"8": time.Date(3000, 6, 30, 23, 59, 59, 0, time.UTC),
|
"8": time.Date(3000, 6, 30, 23, 59, 59, 0, time.UTC),
|
||||||
}
|
}
|
||||||
|
excludedVendorsSuffix = []string{
|
||||||
|
".remi",
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Scanner implements the Redhat scanner
|
||||||
type Scanner struct {
|
type Scanner struct {
|
||||||
vs dbTypes.VulnSrc
|
vs dbTypes.VulnSrc
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewScanner is the factory method for Scanner
|
||||||
func NewScanner() *Scanner {
|
func NewScanner() *Scanner {
|
||||||
return &Scanner{
|
return &Scanner{
|
||||||
vs: redhat.NewVulnSrc(),
|
vs: redhat.NewVulnSrc(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Detect scans and returns redhat vulenrabilities
|
||||||
func (s *Scanner) Detect(osVer string, pkgs []ftypes.Package) ([]types.DetectedVulnerability, error) {
|
func (s *Scanner) Detect(osVer string, pkgs []ftypes.Package) ([]types.DetectedVulnerability, error) {
|
||||||
log.Logger.Info("Detecting RHEL/CentOS vulnerabilities...")
|
log.Logger.Info("Detecting RHEL/CentOS vulnerabilities...")
|
||||||
if strings.Count(osVer, ".") > 0 {
|
if strings.Count(osVer, ".") > 0 {
|
||||||
@@ -57,6 +62,11 @@ func (s *Scanner) Detect(osVer string, pkgs []ftypes.Package) ([]types.DetectedV
|
|||||||
|
|
||||||
var vulns []types.DetectedVulnerability
|
var vulns []types.DetectedVulnerability
|
||||||
for _, pkg := range pkgs {
|
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
|
// For Red Hat Security Data API containing only source package names
|
||||||
advisories, err := s.vs.Get(osVer, pkg.SrcName)
|
advisories, err := s.vs.Get(osVer, pkg.SrcName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -102,6 +112,7 @@ func (s *Scanner) Detect(osVer string, pkgs []ftypes.Package) ([]types.DetectedV
|
|||||||
return vulns, nil
|
return vulns, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsSupportedVersion checks is OSFamily can be scanned with Redhat scanner
|
||||||
func (s *Scanner) IsSupportedVersion(osFamily, osVer string) bool {
|
func (s *Scanner) IsSupportedVersion(osFamily, osVer string) bool {
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
return s.isSupportedVersion(now, osFamily, osVer)
|
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)
|
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
|
||||||
|
}
|
||||||
|
|||||||
@@ -208,6 +208,45 @@ func TestScanner_Detect(t *testing.T) {
|
|||||||
},
|
},
|
||||||
wantErr: true,
|
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 {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ import (
|
|||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
"k8s.io/utils/clock"
|
"k8s.io/utils/clock"
|
||||||
|
|
||||||
|
version "github.com/knqyf263/go-rpm-version"
|
||||||
|
|
||||||
fos "github.com/aquasecurity/fanal/analyzer/os"
|
fos "github.com/aquasecurity/fanal/analyzer/os"
|
||||||
ftypes "github.com/aquasecurity/fanal/types"
|
ftypes "github.com/aquasecurity/fanal/types"
|
||||||
dbTypes "github.com/aquasecurity/trivy-db/pkg/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/log"
|
||||||
"github.com/aquasecurity/trivy/pkg/scanner/utils"
|
"github.com/aquasecurity/trivy/pkg/scanner/utils"
|
||||||
"github.com/aquasecurity/trivy/pkg/types"
|
"github.com/aquasecurity/trivy/pkg/types"
|
||||||
version "github.com/knqyf263/go-rpm-version"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -38,7 +39,9 @@ var (
|
|||||||
"15": time.Date(2019, 12, 31, 23, 59, 59, 0, time.UTC),
|
"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),
|
"15.1": time.Date(2021, 1, 31, 23, 59, 59, 0, time.UTC),
|
||||||
// 6 months after SLES 15 SP3 release
|
// 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{
|
opensuseEolDates = map[string]time.Time{
|
||||||
@@ -52,20 +55,24 @@ var (
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Scanner implements suse scanner
|
||||||
type Scanner struct {
|
type Scanner struct {
|
||||||
vs dbTypes.VulnSrc
|
vs dbTypes.VulnSrc
|
||||||
clock clock.Clock
|
clock clock.Clock
|
||||||
family string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type SUSEType int
|
// Type to define SUSE type
|
||||||
|
type Type int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
SUSEEnterpriseLinux SUSEType = iota
|
// SUSEEnterpriseLinux is Linux Enterprise version
|
||||||
|
SUSEEnterpriseLinux Type = iota
|
||||||
|
// OpenSUSE for open versions
|
||||||
OpenSUSE
|
OpenSUSE
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewScanner(t SUSEType) *Scanner {
|
// NewScanner is the factory method for Scanner
|
||||||
|
func NewScanner(t Type) *Scanner {
|
||||||
switch t {
|
switch t {
|
||||||
case SUSEEnterpriseLinux:
|
case SUSEEnterpriseLinux:
|
||||||
return &Scanner{
|
return &Scanner{
|
||||||
@@ -81,6 +88,7 @@ func NewScanner(t SUSEType) *Scanner {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Detect scans and returns the vulnerabilities
|
||||||
func (s *Scanner) Detect(osVer string, pkgs []ftypes.Package) ([]types.DetectedVulnerability, error) {
|
func (s *Scanner) Detect(osVer string, pkgs []ftypes.Package) ([]types.DetectedVulnerability, error) {
|
||||||
log.Logger.Info("Detecting SUSE vulnerabilities...")
|
log.Logger.Info("Detecting SUSE vulnerabilities...")
|
||||||
log.Logger.Debugf("SUSE: os version: %s", osVer)
|
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
|
return vulns, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsSupportedVersion checks if OSFamily can be scanned using SUSE scanner
|
||||||
func (s *Scanner) IsSupportedVersion(osFamily, osVer string) bool {
|
func (s *Scanner) IsSupportedVersion(osFamily, osVer string) bool {
|
||||||
var eolDate time.Time
|
var eolDate time.Time
|
||||||
var ok bool
|
var ok bool
|
||||||
|
|||||||
@@ -51,16 +51,19 @@ var (
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Scanner implements the Ubuntu scanner
|
||||||
type Scanner struct {
|
type Scanner struct {
|
||||||
vs dbTypes.VulnSrc
|
vs dbTypes.VulnSrc
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewScanner is the factory method for Scanner
|
||||||
func NewScanner() *Scanner {
|
func NewScanner() *Scanner {
|
||||||
return &Scanner{
|
return &Scanner{
|
||||||
vs: ubuntu.NewVulnSrc(),
|
vs: ubuntu.NewVulnSrc(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Detect scans and returns the vulnerabilities
|
||||||
func (s *Scanner) Detect(osVer string, pkgs []ftypes.Package) ([]types.DetectedVulnerability, error) {
|
func (s *Scanner) Detect(osVer string, pkgs []ftypes.Package) ([]types.DetectedVulnerability, error) {
|
||||||
log.Logger.Info("Detecting Ubuntu vulnerabilities...")
|
log.Logger.Info("Detecting Ubuntu vulnerabilities...")
|
||||||
log.Logger.Debugf("ubuntu: os version: %s", osVer)
|
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
|
return vulns, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsSupportedVersion checks is OSFamily can be scanned using Ubuntu scanner
|
||||||
func (s *Scanner) IsSupportedVersion(osFamily, osVer string) bool {
|
func (s *Scanner) IsSupportedVersion(osFamily, osVer string) bool {
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
return s.isSupportedVersion(now, osFamily, osVer)
|
return s.isSupportedVersion(now, osFamily, osVer)
|
||||||
|
|||||||
@@ -10,11 +10,12 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/aquasecurity/trivy-db/pkg/db"
|
|
||||||
"github.com/aquasecurity/trivy/pkg/log"
|
|
||||||
"github.com/google/go-github/v28/github"
|
"github.com/google/go-github/v28/github"
|
||||||
"golang.org/x/oauth2"
|
"golang.org/x/oauth2"
|
||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
|
"github.com/aquasecurity/trivy-db/pkg/db"
|
||||||
|
"github.com/aquasecurity/trivy/pkg/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -22,11 +23,13 @@ const (
|
|||||||
repo = "trivy-db"
|
repo = "trivy-db"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// RepositoryInterface defines the operations on repository
|
||||||
type RepositoryInterface interface {
|
type RepositoryInterface interface {
|
||||||
ListReleases(ctx context.Context, opt *github.ListOptions) ([]*github.RepositoryRelease, *github.Response, error)
|
ListReleases(ctx context.Context, opt *github.ListOptions) ([]*github.RepositoryRelease, *github.Response, error)
|
||||||
DownloadAsset(ctx context.Context, id int64) (io.ReadCloser, string, error)
|
DownloadAsset(ctx context.Context, id int64) (io.ReadCloser, string, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Repository implements RepositoryInterface
|
||||||
type Repository struct {
|
type Repository struct {
|
||||||
repository *github.RepositoriesService
|
repository *github.RepositoriesService
|
||||||
git *github.GitService
|
git *github.GitService
|
||||||
@@ -34,22 +37,27 @@ type Repository struct {
|
|||||||
repoName string
|
repoName string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ListReleases returns all github releases on repository
|
||||||
func (r Repository) ListReleases(ctx context.Context, opt *github.ListOptions) ([]*github.RepositoryRelease, *github.Response, error) {
|
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)
|
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) {
|
func (r Repository) DownloadAsset(ctx context.Context, id int64) (io.ReadCloser, string, error) {
|
||||||
return r.repository.DownloadReleaseAsset(ctx, r.owner, r.repoName, id)
|
return r.repository.DownloadReleaseAsset(ctx, r.owner, r.repoName, id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Operation defines the file operations
|
||||||
type Operation interface {
|
type Operation interface {
|
||||||
DownloadDB(ctx context.Context, fileName string) (io.ReadCloser, int, error)
|
DownloadDB(ctx context.Context, fileName string) (io.ReadCloser, int, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Client implements RepositoryInterface
|
||||||
type Client struct {
|
type Client struct {
|
||||||
Repository RepositoryInterface
|
Repository RepositoryInterface
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewClient is the factory method to return Client for RepositoryInterface operations
|
||||||
func NewClient() Client {
|
func NewClient() Client {
|
||||||
var client *http.Client
|
var client *http.Client
|
||||||
githubToken := os.Getenv("GITHUB_TOKEN")
|
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) {
|
func (c Client) DownloadDB(ctx context.Context, fileName string) (io.ReadCloser, int, error) {
|
||||||
options := github.ListOptions{}
|
options := github.ListOptions{}
|
||||||
releases, _, err := c.Repository.ListReleases(ctx, &options)
|
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)
|
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 {
|
if err != nil || resp.StatusCode != http.StatusOK {
|
||||||
return nil, 0, xerrors.Errorf("unable to download the asset via URL: %w", err)
|
return nil, 0, xerrors.Errorf("unable to download the asset via URL: %w", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,14 +6,17 @@ import (
|
|||||||
"github.com/cheggaaa/pb/v3"
|
"github.com/cheggaaa/pb/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// ProgressBar exports method to track the progress of jobs
|
||||||
type ProgressBar struct {
|
type ProgressBar struct {
|
||||||
quiet bool
|
quiet bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewProgressBar is the factory method to return progressBar object
|
||||||
func NewProgressBar(quiet bool) ProgressBar {
|
func NewProgressBar(quiet bool) ProgressBar {
|
||||||
return ProgressBar{quiet: quiet}
|
return ProgressBar{quiet: quiet}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Start starts the progress tracking
|
||||||
func (p ProgressBar) Start(total int64) Bar {
|
func (p ProgressBar) Start(total int64) Bar {
|
||||||
if p.quiet {
|
if p.quiet {
|
||||||
return Bar{}
|
return Bar{}
|
||||||
@@ -22,16 +25,20 @@ func (p ProgressBar) Start(total int64) Bar {
|
|||||||
return Bar{bar: bar}
|
return Bar{bar: bar}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Bar is the proxy progress bar
|
||||||
type Bar struct {
|
type Bar struct {
|
||||||
bar *pb.ProgressBar
|
bar *pb.ProgressBar
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewProxyReader is the factory method to track the progress
|
||||||
func (b Bar) NewProxyReader(r io.Reader) io.Reader {
|
func (b Bar) NewProxyReader(r io.Reader) io.Reader {
|
||||||
if b.bar == nil {
|
if b.bar == nil {
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
return b.bar.NewProxyReader(r)
|
return b.bar.NewProxyReader(r)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Finish finishes the progress tracking
|
||||||
func (b Bar) Finish() {
|
func (b Bar) Finish() {
|
||||||
if b.bar == nil {
|
if b.bar == nil {
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -9,10 +9,12 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
// Logger is the global variable for logging
|
||||||
Logger *zap.SugaredLogger
|
Logger *zap.SugaredLogger
|
||||||
debugOption bool
|
debugOption bool
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// InitLogger initialize the logger variable
|
||||||
func InitLogger(debug, disable bool) (err error) {
|
func InitLogger(debug, disable bool) (err error) {
|
||||||
debugOption = debug
|
debugOption = debug
|
||||||
Logger, err = NewLogger(debug, disable)
|
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) {
|
func NewLogger(debug, disable bool) (*zap.SugaredLogger, error) {
|
||||||
// First, define our level-handling logic.
|
// First, define our level-handling logic.
|
||||||
errorPriority := zap.LevelEnablerFunc(func(lvl zapcore.Level) bool {
|
errorPriority := zap.LevelEnablerFunc(func(lvl zapcore.Level) bool {
|
||||||
@@ -78,6 +81,7 @@ func NewLogger(debug, disable bool) (*zap.SugaredLogger, error) {
|
|||||||
return logger.Sugar(), nil
|
return logger.Sugar(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fatal for logging fatal errors
|
||||||
func Fatal(err error) {
|
func Fatal(err error) {
|
||||||
if debugOption {
|
if debugOption {
|
||||||
Logger.Fatalf("%+v", err)
|
Logger.Fatalf("%+v", err)
|
||||||
|
|||||||
@@ -13,19 +13,22 @@ import (
|
|||||||
"text/template"
|
"text/template"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/olekukonko/tablewriter"
|
||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
ftypes "github.com/aquasecurity/fanal/types"
|
ftypes "github.com/aquasecurity/fanal/types"
|
||||||
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
|
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
|
||||||
"github.com/aquasecurity/trivy/pkg/types"
|
"github.com/aquasecurity/trivy/pkg/types"
|
||||||
"github.com/aquasecurity/trivy/pkg/utils"
|
"github.com/aquasecurity/trivy/pkg/utils"
|
||||||
"github.com/olekukonko/tablewriter"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Now returns the current time
|
||||||
var Now = time.Now
|
var Now = time.Now
|
||||||
|
|
||||||
|
// Results to hold list of Result
|
||||||
type Results []Result
|
type Results []Result
|
||||||
|
|
||||||
|
// Result to hold image scan results
|
||||||
type Result struct {
|
type Result struct {
|
||||||
Target string `json:"Target"`
|
Target string `json:"Target"`
|
||||||
Type string `json:"Type,omitempty"`
|
Type string `json:"Type,omitempty"`
|
||||||
@@ -33,13 +36,14 @@ type Result struct {
|
|||||||
Vulnerabilities []types.DetectedVulnerability `json:"Vulnerabilities"`
|
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 {
|
func WriteResults(format string, output io.Writer, severities []dbTypes.Severity, results Results, outputTemplate string, light bool) error {
|
||||||
var writer Writer
|
var writer Writer
|
||||||
switch format {
|
switch format {
|
||||||
case "table":
|
case "table":
|
||||||
writer = &TableWriter{Output: output, Light: light, Severities: severities}
|
writer = &TableWriter{Output: output, Light: light, Severities: severities}
|
||||||
case "json":
|
case "json":
|
||||||
writer = &JsonWriter{Output: output}
|
writer = &JSONWriter{Output: output}
|
||||||
case "template":
|
case "template":
|
||||||
var err error
|
var err error
|
||||||
if writer, err = NewTemplateWriter(output, outputTemplate); err != nil {
|
if writer, err = NewTemplateWriter(output, outputTemplate); err != nil {
|
||||||
@@ -55,22 +59,28 @@ func WriteResults(format string, output io.Writer, severities []dbTypes.Severity
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Writer defines the result write operation
|
||||||
type Writer interface {
|
type Writer interface {
|
||||||
Write(Results) error
|
Write(Results) error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TableWriter implements Writer and output in tabular form
|
||||||
type TableWriter struct {
|
type TableWriter struct {
|
||||||
Severities []dbTypes.Severity
|
Severities []dbTypes.Severity
|
||||||
Output io.Writer
|
Output io.Writer
|
||||||
Light bool
|
Light bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Write writes the result on standard output
|
||||||
func (tw TableWriter) Write(results Results) error {
|
func (tw TableWriter) Write(results Results) error {
|
||||||
for _, result := range results {
|
for _, result := range results {
|
||||||
tw.write(result)
|
tw.write(result)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// nolint: gocyclo
|
||||||
|
// TODO: refactror and fix cyclometic complexity
|
||||||
func (tw TableWriter) write(result Result) {
|
func (tw TableWriter) write(result Result) {
|
||||||
table := tablewriter.NewWriter(tw.Output)
|
table := tablewriter.NewWriter(tw.Output)
|
||||||
header := []string{"Library", "Vulnerability ID", "Severity", "Installed Version", "Fixed Version"}
|
header := []string{"Library", "Vulnerability ID", "Severity", "Installed Version", "Fixed Version"}
|
||||||
@@ -134,11 +144,13 @@ func (tw TableWriter) write(result Result) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
type JsonWriter struct {
|
// JSONWriter implements result Writer
|
||||||
|
type JSONWriter struct {
|
||||||
Output io.Writer
|
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, "", " ")
|
output, err := json.MarshalIndent(results, "", " ")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return xerrors.Errorf("failed to marshal json: %w", err)
|
return xerrors.Errorf("failed to marshal json: %w", err)
|
||||||
@@ -150,11 +162,13 @@ func (jw JsonWriter) Write(results Results) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TemplateWriter write result in custom format defined by user's template
|
||||||
type TemplateWriter struct {
|
type TemplateWriter struct {
|
||||||
Output io.Writer
|
Output io.Writer
|
||||||
Template *template.Template
|
Template *template.Template
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewTemplateWriter is the factory method to return TemplateWriter object
|
||||||
func NewTemplateWriter(output io.Writer, outputTemplate string) (*TemplateWriter, error) {
|
func NewTemplateWriter(output io.Writer, outputTemplate string) (*TemplateWriter, error) {
|
||||||
if strings.HasPrefix(outputTemplate, "@") {
|
if strings.HasPrefix(outputTemplate, "@") {
|
||||||
buf, err := ioutil.ReadFile(strings.TrimPrefix(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
|
return &TemplateWriter{Output: output, Template: tmpl}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Write writes result
|
||||||
func (tw TemplateWriter) Write(results Results) error {
|
func (tw TemplateWriter) Write(results Results) error {
|
||||||
err := tw.Template.Execute(tw.Output, results)
|
err := tw.Template.Execute(tw.Output, results)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -175,7 +175,7 @@ func TestReportWriter_JSON(t *testing.T) {
|
|||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
|
||||||
jw := report.JsonWriter{}
|
jw := report.JSONWriter{}
|
||||||
jsonWritten := bytes.Buffer{}
|
jsonWritten := bytes.Buffer{}
|
||||||
jw.Output = &jsonWritten
|
jw.Output = &jsonWritten
|
||||||
|
|
||||||
|
|||||||
@@ -16,28 +16,35 @@ import (
|
|||||||
rpc "github.com/aquasecurity/trivy/rpc/scanner"
|
rpc "github.com/aquasecurity/trivy/rpc/scanner"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// SuperSet binds the dependencies for RPC client
|
||||||
var SuperSet = wire.NewSet(
|
var SuperSet = wire.NewSet(
|
||||||
NewProtobufClient,
|
NewProtobufClient,
|
||||||
NewScanner,
|
NewScanner,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// RemoteURL for RPC remote host
|
||||||
type RemoteURL string
|
type RemoteURL string
|
||||||
|
|
||||||
|
// NewProtobufClient is the factory method to return RPC scanner
|
||||||
func NewProtobufClient(remoteURL RemoteURL) rpc.Scanner {
|
func NewProtobufClient(remoteURL RemoteURL) rpc.Scanner {
|
||||||
return rpc.NewScannerProtobufClient(string(remoteURL), &http.Client{})
|
return rpc.NewScannerProtobufClient(string(remoteURL), &http.Client{})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CustomHeaders for holding HTTP headers
|
||||||
type CustomHeaders http.Header
|
type CustomHeaders http.Header
|
||||||
|
|
||||||
|
// Scanner implements the RPC scanner
|
||||||
type Scanner struct {
|
type Scanner struct {
|
||||||
customHeaders CustomHeaders
|
customHeaders CustomHeaders
|
||||||
client rpc.Scanner
|
client rpc.Scanner
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewScanner is the factory method to return RPC Scanner
|
||||||
func NewScanner(customHeaders CustomHeaders, s rpc.Scanner) Scanner {
|
func NewScanner(customHeaders CustomHeaders, s rpc.Scanner) Scanner {
|
||||||
return Scanner{customHeaders: customHeaders, client: s}
|
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) {
|
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))
|
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 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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import (
|
|||||||
"github.com/aquasecurity/trivy/pkg/log"
|
"github.com/aquasecurity/trivy/pkg/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// WithCustomHeaders adds custom headers to request headers
|
||||||
func WithCustomHeaders(ctx context.Context, customHeaders http.Header) context.Context {
|
func WithCustomHeaders(ctx context.Context, customHeaders http.Header) context.Context {
|
||||||
// Attach the headers to a context
|
// Attach the headers to a context
|
||||||
ctxWithToken, err := twirp.WithHTTPRequestHeaders(ctx, customHeaders)
|
ctxWithToken, err := twirp.WithHTTPRequestHeaders(ctx, customHeaders)
|
||||||
|
|||||||
@@ -14,7 +14,8 @@ import (
|
|||||||
"github.com/aquasecurity/trivy/rpc/scanner"
|
"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
|
var rpcPkgs []*common.Package
|
||||||
for _, pkg := range pkgs {
|
for _, pkg := range pkgs {
|
||||||
rpcPkgs = append(rpcPkgs, &common.Package{
|
rpcPkgs = append(rpcPkgs, &common.Package{
|
||||||
@@ -32,7 +33,8 @@ func ConvertToRpcPkgs(pkgs []ftypes.Package) []*common.Package {
|
|||||||
return rpcPkgs
|
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
|
var pkgs []ftypes.Package
|
||||||
for _, pkg := range rpcPkgs {
|
for _, pkg := range rpcPkgs {
|
||||||
pkgs = append(pkgs, ftypes.Package{
|
pkgs = append(pkgs, ftypes.Package{
|
||||||
@@ -50,7 +52,8 @@ func ConvertFromRpcPkgs(rpcPkgs []*common.Package) []ftypes.Package {
|
|||||||
return pkgs
|
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
|
var libs []ftypes.LibraryInfo
|
||||||
for _, l := range rpcLibs {
|
for _, l := range rpcLibs {
|
||||||
libs = append(libs, ftypes.LibraryInfo{
|
libs = append(libs, ftypes.LibraryInfo{
|
||||||
@@ -63,7 +66,8 @@ func ConvertFromRpcLibraries(rpcLibs []*common.Library) []ftypes.LibraryInfo {
|
|||||||
return libs
|
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
|
var rpcLibs []*common.Library
|
||||||
for _, l := range libs {
|
for _, l := range libs {
|
||||||
rpcLibs = append(rpcLibs, &common.Library{
|
rpcLibs = append(rpcLibs, &common.Library{
|
||||||
@@ -74,7 +78,8 @@ func ConvertToRpcLibraries(libs []deptypes.Library) []*common.Library {
|
|||||||
return rpcLibs
|
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
|
var vulns []types.DetectedVulnerability
|
||||||
for _, vuln := range rpcVulns {
|
for _, vuln := range rpcVulns {
|
||||||
severity := dbTypes.Severity(vuln.Severity)
|
severity := dbTypes.Severity(vuln.Severity)
|
||||||
@@ -94,7 +99,8 @@ func ConvertFromRpcVulns(rpcVulns []*common.Vulnerability) []types.DetectedVulne
|
|||||||
return vulns
|
return vulns
|
||||||
}
|
}
|
||||||
|
|
||||||
func ConvertToRpcVulns(vulns []types.DetectedVulnerability) []*common.Vulnerability {
|
// ConvertToRPCVulns returns common.Vulnerability
|
||||||
|
func ConvertToRPCVulns(vulns []types.DetectedVulnerability) []*common.Vulnerability {
|
||||||
var rpcVulns []*common.Vulnerability
|
var rpcVulns []*common.Vulnerability
|
||||||
for _, vuln := range vulns {
|
for _, vuln := range vulns {
|
||||||
severity, err := dbTypes.NewSeverity(vuln.Severity)
|
severity, err := dbTypes.NewSeverity(vuln.Severity)
|
||||||
@@ -132,9 +138,9 @@ func ConvertToRpcVulns(vulns []types.DetectedVulnerability) []*common.Vulnerabil
|
|||||||
return rpcVulns
|
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
|
var results []report.Result
|
||||||
|
|
||||||
for _, result := range rpcResults {
|
for _, result := range rpcResults {
|
||||||
var vulns []types.DetectedVulnerability
|
var vulns []types.DetectedVulnerability
|
||||||
for _, vuln := range result.Vulnerabilities {
|
for _, vuln := range result.Vulnerabilities {
|
||||||
@@ -178,7 +184,8 @@ func ConvertFromRpcResults(rpcResults []*scanner.Result) []report.Result {
|
|||||||
return results
|
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 {
|
if rpcOS == nil {
|
||||||
return 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
|
var pkgInfos []ftypes.PackageInfo
|
||||||
for _, rpcPkgInfo := range rpcPkgInfos {
|
for _, rpcPkgInfo := range rpcPkgInfos {
|
||||||
pkgInfos = append(pkgInfos, ftypes.PackageInfo{
|
pkgInfos = append(pkgInfos, ftypes.PackageInfo{
|
||||||
FilePath: rpcPkgInfo.FilePath,
|
FilePath: rpcPkgInfo.FilePath,
|
||||||
Packages: ConvertFromRpcPkgs(rpcPkgInfo.Packages),
|
Packages: ConvertFromRPCPkgs(rpcPkgInfo.Packages),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return pkgInfos
|
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
|
var apps []ftypes.Application
|
||||||
for _, rpcApp := range rpcApps {
|
for _, rpcApp := range rpcApps {
|
||||||
apps = append(apps, ftypes.Application{
|
apps = append(apps, ftypes.Application{
|
||||||
Type: rpcApp.Type,
|
Type: rpcApp.Type,
|
||||||
FilePath: rpcApp.FilePath,
|
FilePath: rpcApp.FilePath,
|
||||||
Libraries: ConvertFromRpcLibraries(rpcApp.Libraries),
|
Libraries: ConvertFromRPCLibraries(rpcApp.Libraries),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return apps
|
return apps
|
||||||
}
|
}
|
||||||
|
|
||||||
func ConvertFromRpcPutArtifactRequest(req *cache.PutArtifactRequest) ftypes.ArtifactInfo {
|
// ConvertFromRPCPutArtifactRequest converts cache.PutArtifactRequest to fanal.PutArtifactRequest
|
||||||
created, _ := ptypes.Timestamp(req.ArtifactInfo.Created)
|
func ConvertFromRPCPutArtifactRequest(req *cache.PutArtifactRequest) ftypes.ArtifactInfo {
|
||||||
|
created, _ := ptypes.Timestamp(req.ArtifactInfo.Created) // nolint: errcheck
|
||||||
return ftypes.ArtifactInfo{
|
return ftypes.ArtifactInfo{
|
||||||
SchemaVersion: int(req.ArtifactInfo.SchemaVersion),
|
SchemaVersion: int(req.ArtifactInfo.SchemaVersion),
|
||||||
Architecture: req.ArtifactInfo.Architecture,
|
Architecture: req.ArtifactInfo.Architecture,
|
||||||
Created: created,
|
Created: created,
|
||||||
DockerVersion: req.ArtifactInfo.DockerVersion,
|
DockerVersion: req.ArtifactInfo.DockerVersion,
|
||||||
OS: req.ArtifactInfo.Os,
|
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{
|
return ftypes.BlobInfo{
|
||||||
SchemaVersion: int(req.BlobInfo.SchemaVersion),
|
SchemaVersion: int(req.BlobInfo.SchemaVersion),
|
||||||
Digest: req.BlobInfo.Digest,
|
Digest: req.BlobInfo.Digest,
|
||||||
DiffID: req.BlobInfo.DiffId,
|
DiffID: req.BlobInfo.DiffId,
|
||||||
OS: ConvertFromRpcOS(req.BlobInfo.Os),
|
OS: ConvertFromRPCOS(req.BlobInfo.Os),
|
||||||
PackageInfos: ConvertFromRpcPackageInfos(req.BlobInfo.PackageInfos),
|
PackageInfos: ConvertFromRPCPackageInfos(req.BlobInfo.PackageInfos),
|
||||||
Applications: ConvertFromRpcApplications(req.BlobInfo.Applications),
|
Applications: ConvertFromRPCApplications(req.BlobInfo.Applications),
|
||||||
OpaqueDirs: req.BlobInfo.OpaqueDirs,
|
OpaqueDirs: req.BlobInfo.OpaqueDirs,
|
||||||
WhiteoutFiles: req.BlobInfo.WhiteoutFiles,
|
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 {
|
if fos == nil {
|
||||||
return 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)
|
t, err := ptypes.TimestampProto(imageInfo.Created)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Logger.Warnf("invalid timestamp: %s", err)
|
log.Logger.Warnf("invalid timestamp: %s", err)
|
||||||
@@ -260,17 +273,18 @@ func ConvertToRpcArtifactInfo(imageID string, imageInfo ftypes.ArtifactInfo) *ca
|
|||||||
Created: t,
|
Created: t,
|
||||||
DockerVersion: imageInfo.DockerVersion,
|
DockerVersion: imageInfo.DockerVersion,
|
||||||
Os: imageInfo.OS,
|
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
|
var packageInfos []*common.PackageInfo
|
||||||
for _, pkgInfo := range layerInfo.PackageInfos {
|
for _, pkgInfo := range layerInfo.PackageInfos {
|
||||||
packageInfos = append(packageInfos, &common.PackageInfo{
|
packageInfos = append(packageInfos, &common.PackageInfo{
|
||||||
FilePath: pkgInfo.FilePath,
|
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,
|
Name: lib.Library.Name,
|
||||||
Version: lib.Library.Version,
|
Version: lib.Library.Version,
|
||||||
})
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
applications = append(applications, &common.Application{
|
applications = append(applications, &common.Application{
|
||||||
Type: app.Type,
|
Type: app.Type,
|
||||||
@@ -297,7 +310,7 @@ func ConvertToRpcBlobInfo(diffID string, layerInfo ftypes.BlobInfo) *cache.PutBl
|
|||||||
SchemaVersion: ftypes.BlobJSONSchemaVersion,
|
SchemaVersion: ftypes.BlobJSONSchemaVersion,
|
||||||
Digest: layerInfo.Digest,
|
Digest: layerInfo.Digest,
|
||||||
DiffId: layerInfo.DiffID,
|
DiffId: layerInfo.DiffID,
|
||||||
Os: ConvertToRpcOS(layerInfo.OS),
|
Os: ConvertToRPCOS(layerInfo.OS),
|
||||||
PackageInfos: packageInfos,
|
PackageInfos: packageInfos,
|
||||||
Applications: applications,
|
Applications: applications,
|
||||||
OpaqueDirs: layerInfo.OpaqueDirs,
|
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 {
|
func ConvertToMissingBlobsRequest(imageID string, layerIDs []string) *cache.MissingBlobsRequest {
|
||||||
return &cache.MissingBlobsRequest{
|
return &cache.MissingBlobsRequest{
|
||||||
ArtifactId: imageID,
|
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{}
|
rpcOS := &common.OS{}
|
||||||
if os != nil {
|
if os != nil {
|
||||||
rpcOS.Family = os.Family
|
rpcOS.Family = os.Family
|
||||||
@@ -324,7 +339,7 @@ func ConvertToRpcScanResponse(results report.Results, os *ftypes.OS, eosl bool)
|
|||||||
for _, result := range results {
|
for _, result := range results {
|
||||||
rpcResults = append(rpcResults, &scanner.Result{
|
rpcResults = append(rpcResults, &scanner.Result{
|
||||||
Target: result.Target,
|
Target: result.Target,
|
||||||
Vulnerabilities: ConvertToRpcVulns(result.Vulnerabilities),
|
Vulnerabilities: ConvertToRPCVulns(result.Vulnerabilities),
|
||||||
Type: result.Type,
|
Type: result.Type,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ func TestConvertToRpcPkgs(t *testing.T) {
|
|||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
got := ConvertToRpcPkgs(tt.args.pkgs)
|
got := ConvertToRPCPkgs(tt.args.pkgs)
|
||||||
assert.Equal(t, tt.want, got, tt.name)
|
assert.Equal(t, tt.want, got, tt.name)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -113,7 +113,7 @@ func TestConvertFromRpcPkgs(t *testing.T) {
|
|||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
got := ConvertFromRpcPkgs(tt.args.rpcPkgs)
|
got := ConvertFromRPCPkgs(tt.args.rpcPkgs)
|
||||||
assert.Equal(t, tt.want, got, tt.name)
|
assert.Equal(t, tt.want, got, tt.name)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -144,7 +144,7 @@ func TestConvertFromRpcLibraries(t *testing.T) {
|
|||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
got := ConvertFromRpcLibraries(tt.args.rpcLibs)
|
got := ConvertFromRPCLibraries(tt.args.rpcLibs)
|
||||||
assert.Equal(t, got, tt.want, tt.name)
|
assert.Equal(t, got, tt.want, tt.name)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -175,7 +175,7 @@ func TestConvertToRpcLibraries(t *testing.T) {
|
|||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
got := ConvertToRpcLibraries(tt.args.libs)
|
got := ConvertToRPCLibraries(tt.args.libs)
|
||||||
assert.Equal(t, got, tt.want, tt.name)
|
assert.Equal(t, got, tt.want, tt.name)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -224,7 +224,7 @@ func TestConvertFromRpcVulns(t *testing.T) {
|
|||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
got := ConvertFromRpcVulns(tt.args.rpcVulns)
|
got := ConvertFromRPCVulns(tt.args.rpcVulns)
|
||||||
assert.Equal(t, got, tt.want, tt.name)
|
assert.Equal(t, got, tt.want, tt.name)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -337,7 +337,7 @@ func TestConvertToRpcVulns(t *testing.T) {
|
|||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
got := ConvertToRpcVulns(tt.args.vulns)
|
got := ConvertToRPCVulns(tt.args.vulns)
|
||||||
assert.Equal(t, got, tt.want, tt.name)
|
assert.Equal(t, got, tt.want, tt.name)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,15 +3,17 @@ package rpc
|
|||||||
import (
|
import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/aquasecurity/trivy/pkg/log"
|
|
||||||
"github.com/cenkalti/backoff"
|
"github.com/cenkalti/backoff"
|
||||||
"github.com/twitchtv/twirp"
|
"github.com/twitchtv/twirp"
|
||||||
|
|
||||||
|
"github.com/aquasecurity/trivy/pkg/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
maxRetries = 10
|
maxRetries = 10
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Retry executes the function again using backoff until maxRetries or success
|
||||||
func Retry(f func() error) error {
|
func Retry(f func() error) error {
|
||||||
operation := func() error {
|
operation := func() error {
|
||||||
err := f()
|
err := f()
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import (
|
|||||||
proto "github.com/aquasecurity/trivy/rpc/detector"
|
proto "github.com/aquasecurity/trivy/rpc/detector"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// SuperSet binds the dependencies for library RPC server
|
||||||
var SuperSet = wire.NewSet(
|
var SuperSet = wire.NewSet(
|
||||||
detector.SuperSet,
|
detector.SuperSet,
|
||||||
vulnerability.SuperSet,
|
vulnerability.SuperSet,
|
||||||
@@ -26,13 +27,14 @@ type Server struct {
|
|||||||
vulnClient vulnerability.Operation
|
vulnClient vulnerability.Operation
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewServer is the facotry method for Server
|
||||||
func NewServer(detector detector.Operation, vulnClient vulnerability.Operation) *Server {
|
func NewServer(detector detector.Operation, vulnClient vulnerability.Operation) *Server {
|
||||||
return &Server{detector: detector, vulnClient: vulnClient}
|
return &Server{detector: detector, vulnClient: vulnClient}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Detect is for backward compatibility
|
// Detect is for backward compatibility
|
||||||
func (s *Server) Detect(_ context.Context, req *proto.LibDetectRequest) (res *proto.DetectResponse, err error) {
|
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 {
|
if err != nil {
|
||||||
err = xerrors.Errorf("failed to detect library vulnerabilities: %w", err)
|
err = xerrors.Errorf("failed to detect library vulnerabilities: %w", err)
|
||||||
log.Logger.Error(err)
|
log.Logger.Error(err)
|
||||||
@@ -41,5 +43,5 @@ func (s *Server) Detect(_ context.Context, req *proto.LibDetectRequest) (res *pr
|
|||||||
|
|
||||||
s.vulnClient.FillInfo(vulns, "")
|
s.vulnClient.FillInfo(vulns, "")
|
||||||
|
|
||||||
return &proto.DetectResponse{Vulnerabilities: rpc.ConvertToRpcVulns(vulns)}, nil
|
return &proto.DetectResponse{Vulnerabilities: rpc.ConvertToRPCVulns(vulns)}, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,11 +24,13 @@ import (
|
|||||||
rpcScanner "github.com/aquasecurity/trivy/rpc/scanner"
|
rpcScanner "github.com/aquasecurity/trivy/rpc/scanner"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// DBWorkerSuperSet binds the dependencies for Trivy DB worker
|
||||||
var DBWorkerSuperSet = wire.NewSet(
|
var DBWorkerSuperSet = wire.NewSet(
|
||||||
dbFile.SuperSet,
|
dbFile.SuperSet,
|
||||||
newDBWorker,
|
newDBWorker,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// ListenAndServe starts Trivy server
|
||||||
func ListenAndServe(c config.Config, fsCache cache.FSCache) error {
|
func ListenAndServe(c config.Config, fsCache cache.FSCache) error {
|
||||||
requestWg := &sync.WaitGroup{}
|
requestWg := &sync.WaitGroup{}
|
||||||
dbUpdateWg := &sync.WaitGroup{}
|
dbUpdateWg := &sync.WaitGroup{}
|
||||||
@@ -132,7 +134,7 @@ func (w dbWorker) hotUpdate(ctx context.Context, cacheDir string, dbUpdateWg, re
|
|||||||
}
|
}
|
||||||
defer os.RemoveAll(tmpDir)
|
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)
|
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
Reference in New Issue
Block a user