diff --git a/docs/advanced/air-gap.md b/docs/advanced/air-gap.md index 0de376c3ef..661bfe06b7 100644 --- a/docs/advanced/air-gap.md +++ b/docs/advanced/air-gap.md @@ -1,24 +1,24 @@ # Air-Gapped Environment -Trivy can be used in air-gapped environments. - +Trivy can be used in air-gapped environments. Note that an allowlist is [here][allowlist]. ## Air-Gapped Environment for vulnerabilities ### Download the vulnerability database At first, you need to download the vulnerability database for use in air-gapped environments. -Go to [trivy-db][trivy-db] and download `trivy-offline.db.tgz` in the latest release. -If you download `trivy-light-offline.db.tgz`, you have to run Trivy with `--light` option. +Please follow [oras installation instruction][oras]. + +Download `db.tar.gz`: ``` -$ wget https://github.com/aquasecurity/trivy-db/releases/latest/download/trivy-offline.db.tgz +$ oras pull ghcr.io/aquasecurity/trivy-db:2 -a ``` ### Transfer the DB file into the air-gapped environment The way of transfer depends on the environment. ``` -$ rsync -av -e ssh /path/to/trivy-offline.db.tgz [user]@[host]:dst +$ rsync -av -e ssh /path/to/db.tar.gz [user]@[host]:dst ``` ### Put the DB file in Trivy's cache directory @@ -35,17 +35,10 @@ Put the DB file in the cache directory + `/db`. ``` $ mkdir -p /home/myuser/.cache/trivy/db $ cd /home/myuser/.cache/trivy/db -$ mv /path/to/trivy-offline.db.tgz . -``` - -Then, decompress it. -`trivy-offline.db.tgz` file includes two files, `trivy.db` and `metadata.json`. - -``` -$ tar xvf trivy-offline.db.tgz +$ tar xvf /path/to/db.tar.gz -C /home/myuser/.cache/trivy/db x trivy.db x metadata.json -$ rm trivy-offline.db.tgz +$ rm /path/to/db.tar.gz ``` In an air-gapped environment it is your responsibility to update the Trivy database on a regular basis, so that the scanner can detect recently-identified vulnerabilities. @@ -62,7 +55,8 @@ $ trivy image --skip-update --offline-scan alpine:3.12 ### Download misconfiguration policies At first, you need to download misconfiguration policies for use in air-gapped environments. -Please follow [oras installation instruction][oras]. \ +Please follow [oras installation instruction][oras]. + Download `bundle.tar.gz`: ``` @@ -115,5 +109,5 @@ In an air-gapped environment, specify `--skip-policy-update` so that Trivy doesn $ trivy conf --skip-policy-update /path/to/conf ``` -[trivy-db]: https://github.com/aquasecurity/trivy-db/releases +[allowlist]: ../getting-started/troubleshooting.md [oras]: https://oras.land/cli/ diff --git a/docs/advanced/integrations/index.md b/docs/advanced/integrations/index.md index 8c93f33685..64c6b993fc 100644 --- a/docs/advanced/integrations/index.md +++ b/docs/advanced/integrations/index.md @@ -1,4 +1,2 @@ # Integrations Scan your image automatically as part of your CI workflow, failing the workflow if a vulnerability is found. When you don't want to fail the test, specify `--exit-code 0`. - -Since in automated scenarios such as CI/CD you are only interested in the end result, and not the full report, use the `--light` flag to optimize for this scenario and get fast results. diff --git a/docs/getting-started/cli/image.md b/docs/getting-started/cli/image.md index 24a84b300f..1e98e65d19 100644 --- a/docs/getting-started/cli/image.md +++ b/docs/getting-started/cli/image.md @@ -24,7 +24,6 @@ OPTIONS: --vuln-type value comma-separated list of vulnerability types (os,library) (default: "os,library") [$TRIVY_VULN_TYPE] --ignorefile value specify .trivyignore file (default: ".trivyignore") [$TRIVY_IGNOREFILE] --timeout value timeout (default: 5m0s) [$TRIVY_TIMEOUT] - --light light mode: it's faster, but vulnerability descriptions and references are not displayed (default: false) [$TRIVY_LIGHT] --ignore-policy value specify the Rego file to evaluate each vulnerability [$TRIVY_IGNORE_POLICY] --list-all-pkgs enabling the option will output all packages regardless of vulnerability (default: false) [$TRIVY_LIST_ALL_PKGS] --offline-scan do not issue API requests to identify dependencies (default: false) [$TRIVY_OFFLINE_SCAN] diff --git a/docs/getting-started/troubleshooting.md b/docs/getting-started/troubleshooting.md index 3f1e0b8f9c..e28331db9b 100644 --- a/docs/getting-started/troubleshooting.md +++ b/docs/getting-started/troubleshooting.md @@ -69,11 +69,17 @@ Reference : [boltdb: Opening a database][boltdb]. !!! error FATAL failed to download vulnerability DB -If trivy is running behind corporate firewall try to whitelist urls below: +If trivy is running behind corporate firewall, you have to add the following urls to your allowlist. -- api.github.com -- github.com -- github-releases.githubusercontent.com +- ghcr.io +- pkg-containers.githubusercontent.com + +### Old DB schema + +!!! error + --skip-update cannot be specified with the old DB schema. + +Trivy v0.23.0 or later requires Trivy DB v2. Please update your local database or follow [the instruction of air-gapped environment][air-gapped]. ## Homebrew ### Scope error @@ -123,3 +129,5 @@ Try again with `--reset` option: ``` $ trivy image --reset ``` + +[air-gapped]: ../advanced/air-gap.md \ No newline at end of file diff --git a/docs/vulnerability/examples/db.md b/docs/vulnerability/examples/db.md index 188495aced..ec88099bb0 100644 --- a/docs/vulnerability/examples/db.md +++ b/docs/vulnerability/examples/db.md @@ -36,39 +36,3 @@ This is useful to initialize workers in Continuous Integration systems. ``` $ trivy image --download-db-only ``` - -## Lightweight DB -The lightweight DB doesn't contain vulnerability detail such as descriptions and references. Because of that, the size of the DB is smaller and the download is faster. - -This option is useful when you don't need vulnerability details and is suitable for CI/CD. -To find the additional information, you can search vulnerability details on the NVD website. -https://nvd.nist.gov/vuln/search - -``` -$ trivy image --light alpine:3.10 -``` - -`--light` option doesn't display titles like the following example. - -
-Result - -``` -2019-11-14T10:21:01.553+0200 INFO Reopening vulnerability DB -2019-11-14T10:21:02.574+0200 INFO Detecting Alpine vulnerabilities... - -alpine:3.10 (alpine 3.10.2) -=========================== -Total: 3 (UNKNOWN: 0, LOW: 1, MEDIUM: 2, HIGH: 0, CRITICAL: 0) - -+---------+------------------+----------+-------------------+---------------+ -| LIBRARY | VULNERABILITY ID | SEVERITY | INSTALLED VERSION | FIXED VERSION | -+---------+------------------+----------+-------------------+---------------+ -| openssl | CVE-2019-1549 | MEDIUM | 1.1.1c-r0 | 1.1.1d-r0 | -+ +------------------+ + + + -| | CVE-2019-1563 | | | | -+ +------------------+----------+ + + -| | CVE-2019-1547 | LOW | | | -+---------+------------------+----------+-------------------+---------------+ -``` -
diff --git a/go.mod b/go.mod index 11f5042a89..a448730832 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,7 @@ require ( github.com/aquasecurity/go-npm-version v0.0.0-20201110091526-0b796d180798 github.com/aquasecurity/go-pep440-version v0.0.0-20210121094942-22b2f8951d46 github.com/aquasecurity/go-version v0.0.0-20210121072130-637058cfe492 - github.com/aquasecurity/trivy-db v0.0.0-20210916043317-726b7b72a47b + github.com/aquasecurity/trivy-db v0.0.0-20220104200459-525690bf08ef github.com/caarlos0/env/v6 v6.0.0 github.com/cenkalti/backoff v2.2.1+incompatible github.com/cheggaaa/pb/v3 v3.0.3 @@ -24,7 +24,6 @@ require ( github.com/goccy/go-yaml v1.8.2 // indirect github.com/golang/protobuf v1.5.2 github.com/google/go-containerregistry v0.7.1-0.20211214010025-a65b7844a475 - github.com/google/go-github/v33 v33.0.0 github.com/google/wire v0.4.0 github.com/hashicorp/go-getter v1.5.2 github.com/hashicorp/go-hclog v0.15.0 // indirect @@ -43,7 +42,6 @@ require ( github.com/twitchtv/twirp v8.1.0+incompatible github.com/urfave/cli/v2 v2.3.0 go.uber.org/zap v1.19.1 - golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 google.golang.org/protobuf v1.27.1 gopkg.in/go-playground/validator.v9 v9.31.0 // indirect diff --git a/go.sum b/go.sum index 4d2ff58883..91310febf5 100644 --- a/go.sum +++ b/go.sum @@ -30,6 +30,7 @@ cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAV cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= +cloud.google.com/go v0.92.2/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= cloud.google.com/go v0.97.0 h1:3DXvAyifywvq64LfkKaMOmkWPS1CikIQdMe2lY9vxU8= @@ -42,7 +43,9 @@ cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4g 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/errorreporting v0.1.0/go.mod h1:cZSiBMvrnl0X13pD9DwKf9sQ8Eqy3EzHqkyKBZxiIrM= cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= +cloud.google.com/go/firestore v1.6.1/go.mod h1:asNXNOzBdyVQmEU+ggO8UPodTkEVFW5Qx+rwHnAz+EY= 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= @@ -60,6 +63,7 @@ contrib.go.opencensus.io/exporter/stackdriver v0.12.1/go.mod h1:iwB6wGarfphGGe/e contrib.go.opencensus.io/integrations/ocsql v0.1.4/go.mod h1:8DsSdjz3F+APR+0z0WkU1aRorQCFfRxvqjUUPMbF3fE= contrib.go.opencensus.io/resource v0.1.1/go.mod h1:F361eGI91LCmW1I/Saf+rX0+OFcigGlFvXwEGEnkRLA= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20201218220906-28db891af037/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= git.apache.org/thrift.git v0.12.0/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= github.com/AkihiroSuda/containerd-fuse-overlayfs v1.0.0/go.mod h1:0mMDvQFeLbbn1Wy8P2j3hwFhqBq+FKn8OZPno8WLmp8= @@ -122,6 +126,7 @@ github.com/GoogleCloudPlatform/cloudsql-proxy v0.0.0-20191009163259-e802c2cb94ae github.com/GoogleCloudPlatform/docker-credential-gcr v1.5.0 h1:wykTgKwhVr2t2qs+xI020s6W5dt614QqCHV+7W9dg64= github.com/GoogleCloudPlatform/docker-credential-gcr v1.5.0/go.mod h1:BB1eHdMLYEFuFdBlRMb0N7YGVdM5s6Pt0njxgvfbGGs= github.com/GoogleCloudPlatform/k8s-cloud-provider v0.0.0-20190822182118-27a4ced34534/go.mod h1:iroGtC8B3tQiqtds1l+mgk/BBOrxbqjH+eUfFQYRc14= +github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww= @@ -174,8 +179,10 @@ github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMx github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= github.com/VividCortex/ewma v1.1.1 h1:MnEK4VOv6n0RSY4vtRe3h11qjxL3+t0B8yOL8iMXdcM= github.com/VividCortex/ewma v1.1.1/go.mod h1:2Tkkvm3sRDVXaiyucHiACn4cqf7DpdyLvmxzcbUokwA= +github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= github.com/acomagu/bufpipe v1.0.3 h1:fxAGrHZTgQ9w5QqVItgzwj235/uYZYgbXitB+dLupOk= github.com/acomagu/bufpipe v1.0.3/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4= +github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= github.com/agext/levenshtein v1.2.1/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= github.com/agext/levenshtein v1.2.2/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= github.com/agext/levenshtein v1.2.3 h1:YB2fHEn0UJagG8T1rrWknE3ZQzWM06O8AMAatNn7lmo= @@ -195,6 +202,7 @@ github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= +github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/apex/log v1.1.4/go.mod h1:AlpoD9aScyQfJDVHmLMEcx4oU6LqzkWp4Mg9GdAcEvQ= github.com/apex/log v1.3.0/go.mod h1:jd8Vpsr46WAe3EZSQ/IUMs2qQD/GOycT5rPWCO1yGcs= github.com/apex/logs v0.0.4/go.mod h1:XzxuLZ5myVHDy9SAmYpamKKRNApGj54PfYLcFrXqDwo= @@ -231,17 +239,17 @@ github.com/aquasecurity/testdocker v0.0.0-20210911155206-e1e85f5a1516 h1:moQmzbp github.com/aquasecurity/testdocker v0.0.0-20210911155206-e1e85f5a1516/go.mod h1:gTd97VdQ0rg8Mkiic3rPgNOQdprZ7feTAhiD5mGQjgM= github.com/aquasecurity/tfsec v0.63.1 h1:KH63HTcUoab7d3PKtqFO6T8K5AY7bzLw7Kiu+EY9U64= github.com/aquasecurity/tfsec v0.63.1/go.mod h1:g5ZWmsfqW1FsCaPb9ux8Pzjcyss/WUB2XuRd5slqvnc= -github.com/aquasecurity/trivy-db v0.0.0-20210916043317-726b7b72a47b h1:RaS93vlHzgreZk3CYqcNgoqukwbsBEYhAiE6qmhLwB0= -github.com/aquasecurity/trivy-db v0.0.0-20210916043317-726b7b72a47b/go.mod h1:5h8GV7Qxp/SMJ4awWHs0KRxwVkKzcwOnRkORWOnCXRU= -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/aquasecurity/trivy-db v0.0.0-20220104200459-525690bf08ef h1:E8ihL2Rh5aceXzexoCgKQVFzWQUQ56TwtITEOu4IuNE= +github.com/aquasecurity/trivy-db v0.0.0-20220104200459-525690bf08ef/go.mod h1:nT/y6Nbo7KDfRhezh3uE8nLNV5R13mGw34j6E8htL+o= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= +github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A= github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= +github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= github.com/aws/aws-sdk-go v1.15.11/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0= github.com/aws/aws-sdk-go v1.15.27/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0= github.com/aws/aws-sdk-go v1.15.78/go.mod h1:E3/ieXAlvM0XWO57iftYVDLLvQ824smPP3ATZkfNZeM= @@ -251,10 +259,12 @@ github.com/aws/aws-sdk-go v1.19.18/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpi github.com/aws/aws-sdk-go v1.19.45/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.20.6/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.25.11/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.27.1/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.31.6/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= github.com/aws/aws-sdk-go v1.42.0 h1:BMZws0t8NAhHFsfnT3B40IwD13jVDG5KerlRksctVIw= github.com/aws/aws-sdk-go v1.42.0/go.mod h1:585smgzpB/KqRA+K3y/NL/oYRqQvpNJYvLm+LY1U59Q= +github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I= github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= @@ -294,6 +304,7 @@ github.com/caarlos0/ctrlc v1.0.0/go.mod h1:CdXpj4rmq0q/1Eb44M9zi2nKB0QraNKuRGYGr 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/campoy/unique v0.0.0-20180121183637-88950e537e7e/go.mod h1:9IOqJGCPMSc6E5ydlp5NIonxObaeu/Iub/X03EKPVYo= +github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= github.com/cavaliercoder/go-cpio v0.0.0-20180626203310-925f9528c45e/go.mod h1:oDpT4efm8tSYHXV5tHSdRvBet/b/QzxZ+XyyPehvm3A= github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= @@ -319,6 +330,7 @@ github.com/cilium/ebpf v0.0.0-20200702112145-1c8d4c9ef775/go.mod h1:7cR51M8ViRLI github.com/cilium/ebpf v0.2.0/go.mod h1:To2CFviqOWL/M0gIMsvSMlqe7em/l1ALkX1PyjrX2Qs= github.com/cilium/ebpf v0.4.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= github.com/cilium/ebpf v0.6.2/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= +github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= 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-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= @@ -330,6 +342,7 @@ github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWH github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= github.com/codahale/hdrhistogram v0.0.0-20160425231609-f8ad88b59a58/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= +github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= github.com/containerd/aufs v0.0.0-20200908144142-dab0cbea06f4/go.mod h1:nukgQABAEopAHvB6j7cnP5zJ+/3aVcE7hCYqvIwAHyE= github.com/containerd/aufs v0.0.0-20201003224125-76a6863f2989/go.mod h1:AkGGQs9NM2vtYHaUen+NljV0/baGCAPELGm2q9ZXpWU= github.com/containerd/aufs v0.0.0-20210316121734-20793ff83c97/go.mod h1:kL5kd6KM5TzQjR79jljyi4olc1Vrx6XBlcyj3gNv2PU= @@ -529,14 +542,14 @@ github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25Kn github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= +github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/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/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8= github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg= github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o= +github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g= 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= @@ -558,6 +571,8 @@ github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoD github.com/fortytw2/leaktest v1.2.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= +github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= +github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= @@ -590,6 +605,7 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2 github.com/go-ini/ini v1.25.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= github.com/go-lintpack/lintpack v0.5.2/go.mod h1:NwZuYi2nUHho8XEIZ6SIxihrnPoqBTDqfpXvXAN0sXM= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= @@ -597,6 +613,7 @@ github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= +github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8= github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= @@ -657,6 +674,7 @@ github.com/gofrs/flock v0.0.0-20190320160742-5135e617513b/go.mod h1:F1TvTiK9OcQq github.com/gofrs/flock v0.7.3/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw= github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= github.com/gogo/googleapis v1.2.0/go.mod h1:Njal3psf3qN6dwBtQfUmBZh2ybovJ0tlu3o/AC7HYjU= github.com/gogo/googleapis v1.3.2/go.mod h1:5YRNX2z1oM5gXdAkurHa942MDgEJyk02w4OecKY87+c= github.com/gogo/googleapis v1.4.0/go.mod h1:5YRNX2z1oM5gXdAkurHa942MDgEJyk02w4OecKY87+c= @@ -760,14 +778,11 @@ github.com/google/go-containerregistry v0.1.2/go.mod h1:GPivBPgdAyd2SU+vf6EpsgOt github.com/google/go-containerregistry v0.6.0/go.mod h1:euCCtNbZ6tKqi1E72vwDj2xZcN5ttKpZLfa/wSo5iLw= github.com/google/go-containerregistry v0.7.1-0.20211214010025-a65b7844a475 h1:da8EHPcyjqM4dHLhPqtY48YUj9ATT1ugRyi4g+MdITM= github.com/google/go-containerregistry v0.7.1-0.20211214010025-a65b7844a475/go.mod h1:IwJblnDNiCs8sxubbfPNniYsUqr8m+nt7YbPzecsGuE= -github.com/google/go-github v17.0.0+incompatible h1:N0LgJ1j65A7kfXrZnUDaYCs/Sf4rEjNlfyDHW9dolSY= github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= github.com/google/go-github/v28 v28.1.1/go.mod h1:bsqJWQX05omyWVmc00nEUql9mhQyv38lDZ8kPZcQVoM= -github.com/google/go-github/v33 v33.0.0 h1:qAf9yP0qc54ufQxzwv+u9H0tiVOnPJxo0lI/JXqw3ZM= -github.com/google/go-github/v33 v33.0.0/go.mod h1:GMdDnVZY/2TsWgp/lkYnpSAh6TrzhANBBwm6k6TTEXg= github.com/google/go-github/v38 v38.1.0/go.mod h1:cStvrz/7nFr0FoENgG6GLbp53WaelXucT+BBz/3VKx4= -github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= +github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= github.com/google/go-replayers/grpcreplay v0.1.0/go.mod h1:8Ig2Idjpr6gifRd6pNVggX6TC1Zw6Jx74AKp7QNH2QE= github.com/google/go-replayers/httpreplay v0.1.0/go.mod h1:YKZViNhiGgqdBlUbI2MwGpq4pXxNmhJLPHQ7cv2b5no= github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= @@ -797,6 +812,7 @@ github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/rpmpack v0.0.0-20191226140753-aa36bfddb3a0/go.mod h1:RaTPr0KUf2K7fnZYLNDrr8rxAamWs3iNywJLtQ2AzBg= +github.com/google/safehtml v0.0.2/go.mod h1:L4KWwDsUJdECRAEpZoBn3O64bQaywRscowZjJAzjHnU= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= 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= @@ -813,8 +829,9 @@ github.com/googleapis/gax-go v2.0.2+incompatible h1:silFMLAnr330+NRuag/VjIGF7TLp github.com/googleapis/gax-go v2.0.2+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= 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/gax-go/v2 v2.1.0 h1:6DWmvNpomjL1+3liNSZbVns3zsYzzCjm6pRBO1tLeso= github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= +github.com/googleapis/gax-go/v2 v2.1.1 h1:dp3bWCh+PPO1zjRRiCSczJav13sBvG4UhNyVTa1KqdU= +github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= 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.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= @@ -855,7 +872,9 @@ github.com/hanwen/go-fuse v1.0.0/go.mod h1:unqXarDXqzAk0rt98O2tVndEPIpUgLD9+rwFi github.com/hanwen/go-fuse/v2 v2.0.3/go.mod h1:0EQM6aH2ctVpvZ6a+onrQ/vaykxh2GH7hy3e13vzTUY= github.com/hanwen/go-fuse/v2 v2.1.0/go.mod h1:oRyA5eK+pvJyv5otpO/DgccS8y/RvYMaO00GgRLGryc= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= +github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= +github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= @@ -910,6 +929,7 @@ github.com/hashicorp/uuid v0.0.0-20160311170451-ebb0a03e909c/go.mod h1:fHzc09Uny github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huandu/xstrings v1.3.2 h1:L18LIDzqlW6xN2rEkpdV8+oL/IXWJ1APd+vsdYy4Wdw= github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= +github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= @@ -921,11 +941,13 @@ github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/inconshreveable/go-update v0.0.0-20160112193335-8152e7eb6ccf/go.mod h1:hyb9oH7vZsitZCiBt0ZvifOrB+qc8PS5IiilCIb87rg= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= github.com/ishidawataru/sctp v0.0.0-20191218070446-00ab2ac2db07/go.mod h1:co9pwDoBCm1kGxawmb4sPq0cSIOOWNPT4KnHotMP1Zg= github.com/ishidawataru/sctp v0.0.0-20210226210310-f2269e66cdee/go.mod h1:co9pwDoBCm1kGxawmb4sPq0cSIOOWNPT4KnHotMP1Zg= github.com/j-keck/arping v0.0.0-20160618110441-2cf9dc699c56/go.mod h1:ymszkNOg6tORTn+6F6j+Jc8TOr5osrynvN6ivFWZ2GA= github.com/jaguilar/vt100 v0.0.0-20150826170717-2703a27b14ea/go.mod h1:QMdK4dGB3YhEW2BmA1wgGpPYI3HZy/5gD705PXKUVSg= github.com/jarcoal/httpmock v1.0.5/go.mod h1:ATjnClrvW/3tijVmpL/va5Z3aAyGvqU3gCT8nX0Txik= +github.com/jba/templatecheck v0.6.0/go.mod h1:/1k7EajoSErFI9GLHAsiIJEaNLt3ALKNw2TV7z2SYv4= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU= @@ -1017,8 +1039,11 @@ github.com/liamg/tml v0.4.0/go.mod h1:0h4EAV/zBOsqI91EWONedjRpO8O0itjGJVd+wG5eC+ github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= +github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= github.com/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= github.com/lucasb-eyer/go-colorful v1.0.3/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= +github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= @@ -1052,7 +1077,6 @@ github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcME 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/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= -github.com/mattn/go-jsonpointer v0.0.0-20180225143300-37667080efed/go.mod h1:SDJ4hurDYyQ9/7nc+eCYtXqdufgK4Cq9TJlwPklqEYA= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.6/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= @@ -1133,12 +1157,21 @@ github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRW github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= github.com/nakabonne/nestif v0.3.0/go.mod h1:dI314BppzXjJ4HsCnbo7XzrJHPszZsjnk5wEBSYHI2c= +github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg= +github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU= +github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k= +github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w= +github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= +github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= +github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= github.com/nbutton23/zxcvbn-go v0.0.0-20180912185939-ae427f1e4c1d/go.mod h1:o96djdrsSGy3AWPyBgZMAGfxZNfgntdJG+11KU4QvbU= github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= +github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs= +github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= @@ -1200,17 +1233,23 @@ github.com/opencontainers/runtime-tools v0.0.0-20181011054405-1d69bd0f9c39/go.mo github.com/opencontainers/selinux v1.6.0/go.mod h1:VVGKuOLlE7v4PJyT6h7mNWvq1rzqiriPsEqVhc+svHE= github.com/opencontainers/selinux v1.8.0/go.mod h1:RScLhm78qiWa2gbVCcGkC7tCGdgk3ogry1nUQF8Evvo= github.com/opencontainers/selinux v1.8.2/go.mod h1:MUIHuUEvKB1wtJjQdOyYRgOnLD2xAPP8dBsCoU0KuF8= +github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis= github.com/opentracing-contrib/go-stdlib v1.0.0/go.mod h1:qtI1ogk+2JhVPIXVc6q+NHziSmy2W5GbdQZFUHADCBU= +github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74= +github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= +github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxSfWAKL3wpBW7V8scJMt8N8gnaMCS9E/cA= github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8= github.com/openzipkin/zipkin-go v0.1.3/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8= github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= +github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= +github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= github.com/owenrumney/go-sarif v1.0.10/go.mod h1:sgJM0ZaZ28jT8t8Iq3/mUCFBW9cX09EobIBXYOhiYBc= github.com/owenrumney/go-sarif v1.0.12/go.mod h1:Jk5smXU9QuCqTdh4N3PehnG+azzrf0XcQ267ZwAG8Ho= github.com/owenrumney/squealer v0.2.28 h1:LYsqUHal+5QlANjbZ+h44SN5kIZSfHCWKUzBAS1KwB0= github.com/owenrumney/squealer v0.2.28/go.mod h1:wwVPzhjiUBILIdDtnzGSEcapXczIj/tONP+ZJ49IhPY= -github.com/parnurzeal/gorequest v0.2.16/go.mod h1:3Kh2QUMJoqw3icWAecsyzkpY7UzRfDhbRdTjtNwNiUE= +github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= @@ -1218,15 +1257,19 @@ github.com/pelletier/go-toml v1.8.0/go.mod h1:D6yutnOGMveHEPV7VQOuvI/gXY61bv+9bA github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc= github.com/pelletier/go-toml v1.9.1/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/peterh/liner v0.0.0-20170211195444-bf27d3ba8e1d/go.mod h1:xIteQHvHuaLYG9IFj6mSxM0fCKrs34IrEQUhOYuGPHc= github.com/phayes/checkstyle v0.0.0-20170904204023-bfd46e6a821d/go.mod h1:3OzsM7FXDQlpCiw2j81fOmAwQLnZnLGXVKUzeKQXIAw= +github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= github.com/pkg/profile v1.5.0/go.mod h1:qBsxPvzyUincmltOk6iyRVxHYg4adc0OFOv72ZdLa18= github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= github.com/pkg/term v0.0.0-20190109203006-aa71e9d9e942/go.mod h1:eCbImbZ95eXtAUIbLAuAVnBnwf83mjf6QIVH8SHYwqQ= @@ -1242,6 +1285,7 @@ github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= +github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= github.com/prometheus/client_model v0.0.0-20171117100541-99fa1f4be8e5/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= @@ -1249,6 +1293,7 @@ github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1: github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/common v0.0.0-20180110214958-89604d197083/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= @@ -1257,6 +1302,7 @@ github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y8 github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= +github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= github.com/prometheus/common v0.29.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= @@ -1286,10 +1332,11 @@ github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJ github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v1.1.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= -github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.5.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o= github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= +github.com/rs/zerolog v1.21.0/go.mod h1:ZPhntP/xmq1nnND05hhpAh2QMhSsA4UN3MGZ6O2J3hM= github.com/rubiojr/go-vhd v0.0.0-20160810183302-0bfd3b39853c/go.mod h1:DM5xW0nvfNNm2uytzsvhI3OnX8uzaRAg8UX/CnDqbto= github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= @@ -1300,6 +1347,7 @@ github.com/ryancurrah/gomodguard v1.0.4/go.mod h1:9T/Cfuxs5StfsocWr4WzDL36HqnX0f github.com/ryancurrah/gomodguard v1.1.0/go.mod h1:4O8tr7hBODaGE6VIhfJDHcwzh5GUccKSJBU0UMXJFVM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/safchain/ethtool v0.0.0-20190326074333-42ed695e3de8/go.mod h1:Z0q5wiBQGYcxhMZ6gUqHn6pYNLypFAvaL3UvgZLR0U4= +github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= github.com/saracen/walker v0.0.0-20191201085201-324a081bae7e h1:NO86zOn5ScSKW8wRbMaSIcjDZUFpWdCQQnexRqZ9h9A= github.com/saracen/walker v0.0.0-20191201085201-324a081bae7e/go.mod h1:G0Z6yVPru183i2MuRJx1DcR4dgIZtLcTdaaE/pC1BJU= github.com/sassoftware/go-rpmutils v0.0.0-20190420191620-a8f1baeba37b/go.mod h1:am+Fp8Bt506lA3Rk3QCmSqmYmLMnPDhdDUcosQCAx+I= @@ -1319,7 +1367,6 @@ github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4/go.mod h1:qsXQc7+bwAM3Q github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= -github.com/simplereach/timeutils v1.2.0/go.mod h1:VVbQDfN/FHRZa1LSqcwo4kNZ62OOyqLLGQKYB3pB0Q8= github.com/sirupsen/logrus v1.0.4-0.20170822132746-89742aefa4b2/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= @@ -1336,6 +1383,7 @@ github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:s github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/smartystreets/gunit v1.0.0/go.mod h1:qwPWnhz6pn0NnRBP++URONOVyNkPyr4SauJk4cUOwJs= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= github.com/sosedoff/gitkit v0.3.0 h1:TfINVRNUM+GcFa+LGhZ3RcWN86Im1M6i8qs0IsgMy90= github.com/sosedoff/gitkit v0.3.0/go.mod h1:V3EpGZ0nvCBhXerPsbDeqtyReNb48cwP9KtkUYTKT5I= github.com/sourcegraph/go-diff v0.5.1/go.mod h1:j2dHj3m8aZgQO8lMTcTnBcXkRRRqi34cd2MNlA9u1mE= @@ -1368,6 +1416,9 @@ github.com/spf13/viper v1.6.1/go.mod h1:t3iDnF5Jlj76alVNuyFBk5oUMCvsrkbvZK0WQdfD github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns= github.com/stefanberger/go-pkcs11uri v0.0.0-20201008174630-78d3cae3a980/go.mod h1:AO3tvPzVZ/ayst6UlUKUv6rcPQInYe3IknH3jYhAKu8= +github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= +github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= +github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= github.com/stretchr/objx v0.0.0-20180129172003-8a3f7159479f/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= @@ -1474,6 +1525,7 @@ github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/gopher-lua v0.0.0-20200816102855-ee81675732da h1:NimzV1aGyq29m5ukMK0AMWEhFaL/lrEOaephfuoiARg= github.com/yuin/gopher-lua v0.0.0-20200816102855-ee81675732da/go.mod h1:E1AXubJBdNmFERAOucpDIxNzeGfLzg0mYh+UfMWdChA= github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs= @@ -1505,6 +1557,8 @@ go.opencensus.io v0.15.0/go.mod h1:UffZAU+4sDEINUGP/B7UfBBkq4fqLu9zXAX7ke6CHW0= go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA= go.opencensus.io v0.19.1/go.mod h1:gug0GbSHa8Pafr0d2urOSgoXHZ6x/RUlaiT0d9pqb4A= go.opencensus.io v0.19.2/go.mod h1:NO/8qkisMZLZ1FCsKNqtJPwc8/TaclWyY0B6wcYNg9M= +go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= +go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= 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= @@ -1517,20 +1571,26 @@ go.opentelemetry.io/contrib v0.21.0/go.mod h1:EH4yDYeNoaTqn/8yCWQmfNB78VHfGX2Jt2 go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.21.0/go.mod h1:Vm5u/mtkj1OMhtao0v+BGo2LUoLCgHYXvRmj0jWITlE= go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.21.0/go.mod h1:a9cocRplhIBkUAJmak+BPDx+LVL7cTmqUPB0uBcTA4k= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.21.0/go.mod h1:JQAtechjxLEL81EjmbRwxBq/XEzGaHcsPuDHAx54hg4= +go.opentelemetry.io/otel v0.20.0/go.mod h1:Y3ugLH2oa81t5QO+Lty+zXf8zC9L26ax4Nzoxm/dooo= go.opentelemetry.io/otel v1.0.0-RC1/go.mod h1:x9tRa9HK4hSSq7jf2TKbqFbtt58/TGk0f9XiEYISI1I= go.opentelemetry.io/otel/exporters/jaeger v1.0.0-RC1/go.mod h1:FXJnjGCoTQL6nQ8OpFJ0JI1DrdOvMoVx49ic0Hg4+D4= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.0.0-RC1/go.mod h1:FliQjImlo7emZVjixV8nbDMAa4iAkcWTE9zzSEOiEPw= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.0.0-RC1/go.mod h1:cDwRc2Jrh5Gku1peGK8p9rRuX/Uq2OtVmLicjlw2WYU= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.0.0-RC1/go.mod h1:OYKzEoxgXFvehW7X12WYT4/a2BlASJK9l7RtG4A91fg= go.opentelemetry.io/otel/internal/metric v0.21.0/go.mod h1:iOfAaY2YycsXfYD4kaRSbLx2LKmfpKObWBEv9QK5zFo= +go.opentelemetry.io/otel/metric v0.20.0/go.mod h1:598I5tYlH1vzBjn+BTuhzTCSb/9debfNp6R3s7Pr1eU= go.opentelemetry.io/otel/metric v0.21.0/go.mod h1:JWCt1bjivC4iCrz/aCrM1GSw+ZcvY44KCbaeeRhzHnc= +go.opentelemetry.io/otel/oteltest v0.20.0/go.mod h1:L7bgKf9ZB7qCwT9Up7i9/pn0PWIa9FqQ2IQ8LoxiGnw= go.opentelemetry.io/otel/oteltest v1.0.0-RC1/go.mod h1:+eoIG0gdEOaPNftuy1YScLr1Gb4mL/9lpDkZ0JjMRq4= +go.opentelemetry.io/otel/sdk v0.20.0/go.mod h1:g/IcepuwNsoiX5Byy2nNV0ySUF1em498m7hBWC279Yc= go.opentelemetry.io/otel/sdk v1.0.0-RC1/go.mod h1:kj6yPn7Pgt5ByRuwesbaWcRLA+V7BSDg3Hf8xRvsvf8= +go.opentelemetry.io/otel/trace v0.20.0/go.mod h1:6GjCW8zgDjwGHGa6GkyeB8+/5vjT16gUEi0Nf1iBdgw= go.opentelemetry.io/otel/trace v1.0.0-RC1/go.mod h1:86UHmyHWFEtWjfWPSbu0+d0Pf9Q6e1U+3ViBOc+NXAg= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.opentelemetry.io/proto/otlp v0.9.0/go.mod h1:1vKfU9rv61e9EVGthD1zNvUbiwPcimSsOPU9brfSHJg= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= @@ -1539,11 +1599,13 @@ go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A go.uber.org/goleak v1.1.11-0.20210813005559-691160354723 h1:sHOAIxRGBp443oHZIPB+HsUGaksVCXVQENPxwTfQdH4= go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= go.uber.org/zap v1.19.1 h1:ue41HOKd1vGURxrmeKIgELGb3jPW9DMUDGtsinblHwI= @@ -1577,13 +1639,15 @@ golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20201117144127-c1f2f97bffc9/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= -golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a h1:kr2P4QFmQr29mSLA43kwrOcgcReGTfbE9N577tCTuBc= golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 h1:7I4JAnoQBe7ZtJcBaYHi5UtiO8tQHbUSXxL+pnGRANg= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190312203227-4b39c73a6495/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4= 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= @@ -1591,6 +1655,7 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 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/exp v0.0.0-20211123021643-48cbe7f80d7c/go.mod h1:b9TAUYHmRtqA6klRHApnXMnj+OyLce4yF5cZCUbk2ps= 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-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -1609,17 +1674,20 @@ golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPI golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mobile v0.0.0-20201217150744-e6ae53a27f4f/go.mod h1:skQtrUTUwhdJvXM/2KKJzY8pDgNr9I/FOMqDVRPBUS4= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191209134235-331c550502dd/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.5.1 h1:OJxoQ/rynoF0dcCdI7cLPktw/hR2cueqYfjm43oqK38= golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= +golang.org/x/mod v0.6.0-dev.0.20211013180041-c96bc1413d57 h1:LQmS1nU0twXLA96Kt7U9qtHJEbBk3z6Q0V4UXjZkpr4= +golang.org/x/mod v0.6.0-dev.0.20211013180041-c96bc1413d57/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= 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-20180811021610-c39426892332/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1685,6 +1753,7 @@ golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210825183410-e898025ed96a/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211118161319-6a13c67c3ce4 h1:DZshvxDdVoeKIbudAdFEKi+f70l51luSy/7b76ibTY0= golang.org/x/net v0.0.0-20211118161319-6a13c67c3ce4/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180724155351-3d292e4d0cdc/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -1708,6 +1777,7 @@ golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20211005180243-6b3c2da341f1/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 h1:RerP+noqYHUQ8CMRcPlC2nvTa4dcBIjegkuWdcUDuqg= golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw= @@ -1774,6 +1844,7 @@ golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7w 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-20191210023423-ac6580df4449/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1831,14 +1902,19 @@ golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211117180635-dee7805ff2e1 h1:kwrAHlwJ0DUBZwQ238v+Uod/3eZ8B2K5rYsUHBQvzmI= +golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211117180635-dee7805ff2e1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211213223007-03aa0b5f6827 h1:A0Qkn7Z/n8zC1xd9LTw17AiKlBRK64tw3ejWQiEqca0= +golang.org/x/sys v0.0.0-20211213223007-03aa0b5f6827/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf h1:MZ2shdL+ZM/XzY3ZGOnh4Nlpnxz5GSOhOmtHo3iPU6M= @@ -1913,6 +1989,8 @@ golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtn 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-20200102140908-9497f49d5709/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117012304-6edc0a871e69/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= @@ -1953,6 +2031,9 @@ golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= +golang.org/x/tools v0.1.8-0.20211029000441-d6a9af8af023/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= +golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= +golang.org/x/vuln v0.0.0-20211215213114-5e054cb3e47e/go.mod h1:9qJmykHjqtHdZkMBTPU2esbdS/2fuYYj9Lsb5BLHlPE= 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-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -1967,6 +2048,7 @@ google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+ google.golang.org/api v0.0.0-20181220000619-583d854617af/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/api v0.2.0/go.mod h1:IfRCZScioGtypHNTlz3gFk67J8uePVW7uDTBzXuIkhU= google.golang.org/api v0.3.0/go.mod h1:IuvZyQh8jgscv8qWfQ4ABd8m7hEudgBFM/EdhA3BnXw= +google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.5.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.6.0/go.mod h1:btoxGiFvQNVUZQ8W08zLtrVS08CNpINPEfxXxgJL1Q4= @@ -1999,8 +2081,11 @@ google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNe google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= -google.golang.org/api v0.57.0 h1:4t9zuDlHLcIx0ZEhmXEeFVCRsiOgpgn2QOH9N0MNjPI= +google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI= +google.golang.org/api v0.59.0/go.mod h1:sT2boj7M9YJxZzgeZqXogmhfmRWDtPzT31xkieUbuZU= +google.golang.org/api v0.60.0 h1:eq/zs5WPH4J9undYM9IP1O7dSr7Yh8Y0GtSCpzGzIUk= +google.golang.org/api v0.60.0/go.mod h1:d7rl65NZAkEQ90JFzqBjcRq1TVeG5ZoGV3sSpEnnVb4= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -2076,7 +2161,11 @@ google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEc google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211008145708-270636b82663/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211021150943-2b146023228c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211028162531-8db9c33dc351/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1 h1:b9mVrqYfq3P4bCdaLg1qtBnPzUYgglsIdjZkL/fQVOE= google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= @@ -2084,9 +2173,11 @@ google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmE google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.22.1/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.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA= @@ -2144,6 +2235,7 @@ gopkg.in/cheggaaa/pb.v1 v1.0.28/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qS gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/gcfg.v1 v1.2.0/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= +gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= gopkg.in/go-playground/validator.v9 v9.30.0/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ= @@ -2153,7 +2245,6 @@ gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.56.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -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/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= @@ -2194,6 +2285,7 @@ honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt 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/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.5/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las= k8s.io/api v0.0.0-20180904230853-4e7be11eab3f/go.mod h1:iuAfoD4hCxJ8Onx9kaTIt30j7jUFS00AXQi6QMi99vA= k8s.io/api v0.17.4/go.mod h1:5qxx6vjmwUVG2nHQTKGlLts8Tbok8PzHl4vHtVFuZCA= k8s.io/api v0.19.0/go.mod h1:I1K45XlvTrDjmj5LoM5LuP/KYrhWbjUKT/SoPG0qTjw= @@ -2252,11 +2344,11 @@ 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/strutil v1.0.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs= modernc.org/xc v1.0.0/go.mod h1:mRNCo0bvLjGhHO9WsyuKVU4q0ceiDDDoEeWDJHrNx8I= -moul.io/http2curl v1.0.0/go.mod h1:f6cULg+e4Md/oW1cYmwW4IWQOVl2lGbmCNGOHvzX2kE= mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed/go.mod h1:Xkxe497xwlCKkIaQYRfC7CSLworTXY9RMqwhhCm+8Nc= mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b/go.mod h1:2odslEg/xrtNQqCYg2/jCoyKnw3vv5biOc3JnIcYfL4= mvdan.cc/unparam v0.0.0-20190720180237-d51796306d8f/go.mod h1:4G1h5nDURzA3bwVMZIVpwbkw+04kSxk3rAtzlimaUJw= mvdan.cc/unparam v0.0.0-20200501210554-b37ab49443f7/go.mod h1:HGC5lll35J70Y5v7vCGb9oLhHoScFwkHDJm/05RdSTc= +mvdan.cc/unparam v0.0.0-20211214103731-d0ef000c54e5/go.mod h1:b8RRCBm0eeiWR8cfN88xeq2G5SG3VKGO+5UPWi5FSOY= pack.ag/amqp v0.11.2/go.mod h1:4/cbmt4EJXSKlG6LCfWHoqmN0uFdy5i/+YFz+fTfhV4= 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= @@ -2272,5 +2364,6 @@ sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= +sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU= sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0= sourcegraph.com/sqs/pbtypes v1.0.0/go.mod h1:3AciMUv4qUuRHRHhOG4TZOB+72GdPVz5k+c648qsFS4= diff --git a/integration/integration_test.go b/integration/integration_test.go index aaf1cc3d73..d76a6da287 100644 --- a/integration/integration_test.go +++ b/integration/integration_test.go @@ -17,6 +17,7 @@ import ( "github.com/stretchr/testify/require" "github.com/aquasecurity/trivy-db/pkg/db" + "github.com/aquasecurity/trivy-db/pkg/metadata" "github.com/aquasecurity/trivy/pkg/dbtest" "github.com/aquasecurity/trivy/pkg/report" ) @@ -45,9 +46,8 @@ func initDB(t *testing.T) string { f, err := os.Create(metadataFile) require.NoError(t, err) - err = json.NewEncoder(f).Encode(db.Metadata{ - Version: 1, - Type: 1, + err = json.NewEncoder(f).Encode(metadata.Metadata{ + Version: db.SchemaVersion, NextUpdate: time.Now().Add(24 * time.Hour), UpdatedAt: time.Now(), }) diff --git a/pkg/commands/app.go b/pkg/commands/app.go index ae2cb8a2e3..5d91ef67e1 100644 --- a/pkg/commands/app.go +++ b/pkg/commands/app.go @@ -8,16 +8,14 @@ import ( "strings" "time" - "github.com/spf13/afero" "github.com/urfave/cli/v2" - "github.com/aquasecurity/trivy-db/pkg/db" + "github.com/aquasecurity/trivy-db/pkg/metadata" dbTypes "github.com/aquasecurity/trivy-db/pkg/types" "github.com/aquasecurity/trivy/pkg/commands/artifact" "github.com/aquasecurity/trivy/pkg/commands/client" "github.com/aquasecurity/trivy/pkg/commands/plugin" "github.com/aquasecurity/trivy/pkg/commands/server" - tdb "github.com/aquasecurity/trivy/pkg/db" "github.com/aquasecurity/trivy/pkg/log" "github.com/aquasecurity/trivy/pkg/result" "github.com/aquasecurity/trivy/pkg/types" @@ -26,8 +24,8 @@ import ( // VersionInfo holds the trivy DB version Info type VersionInfo struct { - Version string `json:",omitempty"` - VulnerabilityDB *db.Metadata `json:",omitempty"` + Version string `json:",omitempty"` + VulnerabilityDB *metadata.Metadata `json:",omitempty"` } var ( @@ -183,9 +181,10 @@ var ( EnvVars: []string{"TRIVY_TIMEOUT"}, } + // TODO: remove this flag after a sufficient deprecation period. lightFlag = cli.BoolFlag{ Name: "light", - Usage: "light mode: it's faster, but vulnerability descriptions and references are not displayed", + Usage: "deprecated", EnvVars: []string{"TRIVY_LIGHT"}, } @@ -405,16 +404,16 @@ func setHidden(flags []cli.Flag, hidden bool) []cli.Flag { } func showVersion(cacheDir, outputFormat, version string, outputWriter io.Writer) { - var dbMeta *db.Metadata + var dbMeta *metadata.Metadata - metadata, _ := tdb.NewMetadata(afero.NewOsFs(), cacheDir).Get() // nolint: errcheck - if !metadata.UpdatedAt.IsZero() && !metadata.NextUpdate.IsZero() && metadata.Version != 0 { - dbMeta = &db.Metadata{ - Version: metadata.Version, - Type: metadata.Type, - NextUpdate: metadata.NextUpdate.UTC(), - UpdatedAt: metadata.UpdatedAt.UTC(), - DownloadedAt: metadata.DownloadedAt.UTC(), + mc := metadata.NewClient(cacheDir) + meta, _ := mc.Get() // nolint: errcheck + if !meta.UpdatedAt.IsZero() && !meta.NextUpdate.IsZero() && meta.Version != 0 { + dbMeta = &metadata.Metadata{ + Version: meta.Version, + NextUpdate: meta.NextUpdate.UTC(), + UpdatedAt: meta.UpdatedAt.UTC(), + DownloadedAt: meta.DownloadedAt.UTC(), } } @@ -428,20 +427,12 @@ func showVersion(cacheDir, outputFormat, version string, outputWriter io.Writer) default: output := fmt.Sprintf("Version: %s\n", version) if dbMeta != nil { - var dbType string - switch dbMeta.Type { - case db.TypeFull: - dbType = "Full" - case db.TypeLight: - dbType = "Light" - } output += fmt.Sprintf(`Vulnerability DB: - Type: %s Version: %d UpdatedAt: %s NextUpdate: %s DownloadedAt: %s -`, dbType, dbMeta.Version, dbMeta.UpdatedAt.UTC(), dbMeta.NextUpdate.UTC(), dbMeta.DownloadedAt.UTC()) +`, dbMeta.Version, dbMeta.UpdatedAt.UTC(), dbMeta.NextUpdate.UTC(), dbMeta.DownloadedAt.UTC()) } fmt.Fprintf(outputWriter, output) } @@ -587,6 +578,7 @@ func NewClientCommand() *cli.Command { &securityChecksFlag, &ignoreFileFlag, &timeoutFlag, + &noProgressFlag, &ignorePolicy, stringSliceFlag(skipFiles), stringSliceFlag(skipDirs), diff --git a/pkg/commands/app_test.go b/pkg/commands/app_test.go index 4ace3523c2..e30ecf4af9 100644 --- a/pkg/commands/app_test.go +++ b/pkg/commands/app_test.go @@ -12,7 +12,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/aquasecurity/trivy-db/pkg/db" + "github.com/aquasecurity/trivy-db/pkg/metadata" ) func Test_showVersion(t *testing.T) { @@ -35,7 +35,6 @@ func Test_showVersion(t *testing.T) { }, expectedOutput: `Version: v1.2.3 Vulnerability DB: - Type: Full Version: 42 UpdatedAt: 2020-03-16 23:40:20 +0000 UTC NextUpdate: 2020-03-16 23:57:00 +0000 UTC @@ -49,7 +48,7 @@ Vulnerability DB: outputFormat: "json", version: "1.2.3", }, - expectedOutput: `{"Version":"1.2.3","VulnerabilityDB":{"Version":42,"Type":1,"NextUpdate":"2020-03-16T23:57:00Z","UpdatedAt":"2020-03-16T23:40:20Z","DownloadedAt":"2020-03-16T23:40:20Z"}} + expectedOutput: `{"Version":"1.2.3","VulnerabilityDB":{"Version":42,"NextUpdate":"2020-03-16T23:57:00Z","UpdatedAt":"2020-03-16T23:40:20Z","DownloadedAt":"2020-03-16T23:40:20Z"}} `, createDB: true, }, @@ -90,9 +89,8 @@ Vulnerability DB: require.NoError(t, err) metadataFile := filepath.Join(cacheDir, "db", "metadata.json") - b, err := json.Marshal(db.Metadata{ + b, err := json.Marshal(metadata.Metadata{ Version: 42, - Type: 1, NextUpdate: time.Unix(1584403020, 0), UpdatedAt: time.Unix(1584402020, 0), DownloadedAt: time.Unix(1584402020, 0), diff --git a/pkg/commands/artifact/run.go b/pkg/commands/artifact/run.go index 08aff4a148..d3adbce417 100644 --- a/pkg/commands/artifact/run.go +++ b/pkg/commands/artifact/run.go @@ -81,7 +81,6 @@ func runWithTimeout(ctx context.Context, opt Option, initializeScanner Initializ Output: opt.Output, Severities: opt.Severities, OutputTemplate: opt.Template, - Light: opt.Light, IncludeNonFailures: opt.IncludeNonFailures, Trace: opt.Trace, }); err != nil { @@ -121,7 +120,7 @@ func initFSCache(c Option) (cache.Cache, error) { func initDB(c Option) error { // download the database file noProgress := c.Quiet || c.NoProgress - if err := operation.DownloadDB(c.AppVersion, c.CacheDir, noProgress, c.Light, c.SkipDBUpdate); err != nil { + if err := operation.DownloadDB(c.AppVersion, c.CacheDir, noProgress, c.SkipDBUpdate); err != nil { return err } @@ -185,7 +184,8 @@ func scan(ctx context.Context, opt Option, initializeScanner InitializeScanner, // ScannerOptions is filled only when config scanning is enabled. var configScannerOptions config.ScannerOption if utils.StringInSlice(types.SecurityCheckConfig, opt.SecurityChecks) { - builtinPolicyPaths, err := operation.InitBuiltinPolicies(ctx, opt.SkipPolicyUpdate) + noProgress := opt.Quiet || opt.NoProgress + builtinPolicyPaths, err := operation.InitBuiltinPolicies(ctx, opt.CacheDir, noProgress, opt.SkipPolicyUpdate) if err != nil { return pkgReport.Report{}, xerrors.Errorf("failed to initialize built-in policies: %w", err) } diff --git a/pkg/commands/client/option.go b/pkg/commands/client/option.go index d5f74f8365..ea00233f35 100644 --- a/pkg/commands/client/option.go +++ b/pkg/commands/client/option.go @@ -19,6 +19,9 @@ type Option struct { option.ReportOption option.ConfigOption + // For policy downloading + NoProgress bool + // We don't want to allow disabled analyzers to be passed by users, // but it differs depending on scanning modes. DisabledAnalyzers []analyzer.Type @@ -44,6 +47,7 @@ func NewOption(c *cli.Context) (Option, error) { ImageOption: option.NewImageOption(c), ReportOption: option.NewReportOption(c), ConfigOption: option.NewConfigOption(c), + NoProgress: c.Bool("no-progress"), RemoteAddr: c.String("remote"), token: c.String("token"), tokenHeader: c.String("token-header"), diff --git a/pkg/commands/client/run.go b/pkg/commands/client/run.go index 42b81c8533..dead9296c5 100644 --- a/pkg/commands/client/run.go +++ b/pkg/commands/client/run.go @@ -89,7 +89,6 @@ func runWithTimeout(ctx context.Context, opt Option) error { Output: opt.Output, Severities: opt.Severities, OutputTemplate: opt.Template, - Light: false, IncludeNonFailures: opt.IncludeNonFailures, Trace: opt.Trace, }); err != nil { @@ -143,7 +142,8 @@ func initializeScanner(ctx context.Context, opt Option) (scanner.Scanner, func() // ScannerOptions is filled only when config scanning is enabled. var configScannerOptions config.ScannerOption if utils.StringInSlice(types.SecurityCheckConfig, opt.SecurityChecks) { - builtinPolicyPaths, err := operation.InitBuiltinPolicies(ctx, opt.SkipPolicyUpdate) + noProgress := opt.Quiet || opt.NoProgress + builtinPolicyPaths, err := operation.InitBuiltinPolicies(ctx, opt.CacheDir, noProgress, opt.SkipPolicyUpdate) if err != nil { return scanner.Scanner{}, nil, xerrors.Errorf("failed to initialize default policies: %w", err) } diff --git a/pkg/commands/operation/inject.go b/pkg/commands/operation/inject.go deleted file mode 100644 index fab68182ce..0000000000 --- a/pkg/commands/operation/inject.go +++ /dev/null @@ -1,14 +0,0 @@ -//go:build wireinject -// +build wireinject - -package operation - -import ( - "github.com/aquasecurity/trivy/pkg/db" - "github.com/google/wire" -) - -func initializeDBClient(cacheDir string, quiet bool) db.Client { - wire.Build(db.SuperSet) - return db.Client{} -} diff --git a/pkg/commands/operation/operation.go b/pkg/commands/operation/operation.go index 96e145e3fd..8863bfecf8 100644 --- a/pkg/commands/operation/operation.go +++ b/pkg/commands/operation/operation.go @@ -7,10 +7,10 @@ import ( "github.com/go-redis/redis/v8" "github.com/google/wire" - "github.com/spf13/afero" "golang.org/x/xerrors" "github.com/aquasecurity/fanal/cache" + "github.com/aquasecurity/trivy-db/pkg/metadata" "github.com/aquasecurity/trivy/pkg/db" "github.com/aquasecurity/trivy/pkg/log" "github.com/aquasecurity/trivy/pkg/policy" @@ -77,10 +77,10 @@ func (c Cache) ClearArtifacts() error { } // DownloadDB downloads the DB -func DownloadDB(appVersion, cacheDir string, quiet, light, skipUpdate bool) error { - client := initializeDBClient(cacheDir, quiet) +func DownloadDB(appVersion, cacheDir string, quiet, skipUpdate bool) error { + client := db.NewClient(cacheDir, quiet) ctx := context.Background() - needsUpdate, err := client.NeedsUpdate(appVersion, light, skipUpdate) + needsUpdate, err := client.NeedsUpdate(appVersion, skipUpdate) if err != nil { return xerrors.Errorf("database error: %w", err) } @@ -88,12 +88,9 @@ func DownloadDB(appVersion, cacheDir string, quiet, light, skipUpdate bool) erro if needsUpdate { log.Logger.Info("Need to update DB") log.Logger.Info("Downloading DB...") - if err = client.Download(ctx, cacheDir, light); err != nil { + if err = client.Download(ctx, cacheDir); err != nil { return xerrors.Errorf("failed to download vulnerability DB: %w", err) } - if err = client.UpdateMetadata(cacheDir); err != nil { - return xerrors.Errorf("unable to update database metadata: %w", err) - } } // for debug @@ -104,8 +101,8 @@ func DownloadDB(appVersion, cacheDir string, quiet, light, skipUpdate bool) erro } // InitBuiltinPolicies downloads the built-in policies and loads them -func InitBuiltinPolicies(ctx context.Context, skipUpdate bool) ([]string, error) { - client, err := policy.NewClient() +func InitBuiltinPolicies(ctx context.Context, cacheDir string, quiet, skipUpdate bool) ([]string, error) { + client, err := policy.NewClient(cacheDir, quiet) if err != nil { return nil, xerrors.Errorf("policy client error: %w", err) } @@ -138,12 +135,12 @@ func InitBuiltinPolicies(ctx context.Context, skipUpdate bool) ([]string, error) } func showDBInfo(cacheDir string) error { - m := db.NewMetadata(afero.NewOsFs(), cacheDir) - metadata, err := m.Get() + m := metadata.NewClient(cacheDir) + meta, err := m.Get() if err != nil { return xerrors.Errorf("something wrong with DB: %w", err) } - log.Logger.Debugf("DB Schema: %d, Type: %d, UpdatedAt: %s, NextUpdate: %s, DownloadedAt: %s", - metadata.Version, metadata.Type, metadata.UpdatedAt, metadata.NextUpdate, metadata.DownloadedAt) + log.Logger.Debugf("DB Schema: %d, UpdatedAt: %s, NextUpdate: %s, DownloadedAt: %s", + meta.Version, meta.UpdatedAt, meta.NextUpdate, meta.DownloadedAt) return nil } diff --git a/pkg/commands/operation/wire_gen.go b/pkg/commands/operation/wire_gen.go deleted file mode 100644 index 65210d7b84..0000000000 --- a/pkg/commands/operation/wire_gen.go +++ /dev/null @@ -1,29 +0,0 @@ -// Code generated by Wire. DO NOT EDIT. - -//go:generate wire -//go:build !wireinject -// +build !wireinject - -package operation - -import ( - db2 "github.com/aquasecurity/trivy-db/pkg/db" - "github.com/aquasecurity/trivy/pkg/db" - "github.com/aquasecurity/trivy/pkg/github" - "github.com/aquasecurity/trivy/pkg/indicator" - "github.com/spf13/afero" - "k8s.io/utils/clock" -) - -// Injectors from inject.go: - -func initializeDBClient(cacheDir string, quiet bool) db.Client { - config := db2.Config{} - client := github.NewClient() - progressBar := indicator.NewProgressBar(quiet) - realClock := clock.RealClock{} - fs := afero.NewOsFs() - metadata := db.NewMetadata(fs, cacheDir) - dbClient := db.NewClient(config, client, progressBar, realClock, metadata) - return dbClient -} diff --git a/pkg/commands/option/db.go b/pkg/commands/option/db.go index c4615c1944..8435333a8f 100644 --- a/pkg/commands/option/db.go +++ b/pkg/commands/option/db.go @@ -3,6 +3,8 @@ package option import ( "github.com/urfave/cli/v2" "golang.org/x/xerrors" + + "github.com/aquasecurity/trivy/pkg/log" ) // DBOption holds the options for trivy DB @@ -30,5 +32,8 @@ func (c *DBOption) Init() (err error) { if c.SkipDBUpdate && c.DownloadDBOnly { return xerrors.New("--skip-db-update and --download-db-only options can not be specified both") } + if c.Light { + log.Logger.Warn("'--light' option is deprecated and will be removed") + } return nil } diff --git a/pkg/commands/server/run.go b/pkg/commands/server/run.go index ef172a8162..0b43d8e5aa 100644 --- a/pkg/commands/server/run.go +++ b/pkg/commands/server/run.go @@ -40,7 +40,7 @@ func run(c Config) (err error) { } // download the database file - if err = operation.DownloadDB(c.AppVersion, c.CacheDir, true, false, c.SkipDBUpdate); err != nil { + if err = operation.DownloadDB(c.AppVersion, c.CacheDir, true, c.SkipDBUpdate); err != nil { return err } diff --git a/pkg/db/db.go b/pkg/db/db.go index 2a33870cd8..a21c7ee216 100644 --- a/pkg/db/db.go +++ b/pkg/db/db.go @@ -1,268 +1,181 @@ package db import ( - "compress/gzip" "context" - "encoding/json" - "io" - "os" - "path/filepath" + "fmt" "time" - "github.com/google/wire" - "github.com/spf13/afero" + "github.com/aquasecurity/trivy/pkg/oci" + "golang.org/x/xerrors" "k8s.io/utils/clock" "github.com/aquasecurity/trivy-db/pkg/db" - "github.com/aquasecurity/trivy/pkg/github" - "github.com/aquasecurity/trivy/pkg/indicator" + "github.com/aquasecurity/trivy-db/pkg/metadata" "github.com/aquasecurity/trivy/pkg/log" ) const ( - fullDB = "trivy.db.gz" - lightDB = "trivy-light.db.gz" - - metadataFile = "metadata.json" - - gb = 1024 * 1024 * 1024 -) - -// SuperSet binds the dependencies -var SuperSet = wire.NewSet( - // indicator.ProgressBar - indicator.NewProgressBar, - - // clock.Clock - wire.Struct(new(clock.RealClock)), - wire.Bind(new(clock.Clock), new(clock.RealClock)), - - // db.Config - wire.Struct(new(db.Config)), - wire.Bind(new(dbOperation), new(db.Config)), - - // github.Client - github.NewClient, - wire.Bind(new(github.Operation), new(github.Client)), - - // Metadata - afero.NewOsFs, - NewMetadata, - - // db.Client - NewClient, - wire.Bind(new(Operation), new(Client)), + dbRepository = "ghcr.io/aquasecurity/trivy-db" + dbMediaType = "application/vnd.aquasec.trivy.db.layer.v1.tar+gzip" ) // Operation defines the DB operations type Operation interface { - NeedsUpdate(cliVersion string, light, skip bool) (need bool, err error) - Download(ctx context.Context, cacheDir string, light bool) (err error) - UpdateMetadata(cacheDir string) (err error) + NeedsUpdate(cliVersion string, skip bool) (need bool, err error) + Download(ctx context.Context, dst string) (err error) } -type dbOperation interface { - GetMetadata() (metadata db.Metadata, err error) - StoreMetadata(metadata db.Metadata, dir string) (err error) +type options struct { + artifact *oci.Artifact + clock clock.Clock +} + +// Option is a functional option +type Option func(*options) + +// WithOCIArtifact takes an OCI artifact +func WithOCIArtifact(art *oci.Artifact) Option { + return func(opts *options) { + opts.artifact = art + } +} + +// WithClock takes a clock +func WithClock(clock clock.Clock) Option { + return func(opts *options) { + opts.clock = clock + } } // Client implements DB operations type Client struct { - dbc dbOperation - githubClient github.Operation - pb indicator.ProgressBar - clock clock.Clock - metadata Metadata + *options + + cacheDir string + metadata metadata.Client + quiet bool } // NewClient is the factory method for DB client -func NewClient(dbc dbOperation, githubClient github.Operation, pb indicator.ProgressBar, clock clock.Clock, metadata Metadata) Client { - return Client{ - dbc: dbc, - githubClient: githubClient, - pb: pb, - clock: clock, - metadata: metadata, +func NewClient(cacheDir string, quiet bool, opts ...Option) *Client { + o := &options{ + clock: clock.RealClock{}, + } + + for _, opt := range opts { + opt(o) + } + + return &Client{ + options: o, + cacheDir: cacheDir, + metadata: metadata.NewClient(cacheDir), + quiet: quiet, } } // NeedsUpdate check is DB needs update -func (c Client) NeedsUpdate(cliVersion string, light, skip bool) (bool, error) { - dbType := db.TypeFull - if light { - dbType = db.TypeLight - } - - metadata, err := c.metadata.Get() +func (c *Client) NeedsUpdate(cliVersion string, skip bool) (bool, error) { + meta, err := c.metadata.Get() if err != nil { log.Logger.Debugf("There is no valid metadata file: %s", err) if skip { log.Logger.Error("The first run cannot skip downloading DB") return false, xerrors.New("--skip-update cannot be specified on the first run") } - metadata = db.Metadata{} // suppress a warning + meta = metadata.Metadata{Version: db.SchemaVersion} } - if db.SchemaVersion < metadata.Version { + if db.SchemaVersion < meta.Version { log.Logger.Errorf("Trivy version (%s) is old. Update to the latest version.", cliVersion) return false, xerrors.Errorf("the version of DB schema doesn't match. Local DB: %d, Expected: %d", - metadata.Version, db.SchemaVersion) + meta.Version, db.SchemaVersion) } if skip { - if err = c.validate(dbType, metadata); err != nil { - return false, err + if err = c.validate(meta); err != nil { + return false, xerrors.Errorf("validate error: %w", err) } return false, nil } - if db.SchemaVersion != metadata.Version || metadata.Type != dbType { + if db.SchemaVersion != meta.Version { return true, nil } - return !c.isNewDB(metadata), nil + return !c.isNewDB(meta), 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") +func (c *Client) validate(meta metadata.Metadata) error { + if db.SchemaVersion != meta.Version { + log.Logger.Error("The local DB has an old schema version which is not supported by the current version of Trivy CLI. It needs to be updated.") + return xerrors.New("--skip-update cannot be specified with the old DB schema") } 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") +func (c *Client) isNewDB(meta metadata.Metadata) bool { + if c.clock.Now().Before(meta.NextUpdate) { + log.Logger.Debug("DB update was skipped because the local 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") + if c.clock.Now().Before(meta.DownloadedAt.Add(time.Hour)) { + log.Logger.Debug("DB update was skipped because the local DB was downloaded during the last hour") return true } return false } // Download downloads the DB file -func (c Client) Download(ctx context.Context, cacheDir string, light bool) error { - // Remove the metadata file before downloading DB +func (c *Client) Download(ctx context.Context, dst string) error { + // Remove the metadata file under the cache directory before downloading DB if err := c.metadata.Delete(); err != nil { log.Logger.Debug("no metadata file") } - dbFile := fullDB - if light { - dbFile = lightDB + if err := c.populateOCIArtifact(); err != nil { + return xerrors.Errorf("OCI artifact error: %w", err) } - rc, size, err := c.githubClient.DownloadDB(ctx, dbFile) - if err != nil { - return xerrors.Errorf("failed to download vulnerability DB: %w", err) - } - defer rc.Close() - - bar := c.pb.Start(int64(size)) - barReader := bar.NewProxyReader(rc) - defer bar.Finish() - gr, err := gzip.NewReader(barReader) - if err != nil { - return xerrors.Errorf("invalid gzip file: %w", err) + if err := c.artifact.Download(ctx, db.Dir(dst)); err != nil { + return xerrors.Errorf("database download error: %w", err) } - dbPath := db.Path(cacheDir) - dbDir := filepath.Dir(dbPath) - - if err = os.MkdirAll(dbDir, 0700); err != nil { - return xerrors.Errorf("failed to mkdir: %w", err) + if err := c.updateDownloadedAt(dst); err != nil { + return xerrors.Errorf("failed to update downloaded_at: %w", err) } - - file, err := os.Create(dbPath) - if err != nil { - return xerrors.Errorf("unable to open DB file: %w", err) - } - defer file.Close() - - limited := io.LimitReader(gr, 2*gb) - if _, err = io.Copy(file, limited); err != nil { - return xerrors.Errorf("failed to save DB file: %w", err) - } - return nil } -// UpdateMetadata updates the DB metadata -func (c Client) UpdateMetadata(cacheDir string) error { +func (c *Client) updateDownloadedAt(dst string) error { log.Logger.Debug("Updating database metadata...") - // make sure the DB has been successfully downloaded - if err := db.Init(cacheDir); err != nil { - return xerrors.Errorf("DB error: %w", err) - } - defer db.Close() - - metadata, err := c.dbc.GetMetadata() + // We have to initialize a metadata client here + // since the destination may be different from the cache directory. + client := metadata.NewClient(dst) + meta, err := client.Get() if err != nil { return xerrors.Errorf("unable to get metadata: %w", err) } - metadata.DownloadedAt = c.clock.Now().UTC() - if err = c.dbc.StoreMetadata(metadata, filepath.Join(cacheDir, "db")); err != nil { - return xerrors.Errorf("failed to store metadata: %w", err) + meta.DownloadedAt = c.clock.Now().UTC() + if err = client.Update(meta); err != nil { + return xerrors.Errorf("failed to update metadata: %w", err) } return nil } -// Metadata defines the file meta -type Metadata struct { // TODO: Move all Metadata things to trivy-db repo - fs afero.Fs - filePath string -} - -// NewMetadata is the factory method for file Metadata -func NewMetadata(fs afero.Fs, cacheDir string) Metadata { - filePath := MetadataPath(cacheDir) - return Metadata{ - fs: fs, - filePath: filePath, - } -} - -// MetadataPath returns the metaData file path -func MetadataPath(cacheDir string) string { - dbPath := db.Path(cacheDir) - dbDir := filepath.Dir(dbPath) - return filepath.Join(dbDir, metadataFile) -} - -// Delete deletes the file of database metadata -func (m Metadata) Delete() error { - if err := m.fs.Remove(m.filePath); err != nil { - return xerrors.Errorf("unable to remove the metadata file: %w", err) +func (c *Client) populateOCIArtifact() error { + if c.artifact == nil { + repo := fmt.Sprintf("%s:%d", dbRepository, db.SchemaVersion) + art, err := oci.NewArtifact(repo, dbMediaType, c.quiet) + if err != nil { + return xerrors.Errorf("OCI artifact error: %w", err) + } + c.artifact = art } return nil } - -// Get returns the file metadata -func (m Metadata) Get() (db.Metadata, error) { - f, err := m.fs.Open(m.filePath) - if err != nil { - return db.Metadata{}, xerrors.Errorf("unable to open a file: %w", err) - } - defer f.Close() - - var metadata db.Metadata - if err = json.NewDecoder(f).Decode(&metadata); err != nil { - return db.Metadata{}, xerrors.Errorf("unable to decode metadata: %w", err) - } - return metadata, nil -} diff --git a/pkg/db/db_test.go b/pkg/db/db_test.go index adad221fdb..e236419761 100644 --- a/pkg/db/db_test.go +++ b/pkg/db/db_test.go @@ -1,367 +1,224 @@ -package db +package db_test import ( "context" - "encoding/json" - "errors" - "os" + "fmt" "testing" "time" - "github.com/aquasecurity/trivy/pkg/github" - "github.com/aquasecurity/trivy/pkg/indicator" - - "github.com/spf13/afero" - + "github.com/google/go-containerregistry/pkg/v1" + fakei "github.com/google/go-containerregistry/pkg/v1/fake" + "github.com/google/go-containerregistry/pkg/v1/tarball" + "github.com/google/go-containerregistry/pkg/v1/types" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - - "golang.org/x/xerrors" - "k8s.io/utils/clock" clocktesting "k8s.io/utils/clock/testing" - "github.com/aquasecurity/trivy-db/pkg/db" - "github.com/stretchr/testify/assert" + tdb "github.com/aquasecurity/trivy-db/pkg/db" + "github.com/aquasecurity/trivy-db/pkg/metadata" + "github.com/aquasecurity/trivy/pkg/db" + "github.com/aquasecurity/trivy/pkg/oci" ) +const mediaType = "application/vnd.aquasec.trivy.db.layer.v1.tar+gzip" + +type fakeLayer struct { + v1.Layer +} + +func (f fakeLayer) MediaType() (types.MediaType, error) { + return mediaType, nil +} + +func newFakeLayer(t *testing.T, input string) v1.Layer { + layer, err := tarball.LayerFromFile(input) + require.NoError(t, err) + + return fakeLayer{layer} +} + func TestClient_NeedsUpdate(t *testing.T) { timeNextUpdateDay1 := time.Date(2019, 9, 1, 0, 0, 0, 0, time.UTC) timeNextUpdateDay2 := time.Date(2019, 10, 2, 0, 0, 0, 0, time.UTC) - testCases := []struct { - name string - light bool - skip bool - clock clock.Clock - metadata db.Metadata - expected bool - expectedError error + tests := []struct { + name string + skip bool + clock clock.Clock + metadata metadata.Metadata + want bool + wantErr string }{ { name: "happy path", - light: false, clock: clocktesting.NewFakeClock(time.Date(2019, 10, 1, 0, 0, 0, 0, time.UTC)), - metadata: db.Metadata{ - Version: 1, - Type: db.TypeFull, + metadata: metadata.Metadata{ + Version: tdb.SchemaVersion, NextUpdate: timeNextUpdateDay1, }, - expected: true, + want: true, }, { name: "happy path for first run", - light: false, clock: clocktesting.NewFakeClock(time.Date(2019, 10, 1, 0, 0, 0, 0, time.UTC)), - metadata: db.Metadata{}, - expected: true, - }, - { - name: "happy path with different type", - light: true, - clock: clocktesting.NewFakeClock(time.Date(2019, 10, 1, 0, 0, 0, 0, time.UTC)), - metadata: db.Metadata{ - Version: 1, - Type: db.TypeFull, - NextUpdate: timeNextUpdateDay1, - }, - expected: true, + metadata: metadata.Metadata{}, + want: true, }, { name: "happy path with old schema version", - light: true, clock: clocktesting.NewFakeClock(time.Date(2019, 10, 1, 0, 0, 0, 0, time.UTC)), - metadata: db.Metadata{ + metadata: metadata.Metadata{ Version: 0, - Type: db.TypeFull, NextUpdate: timeNextUpdateDay1, }, - expected: true, + want: true, }, { name: "happy path with --skip-update", - light: false, clock: clocktesting.NewFakeClock(time.Date(2019, 10, 1, 0, 0, 0, 0, time.UTC)), - metadata: db.Metadata{ - Version: 1, - Type: db.TypeFull, + metadata: metadata.Metadata{ + Version: tdb.SchemaVersion, NextUpdate: timeNextUpdateDay1, }, - skip: true, - expected: false, + skip: true, + want: false, }, { name: "skip downloading DB", - light: false, clock: clocktesting.NewFakeClock(time.Date(2019, 10, 1, 0, 0, 0, 0, time.UTC)), - metadata: db.Metadata{ - Version: 1, - Type: db.TypeFull, + metadata: metadata.Metadata{ + Version: tdb.SchemaVersion, NextUpdate: timeNextUpdateDay2, }, - expected: false, + want: false, }, { name: "newer schema version", - light: false, clock: clocktesting.NewFakeClock(time.Date(2019, 10, 1, 0, 0, 0, 0, time.UTC)), - metadata: db.Metadata{ - Version: 2, - Type: db.TypeFull, + metadata: metadata.Metadata{ + Version: tdb.SchemaVersion + 1, NextUpdate: timeNextUpdateDay2, }, - expectedError: xerrors.New("the version of DB schema doesn't match. Local DB: 2, Expected: 1"), + wantErr: fmt.Sprintf("the version of DB schema doesn't match. Local DB: %d, Expected: %d", + tdb.SchemaVersion+1, tdb.SchemaVersion), }, { - name: "--skip-update on the first run", - light: false, - clock: clocktesting.NewFakeClock(time.Date(2019, 10, 1, 0, 0, 0, 0, time.UTC)), - metadata: db.Metadata{}, - skip: true, - expectedError: xerrors.New("--skip-update cannot be specified on the first run"), + name: "--skip-update on the first run", + clock: clocktesting.NewFakeClock(time.Date(2019, 10, 1, 0, 0, 0, 0, time.UTC)), + metadata: metadata.Metadata{}, + skip: true, + wantErr: "--skip-update cannot be specified on the first run", }, { name: "--skip-update with different schema version", - light: false, clock: clocktesting.NewFakeClock(time.Date(2019, 10, 1, 0, 0, 0, 0, time.UTC)), - metadata: db.Metadata{ + metadata: metadata.Metadata{ Version: 0, - Type: db.TypeFull, NextUpdate: timeNextUpdateDay1, }, - skip: true, - expectedError: xerrors.New("--skip-update cannot be specified with the old DB"), + skip: true, + wantErr: "--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, + metadata: metadata.Metadata{ + Version: tdb.SchemaVersion, NextUpdate: timeNextUpdateDay1, DownloadedAt: time.Date(2019, 9, 30, 22, 30, 0, 0, time.UTC), }, - expected: true, + want: 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, + metadata: metadata.Metadata{ + Version: tdb.SchemaVersion, NextUpdate: timeNextUpdateDay1, DownloadedAt: time.Date(2019, 9, 30, 23, 30, 0, 0, time.UTC), }, - expected: false, + want: false, }, } - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - fs := afero.NewMemMapFs() - metadata := NewMetadata(fs, "/cache") - if tc.metadata != (db.Metadata{}) { - b, err := json.Marshal(tc.metadata) - require.NoError(t, err) - err = afero.WriteFile(fs, metadata.filePath, b, 0600) + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + cacheDir := t.TempDir() + if tt.metadata != (metadata.Metadata{}) { + meta := metadata.NewClient(cacheDir) + err := meta.Update(tt.metadata) require.NoError(t, err) } - client := Client{ - clock: tc.clock, - metadata: metadata, - } - - needsUpdate, err := client.NeedsUpdate("test", tc.light, tc.skip) + client := db.NewClient(cacheDir, true, db.WithClock(tt.clock)) + needsUpdate, err := client.NeedsUpdate("test", tt.skip) switch { - case tc.expectedError != nil: - assert.EqualError(t, err, tc.expectedError.Error(), tc.name) + case tt.wantErr != "": + require.Error(t, err) + assert.Contains(t, err.Error(), tt.wantErr, tt.name) default: - assert.NoError(t, err, tc.name) + assert.NoError(t, err, tt.name) } - assert.Equal(t, tc.expected, needsUpdate) + assert.Equal(t, tt.want, needsUpdate) }) } } func TestClient_Download(t *testing.T) { - testCases := []struct { - name string - light bool - downloadDB []github.DownloadDBExpectation - expectedContent []byte - expectedError error - }{ - { - name: "happy path", - light: false, - downloadDB: []github.DownloadDBExpectation{ - { - Args: github.DownloadDBInput{FileName: fullDB}, - ReturnArgs: github.DownloadDBOutput{ - FileName: "testdata/test.db.gz", - }, - }, - }, - }, - { - name: "DownloadDB returns an error", - light: false, - downloadDB: []github.DownloadDBExpectation{ - { - Args: github.DownloadDBInput{FileName: fullDB}, - ReturnArgs: github.DownloadDBOutput{ - Err: xerrors.New("download failed"), - }, - }, - }, - expectedError: xerrors.New("failed to download vulnerability DB: download failed"), - }, - { - name: "invalid gzip", - light: false, - downloadDB: []github.DownloadDBExpectation{ - { - Args: github.DownloadDBInput{FileName: fullDB}, - ReturnArgs: github.DownloadDBOutput{ - FileName: "testdata/invalid.db.gz", - }, - }, - }, - expectedError: xerrors.New("invalid gzip file: unexpected EOF"), - }, - } - - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - mockConfig := new(mockDbOperation) - - mockGitHubClient, err := github.NewMockClient(tc.downloadDB) - require.NoError(t, err, tc.name) - - fs := afero.NewMemMapFs() - metadata := NewMetadata(fs, "/cache") - - dir, err := os.MkdirTemp("", "db") - require.NoError(t, err, tc.name) - defer os.RemoveAll(dir) - - pb := indicator.NewProgressBar(true) - client := NewClient(mockConfig, mockGitHubClient, pb, nil, metadata) - ctx := context.Background() - err = client.Download(ctx, dir, tc.light) - - switch { - case tc.expectedError != nil: - assert.EqualError(t, err, tc.expectedError.Error(), tc.name) - default: - assert.NoError(t, err, tc.name) - } - - mockGitHubClient.AssertExpectations(t) - }) - } -} - -func TestClient_UpdateMetadata(t *testing.T) { timeDownloadedAt := clocktesting.NewFakeClock(time.Date(2019, 10, 1, 0, 0, 0, 0, time.UTC)) - testCases := []struct { - name string - clock clock.Clock - getMetadataExpectation dbOperationGetMetadataExpectation - storeMetadataExpectation dbOperationStoreMetadataExpectation - expectedError error + + tests := []struct { + name string + input string + want metadata.Metadata + wantErr string }{ { name: "happy path", - clock: timeDownloadedAt, - getMetadataExpectation: dbOperationGetMetadataExpectation{ - Returns: dbOperationGetMetadataReturns{ - Metadata: db.Metadata{ - Version: 1, - Type: 1, - NextUpdate: time.Date(2020, 4, 30, 23, 59, 59, 0, time.UTC), - UpdatedAt: time.Date(2006, 4, 30, 23, 59, 59, 0, time.UTC), - }, - Err: nil, - }, - }, - storeMetadataExpectation: dbOperationStoreMetadataExpectation{ - Metadata: db.Metadata{ - Version: 1, - Type: 1, - NextUpdate: time.Date(2020, 4, 30, 23, 59, 59, 0, time.UTC), - UpdatedAt: time.Date(2006, 4, 30, 23, 59, 59, 0, time.UTC), - DownloadedAt: timeDownloadedAt.Now(), - }, + input: "testdata/db.tar.gz", + want: metadata.Metadata{ + Version: 1, + NextUpdate: time.Date(3000, 1, 1, 18, 5, 43, 198355188, time.UTC), + UpdatedAt: time.Date(3000, 1, 1, 12, 5, 43, 198355588, time.UTC), + DownloadedAt: time.Date(2019, 10, 1, 0, 0, 0, 0, time.UTC), }, }, { - name: "sad path, get metadata fails", - clock: timeDownloadedAt, - getMetadataExpectation: dbOperationGetMetadataExpectation{ - Returns: dbOperationGetMetadataReturns{ - Err: errors.New("get metadata failed"), - }, - }, - expectedError: errors.New("unable to get metadata: get metadata failed"), - }, - { - name: "sad path, store metadata fails", - clock: timeDownloadedAt, - getMetadataExpectation: dbOperationGetMetadataExpectation{ - Returns: dbOperationGetMetadataReturns{ - Metadata: db.Metadata{ - Version: 1, - Type: 1, - NextUpdate: time.Date(2020, 4, 30, 23, 59, 59, 0, time.UTC), - UpdatedAt: time.Date(2006, 4, 30, 23, 59, 59, 0, time.UTC), - }, - Err: nil, - }, - }, - storeMetadataExpectation: dbOperationStoreMetadataExpectation{ - Metadata: db.Metadata{ - Version: 1, - Type: 1, - NextUpdate: time.Date(2020, 4, 30, 23, 59, 59, 0, time.UTC), - UpdatedAt: time.Date(2006, 4, 30, 23, 59, 59, 0, time.UTC), - DownloadedAt: timeDownloadedAt.Now(), - }, - Returns: dbOperationStoreMetadataReturns{ - Err: errors.New("store metadata failed"), - }, - }, - expectedError: errors.New("failed to store metadata: store metadata failed"), + name: "invalid gzip", + input: "testdata/trivy.db", + wantErr: "unexpected EOF", }, } - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - mockConfig := new(mockDbOperation) - mockConfig.ApplyGetMetadataExpectation(tc.getMetadataExpectation) - mockConfig.ApplyStoreMetadataExpectation(tc.storeMetadataExpectation) + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + cacheDir := t.TempDir() - fs := afero.NewMemMapFs() - metadata := NewMetadata(fs, "/cache") + // Mock image + img := new(fakei.FakeImage) + img.LayersReturns([]v1.Layer{newFakeLayer(t, tt.input)}, nil) - dir, err := os.MkdirTemp("", "db") - require.NoError(t, err, tc.name) - defer os.RemoveAll(dir) + // Mock OCI artifact + art, err := oci.NewArtifact("db", mediaType, true, oci.WithImage(img)) + require.NoError(t, err) - pb := indicator.NewProgressBar(true) - client := NewClient(mockConfig, nil, pb, tc.clock, metadata) - - err = client.UpdateMetadata(dir) - switch { - case tc.expectedError != nil: - assert.EqualError(t, err, tc.expectedError.Error(), tc.name) - default: - assert.NoError(t, err, tc.name) + client := db.NewClient(cacheDir, true, db.WithOCIArtifact(art), db.WithClock(timeDownloadedAt)) + err = client.Download(context.Background(), cacheDir) + if tt.wantErr != "" { + require.Error(t, err) + assert.Contains(t, err.Error(), tt.wantErr) + return } + assert.NoError(t, err) + + meta := metadata.NewClient(cacheDir) + got, err := meta.Get() + require.NoError(t, err) + + assert.Equal(t, tt.want, got) }) } } diff --git a/pkg/db/mock_db_operation.go b/pkg/db/mock_db_operation.go deleted file mode 100644 index f1992efcfd..0000000000 --- a/pkg/db/mock_db_operation.go +++ /dev/null @@ -1,88 +0,0 @@ -// Code generated by mockery v1.0.0. DO NOT EDIT. - -package db - -import ( - "github.com/aquasecurity/trivy-db/pkg/db" - mock "github.com/stretchr/testify/mock" -) - -// mockDbOperation is an autogenerated mock type for the dbOperation type -type mockDbOperation struct { - mock.Mock -} - -type dbOperationGetMetadataReturns struct { - Metadata db.Metadata - Err error -} - -type dbOperationGetMetadataExpectation struct { - Returns dbOperationGetMetadataReturns -} - -func (_m *mockDbOperation) ApplyGetMetadataExpectation(e dbOperationGetMetadataExpectation) { - var args []interface{} - _m.On("GetMetadata", args...).Return(e.Returns.Metadata, e.Returns.Err) -} - -func (_m *mockDbOperation) ApplyGetMetadataExpectations(expectations []dbOperationGetMetadataExpectation) { - for _, e := range expectations { - _m.ApplyGetMetadataExpectation(e) - } -} - -// GetMetadata provides a mock function with given fields: -func (_m *mockDbOperation) GetMetadata() (db.Metadata, error) { - ret := _m.Called() - - var r0 db.Metadata - if rf, ok := ret.Get(0).(func() db.Metadata); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(db.Metadata) - } - - var r1 error - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -type dbOperationStoreMetadataReturns struct { - Err error -} - -type dbOperationStoreMetadataExpectation struct { - Metadata db.Metadata - Dir string - Returns dbOperationStoreMetadataReturns -} - -func (_m *mockDbOperation) ApplyStoreMetadataExpectation(e dbOperationStoreMetadataExpectation) { - _m.On("StoreMetadata", e.Metadata, mock.Anything).Return(e.Returns.Err) -} - -func (_m *mockDbOperation) ApplyStoreMetadataExpectations(expectations []dbOperationStoreMetadataExpectation) { - for _, e := range expectations { - _m.ApplyStoreMetadataExpectation(e) - } -} - -// StoreMetadata provides a mock function with given fields: metadata, dir -func (_m *mockDbOperation) StoreMetadata(metadata db.Metadata, dir string) error { - ret := _m.Called(metadata, dir) - - var r0 error - if rf, ok := ret.Get(0).(func(db.Metadata, string) error); ok { - r0 = rf(metadata, dir) - } else { - r0 = ret.Error(0) - } - - return r0 -} diff --git a/pkg/db/mock_operation.go b/pkg/db/mock_operation.go index ec397abf4c..5b8f828b94 100644 --- a/pkg/db/mock_operation.go +++ b/pkg/db/mock_operation.go @@ -14,12 +14,10 @@ type MockOperation struct { } type OperationDownloadArgs struct { - Ctx context.Context - CtxAnything bool - CacheDir string - CacheDirAnything bool - Light bool - LightAnything bool + Ctx context.Context + CtxAnything bool + Dst string + DstAnything bool } type OperationDownloadReturns struct { @@ -38,15 +36,10 @@ func (_m *MockOperation) ApplyDownloadExpectation(e OperationDownloadExpectation } else { args = append(args, e.Args.Ctx) } - if e.Args.CacheDirAnything { + if e.Args.DstAnything { args = append(args, mock.Anything) } else { - args = append(args, e.Args.CacheDir) - } - if e.Args.LightAnything { - args = append(args, mock.Anything) - } else { - args = append(args, e.Args.Light) + args = append(args, e.Args.Dst) } _m.On("Download", args...).Return(e.Returns.Err) } @@ -57,13 +50,13 @@ func (_m *MockOperation) ApplyDownloadExpectations(expectations []OperationDownl } } -// Download provides a mock function with given fields: ctx, cacheDir, light -func (_m *MockOperation) Download(ctx context.Context, cacheDir string, light bool) error { - ret := _m.Called(ctx, cacheDir, light) +// Download provides a mock function with given fields: ctx, dst +func (_m *MockOperation) Download(ctx context.Context, dst string) error { + ret := _m.Called(ctx, dst) var r0 error - if rf, ok := ret.Get(0).(func(context.Context, string, bool) error); ok { - r0 = rf(ctx, cacheDir, light) + if rf, ok := ret.Get(0).(func(context.Context, string) error); ok { + r0 = rf(ctx, dst) } else { r0 = ret.Error(0) } @@ -76,8 +69,6 @@ type OperationNeedsUpdateArgs struct { CliVersionAnything bool Skip bool SkipAnything bool - Light bool - LightAnything bool } type OperationNeedsUpdateReturns struct { @@ -102,11 +93,6 @@ func (_m *MockOperation) ApplyNeedsUpdateExpectation(e OperationNeedsUpdateExpec } else { args = append(args, e.Args.Skip) } - if e.Args.LightAnything { - args = append(args, mock.Anything) - } else { - args = append(args, e.Args.Light) - } _m.On("NeedsUpdate", args...).Return(e.Returns.Need, e.Returns.Err) } @@ -116,67 +102,23 @@ func (_m *MockOperation) ApplyNeedsUpdateExpectations(expectations []OperationNe } } -// NeedsUpdate provides a mock function with given fields: cliVersion, skip, light -func (_m *MockOperation) NeedsUpdate(cliVersion string, skip bool, light bool) (bool, error) { - ret := _m.Called(cliVersion, skip, light) +// NeedsUpdate provides a mock function with given fields: cliVersion, skip +func (_m *MockOperation) NeedsUpdate(cliVersion string, skip bool) (bool, error) { + ret := _m.Called(cliVersion, skip) var r0 bool - if rf, ok := ret.Get(0).(func(string, bool, bool) bool); ok { - r0 = rf(cliVersion, skip, light) + if rf, ok := ret.Get(0).(func(string, bool) bool); ok { + r0 = rf(cliVersion, skip) } else { r0 = ret.Get(0).(bool) } var r1 error - if rf, ok := ret.Get(1).(func(string, bool, bool) error); ok { - r1 = rf(cliVersion, skip, light) + if rf, ok := ret.Get(1).(func(string, bool) error); ok { + r1 = rf(cliVersion, skip) } else { r1 = ret.Error(1) } return r0, r1 } - -type OperationUpdateMetadataArgs struct { - CacheDir string - CacheDirAnything bool -} - -type OperationUpdateMetadataReturns struct { - Err error -} - -type OperationUpdateMetadataExpectation struct { - Args OperationUpdateMetadataArgs - Returns OperationUpdateMetadataReturns -} - -func (_m *MockOperation) ApplyUpdateMetadataExpectation(e OperationUpdateMetadataExpectation) { - var args []interface{} - if e.Args.CacheDirAnything { - args = append(args, mock.Anything) - } else { - args = append(args, e.Args.CacheDir) - } - _m.On("UpdateMetadata", args...).Return(e.Returns.Err) -} - -func (_m *MockOperation) ApplyUpdateMetadataExpectations(expectations []OperationUpdateMetadataExpectation) { - for _, e := range expectations { - _m.ApplyUpdateMetadataExpectation(e) - } -} - -// UpdateMetadata provides a mock function with given fields: cacheDir -func (_m *MockOperation) UpdateMetadata(cacheDir string) error { - ret := _m.Called(cacheDir) - - var r0 error - if rf, ok := ret.Get(0).(func(string) error); ok { - r0 = rf(cacheDir) - } else { - r0 = ret.Error(0) - } - - return r0 -} diff --git a/pkg/db/testdata/db.tar.gz b/pkg/db/testdata/db.tar.gz new file mode 100644 index 0000000000..3580e70a11 Binary files /dev/null and b/pkg/db/testdata/db.tar.gz differ diff --git a/pkg/db/testdata/invalid.db.gz b/pkg/db/testdata/invalid.db.gz deleted file mode 100644 index 257cc5642c..0000000000 --- a/pkg/db/testdata/invalid.db.gz +++ /dev/null @@ -1 +0,0 @@ -foo diff --git a/pkg/db/testdata/test.db.gz b/pkg/db/testdata/test.db.gz deleted file mode 100644 index 0811776fa8..0000000000 Binary files a/pkg/db/testdata/test.db.gz and /dev/null differ diff --git a/pkg/db/testdata/trivy.db b/pkg/db/testdata/trivy.db new file mode 100644 index 0000000000..30d74d2584 --- /dev/null +++ b/pkg/db/testdata/trivy.db @@ -0,0 +1 @@ +test \ No newline at end of file diff --git a/pkg/github/github.go b/pkg/github/github.go deleted file mode 100644 index 88d2fce08e..0000000000 --- a/pkg/github/github.go +++ /dev/null @@ -1,142 +0,0 @@ -package github - -import ( - "context" - "fmt" - "io" - "net/http" - "os" - "sort" - "strconv" - "strings" - - "github.com/google/go-github/v33/github" - "golang.org/x/oauth2" - "golang.org/x/xerrors" - - "github.com/aquasecurity/trivy-db/pkg/db" - "github.com/aquasecurity/trivy/pkg/log" -) - -const ( - owner = "aquasecurity" - repo = "trivy-db" -) - -// RepositoryInterface defines the operations on repository -type RepositoryInterface interface { - ListReleases(ctx context.Context, opt *github.ListOptions) ([]*github.RepositoryRelease, *github.Response, error) - DownloadAsset(ctx context.Context, id int64) (io.ReadCloser, string, error) -} - -// Repository implements RepositoryInterface -type Repository struct { - repository *github.RepositoriesService - git *github.GitService - owner 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) { - return r.repository.ListReleases(ctx, r.owner, r.repoName, opt) -} - -// DownloadAsset returns reader object of downloaded object -func (r Repository) DownloadAsset(ctx context.Context, id int64) (io.ReadCloser, string, error) { - return r.repository.DownloadReleaseAsset(ctx, r.owner, r.repoName, id, nil) -} - -// Operation defines the file operations -type Operation interface { - DownloadDB(ctx context.Context, fileName string) (io.ReadCloser, int, error) -} - -// Client implements RepositoryInterface -type Client struct { - Repository RepositoryInterface -} - -// NewClient is the factory method to return Client for RepositoryInterface operations -func NewClient() Client { - var client *http.Client - githubToken := os.Getenv("GITHUB_TOKEN") - if githubToken != "" { - log.Logger.Info("Using your github token") - ctx := context.Background() - ts := oauth2.StaticTokenSource(&oauth2.Token{AccessToken: githubToken}) - client = oauth2.NewClient(ctx, ts) - } - gc := github.NewClient(client) - - repo := Repository{ - repository: gc.Repositories, - git: gc.Git, - owner: owner, - repoName: repo, - } - - return Client{ - Repository: repo, - } -} - -// DownloadDB returns reader object of file content -func (c Client) DownloadDB(ctx context.Context, fileName string) (io.ReadCloser, int, error) { - options := github.ListOptions{} - releases, _, err := c.Repository.ListReleases(ctx, &options) - if err != nil { - return nil, 0, xerrors.Errorf("failed to list releases: %w", err) - } - - sort.Slice(releases, func(i, j int) bool { - return releases[i].GetPublishedAt().After(releases[j].GetPublishedAt().Time) - }) - - prefix := fmt.Sprintf("v%d", db.SchemaVersion) - for _, release := range releases { - log.Logger.Debugf("release name: %s", release.GetName()) - if !strings.HasPrefix(release.GetName(), prefix) { - continue - } - - for _, asset := range release.Assets { - rc, size, err := c.downloadAsset(ctx, asset, fileName) - if err != nil { - log.Logger.Debug(err) - continue - } - return rc, size, nil - } - - } - return nil, 0, xerrors.New("DB file not found") -} - -func (c Client) downloadAsset(ctx context.Context, asset *github.ReleaseAsset, fileName string) (io.ReadCloser, int, error) { - log.Logger.Debugf("asset name: %s", asset.GetName()) - if asset.GetName() != fileName { - return nil, 0, xerrors.New("file name doesn't match") - } - - rc, url, err := c.Repository.DownloadAsset(ctx, asset.GetID()) - if err != nil { - return nil, 0, xerrors.Errorf("unable to download the asset: %w", err) - } - - if rc != nil { - return rc, asset.GetSize(), nil - } - - log.Logger.Debugf("asset URL: %s", url) - resp, err := http.Get(url) // nolint: gosec - if err != nil || resp.StatusCode != http.StatusOK { - return nil, 0, xerrors.Errorf("unable to download the asset via URL: %w", err) - } - - size, err := strconv.Atoi(resp.Header.Get("Content-Length")) - if err != nil { - return nil, 0, xerrors.Errorf("invalid size: %w", err) - } - return resp.Body, size, nil -} diff --git a/pkg/github/github_mock.go b/pkg/github/github_mock.go deleted file mode 100644 index d9d01da873..0000000000 --- a/pkg/github/github_mock.go +++ /dev/null @@ -1,57 +0,0 @@ -package github - -import ( - "context" - "io" - "os" - - "github.com/stretchr/testify/mock" -) - -type MockClient struct { - mock.Mock -} - -type DownloadDBInput struct { - FileName string -} -type DownloadDBOutput struct { - FileName string - Size int - Err error -} -type DownloadDBExpectation struct { - Args DownloadDBInput - ReturnArgs DownloadDBOutput -} - -func NewMockClient(downloadDBExpectations []DownloadDBExpectation) (*MockClient, error) { - mockDetector := new(MockClient) - for _, e := range downloadDBExpectations { - var rc io.ReadCloser - if e.ReturnArgs.FileName != "" { - f, err := os.Open(e.ReturnArgs.FileName) - if err != nil { - return nil, err - } - rc = f - } - - mockDetector.On("DownloadDB", mock.Anything, e.Args.FileName).Return( - rc, e.ReturnArgs.Size, e.ReturnArgs.Err) - } - return mockDetector, nil -} - -func (_m *MockClient) DownloadDB(ctx context.Context, fileName string) (io.ReadCloser, int, error) { - ret := _m.Called(ctx, fileName) - ret0 := ret.Get(0) - if ret0 == nil { - return nil, ret.Int(1), ret.Error(2) - } - rc, ok := ret0.(io.ReadCloser) - if !ok { - return nil, ret.Int(1), ret.Error(2) - } - return rc, ret.Int(1), ret.Error(2) -} diff --git a/pkg/github/github_test.go b/pkg/github/github_test.go deleted file mode 100644 index 8bb569c33c..0000000000 --- a/pkg/github/github_test.go +++ /dev/null @@ -1,458 +0,0 @@ -package github - -import ( - "context" - "fmt" - "io" - "net/http" - "net/http/httptest" - "net/url" - "path" - "strings" - "testing" - "time" - - "github.com/google/go-github/v33/github" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" - "golang.org/x/xerrors" -) - -type MockRepository struct { - mock.Mock -} - -func (_m *MockRepository) ListReleases(ctx context.Context, opt *github.ListOptions) ( - []*github.RepositoryRelease, *github.Response, error) { - ret := _m.Called(ctx, opt) - ret0 := ret.Get(0) - if ret0 == nil { - return nil, nil, ret.Error(2) - } - releases, ok := ret0.([]*github.RepositoryRelease) - if !ok { - return nil, nil, ret.Error(2) - } - return releases, nil, ret.Error(2) -} - -func (_m *MockRepository) DownloadAsset(ctx context.Context, id int64) (io.ReadCloser, string, error) { - ret := _m.Called(ctx, id) - ret0 := ret.Get(0) - if ret0 == nil { - return nil, ret.String(1), ret.Error(2) - } - rc, ok := ret0.(io.ReadCloser) - if !ok { - return nil, ret.String(1), ret.Error(2) - } - return rc, ret.String(1), ret.Error(2) -} - -func TestClient_DownloadDB(t *testing.T) { - type listReleasesOutput struct { - releases []*github.RepositoryRelease - response *github.Response - err error - } - type listReleases struct { - input string - output listReleasesOutput - } - - type downloadAssetOutput struct { - rc io.ReadCloser - redirectPath string - err error - } - type downloadAsset struct { - input int64 - output downloadAssetOutput - } - - testCases := []struct { - name string - fileName string - filePaths []string - listReleases []listReleases - downloadAsset []downloadAsset - expectedError error - }{ - { - name: "happy path", - fileName: "trivy.db.gz", - listReleases: []listReleases{ - { - input: mock.Anything, - output: listReleasesOutput{ - releases: []*github.RepositoryRelease{ - { - // this release should be skipped due to the wrong prefix of the tag - ID: github.Int64(2), - Name: github.String("v2-2020010101"), - PublishedAt: &github.Timestamp{ - Time: time.Date(2020, 1, 1, 1, 59, 59, 0, time.UTC), - }, - Assets: []*github.ReleaseAsset{ - { - ID: github.Int64(200), - Name: github.String("trivy.db.gz"), - }, - }, - }, - { - ID: github.Int64(1), - Name: github.String("v1-2020123123"), - PublishedAt: &github.Timestamp{ - Time: time.Date(2020, 12, 31, 23, 59, 59, 0, time.UTC), - }, - Assets: []*github.ReleaseAsset{ - { - ID: github.Int64(100), - Name: github.String("trivy.db.gz"), - }, - }, - }, - }, - }, - }, - }, - downloadAsset: []downloadAsset{ - { - input: 100, - output: downloadAssetOutput{ - rc: io.NopCloser(strings.NewReader("foo")), - }, - }, - }, - }, - { - name: "happy path with redirect URL", - fileName: "trivy.db.gz", - listReleases: []listReleases{ - { - input: mock.Anything, - output: listReleasesOutput{ - releases: []*github.RepositoryRelease{ - { - ID: github.Int64(1), - Name: github.String("v1-2020123123"), - PublishedAt: &github.Timestamp{ - Time: time.Date(2020, 12, 31, 23, 59, 59, 0, time.UTC), - }, - Assets: []*github.ReleaseAsset{ - { - ID: github.Int64(100), - Name: github.String("trivy.db.gz"), - }, - }, - }, - }, - }, - }, - }, - downloadAsset: []downloadAsset{ - { - input: 100, - output: downloadAssetOutput{ - redirectPath: "/happy", - }, - }, - }, - }, - { - name: "happy path with inorder releases", - fileName: "trivy.db.gz", - listReleases: []listReleases{ - { - input: mock.Anything, - output: listReleasesOutput{ - releases: []*github.RepositoryRelease{ - { - ID: github.Int64(1), - Name: github.String("v1-2019100123"), - PublishedAt: &github.Timestamp{ - Time: time.Date(2019, 10, 1, 23, 59, 59, 0, time.UTC), - }, - Assets: []*github.ReleaseAsset{ - { - ID: github.Int64(100), - Name: github.String("trivy.db.gz"), - }, - }, - }, - { - // this release should be used because this is the latest - ID: github.Int64(3), - Name: github.String("v1-2019100200"), - PublishedAt: &github.Timestamp{ - Time: time.Date(2019, 10, 2, 0, 59, 59, 0, time.UTC), - }, - Assets: []*github.ReleaseAsset{ - { - ID: github.Int64(300), - Name: github.String("trivy.db.gz"), - }, - }, - }, - { - ID: github.Int64(2), - Name: github.String("v1-2019100122"), - PublishedAt: &github.Timestamp{ - Time: time.Date(2019, 10, 1, 22, 59, 59, 0, time.UTC), - }, - Assets: []*github.ReleaseAsset{ - { - ID: github.Int64(200), - Name: github.String("trivy.db.gz"), - }, - }, - }, - }, - }, - }, - }, - downloadAsset: []downloadAsset{ - { - input: 300, - output: downloadAssetOutput{ - rc: io.NopCloser(strings.NewReader("foo")), - }, - }, - }, - }, - { - name: "happy path with no asset", - fileName: "trivy.db.gz", - listReleases: []listReleases{ - { - input: mock.Anything, - output: listReleasesOutput{ - releases: []*github.RepositoryRelease{ - { - // this release should be skipped due to no asset - ID: github.Int64(1), - Name: github.String("v1-2019100123"), - PublishedAt: &github.Timestamp{ - Time: time.Date(2019, 10, 1, 23, 59, 59, 0, time.UTC), - }, - }, - { - // this release should be skipped due to no asset - ID: github.Int64(3), - Name: github.String("v1-2019100200"), - PublishedAt: &github.Timestamp{ - Time: time.Date(2019, 10, 2, 0, 59, 59, 0, time.UTC), - }, - }, - { - // this release should be used because this release has assets - ID: github.Int64(2), - Name: github.String("v1-2019100122"), - PublishedAt: &github.Timestamp{ - Time: time.Date(2019, 10, 1, 22, 59, 59, 0, time.UTC), - }, - Assets: []*github.ReleaseAsset{ - { - ID: github.Int64(200), - Name: github.String("trivy.db.gz"), - }, - }, - }, - }, - }, - }, - }, - downloadAsset: []downloadAsset{ - { - input: 200, - output: downloadAssetOutput{ - rc: io.NopCloser(strings.NewReader("foo")), - }, - }, - }, - }, - { - name: "no asset", - fileName: "trivy.db.gz", - listReleases: []listReleases{ - { - input: mock.Anything, - output: listReleasesOutput{ - releases: []*github.RepositoryRelease{ - { - ID: github.Int64(1), - Name: github.String("v1-2020123000"), - PublishedAt: &github.Timestamp{ - Time: time.Date(2020, 12, 31, 23, 59, 59, 0, time.UTC), - }, - }, - }, - }, - }, - }, - expectedError: xerrors.New("DB file not found"), - }, - { - name: "the file name doesn't match", - fileName: "trivy-light.db.gz", - listReleases: []listReleases{ - { - input: mock.Anything, - output: listReleasesOutput{ - releases: []*github.RepositoryRelease{ - { - ID: github.Int64(1), - Name: github.String("v1-2020123000"), - PublishedAt: &github.Timestamp{ - Time: time.Date(2020, 12, 31, 23, 59, 59, 0, time.UTC), - }, - Assets: []*github.ReleaseAsset{ - { - ID: github.Int64(100), - Name: github.String("trivy.db.gz"), - }, - }, - }, - }, - }, - }, - }, - expectedError: xerrors.New("DB file not found"), - }, - { - name: "ListReleases returns error", - fileName: "trivy.db.gz", - listReleases: []listReleases{ - { - input: mock.Anything, - output: listReleasesOutput{ - err: xerrors.New("something wrong"), - }, - }, - }, - expectedError: xerrors.New("failed to list releases: something wrong"), - }, - { - name: "DownloadAsset returns error", - fileName: "trivy.db.gz", - listReleases: []listReleases{ - { - input: mock.Anything, - output: listReleasesOutput{ - releases: []*github.RepositoryRelease{ - { - ID: github.Int64(1), - Name: github.String("v1-2020123000"), - PublishedAt: &github.Timestamp{ - Time: time.Date(2020, 12, 31, 23, 59, 59, 0, time.UTC), - }, - Assets: []*github.ReleaseAsset{ - { - ID: github.Int64(100), - Name: github.String("trivy.db.gz"), - }, - }, - }, - }, - }, - }, - }, - downloadAsset: []downloadAsset{ - { - input: 100, - output: downloadAssetOutput{ - err: xerrors.New("something wrong"), - }, - }, - }, - expectedError: xerrors.New("DB file not found"), - }, - { - name: "404 error", - fileName: "trivy.db.gz", - listReleases: []listReleases{ - { - input: mock.Anything, - output: listReleasesOutput{ - releases: []*github.RepositoryRelease{ - { - ID: github.Int64(1), - Name: github.String("v1-2020123000"), - PublishedAt: &github.Timestamp{ - Time: time.Date(2020, 12, 31, 23, 59, 59, 0, time.UTC), - }, - Assets: []*github.ReleaseAsset{ - { - ID: github.Int64(100), - Name: github.String("trivy.db.gz"), - }, - }, - }, - }, - }, - }, - }, - downloadAsset: []downloadAsset{ - { - input: 100, - output: downloadAssetOutput{ - redirectPath: "/not_found", - }, - }, - }, - expectedError: xerrors.New("DB file not found"), - }, - } - - ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - switch r.URL.Path { - case "/happy": - _, _ = fmt.Fprintf(w, "happy") - case "/not_found": - http.NotFound(w, r) - } - return - }, - )) - defer ts.Close() - - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - mockRepo := new(MockRepository) - for _, lr := range tc.listReleases { - mockRepo.On("ListReleases", mock.Anything, lr.input).Return( - lr.output.releases, lr.output.response, lr.output.err, - ) - } - for _, da := range tc.downloadAsset { - var redirectURL string - if da.output.redirectPath != "" { - u, _ := url.Parse(ts.URL) - u.Path = path.Join(u.Path, da.output.redirectPath) - redirectURL = u.String() - } - mockRepo.On("DownloadAsset", mock.Anything, da.input).Return( - da.output.rc, redirectURL, da.output.err, - ) - } - - client := Client{ - Repository: mockRepo, - } - - ctx := context.Background() - rc, _, err := client.DownloadDB(ctx, tc.fileName) - - switch { - case tc.expectedError != nil: - assert.EqualError(t, err, tc.expectedError.Error(), tc.name) - default: - assert.NoError(t, err, tc.name) - assert.NotNil(t, rc, tc.name) - } - - mockRepo.AssertExpectations(t) - }) - } -} diff --git a/pkg/indicator/progress.go b/pkg/indicator/progress.go deleted file mode 100644 index fc609f6cd3..0000000000 --- a/pkg/indicator/progress.go +++ /dev/null @@ -1,47 +0,0 @@ -package indicator - -import ( - "io" - - "github.com/cheggaaa/pb/v3" -) - -// ProgressBar exports method to track the progress of jobs -type ProgressBar struct { - quiet bool -} - -// NewProgressBar is the factory method to return progressBar object -func NewProgressBar(quiet bool) ProgressBar { - return ProgressBar{quiet: quiet} -} - -// Start starts the progress tracking -func (p ProgressBar) Start(total int64) Bar { - if p.quiet { - return Bar{} - } - bar := pb.Full.Start64(total) - return Bar{bar: bar} -} - -// Bar is the proxy progress bar -type Bar struct { - bar *pb.ProgressBar -} - -// NewProxyReader is the factory method to track the progress -func (b Bar) NewProxyReader(r io.Reader) io.Reader { - if b.bar == nil { - return r - } - return b.bar.NewProxyReader(r) -} - -// Finish finishes the progress tracking -func (b Bar) Finish() { - if b.bar == nil { - return - } - b.bar.Finish() -} diff --git a/pkg/oci/artifact.go b/pkg/oci/artifact.go new file mode 100644 index 0000000000..1cbedcd895 --- /dev/null +++ b/pkg/oci/artifact.go @@ -0,0 +1,135 @@ +package oci + +import ( + "context" + "io" + "os" + + "github.com/cheggaaa/pb/v3" + + "github.com/google/go-containerregistry/pkg/name" + v1 "github.com/google/go-containerregistry/pkg/v1" + "github.com/google/go-containerregistry/pkg/v1/remote" + "golang.org/x/xerrors" + + "github.com/aquasecurity/trivy/pkg/downloader" +) + +type options struct { + img v1.Image +} + +// Option is a functional option +type Option func(*options) + +// WithImage takes an OCI v1 Image +func WithImage(img v1.Image) Option { + return func(opts *options) { + opts.img = img + } +} + +// Artifact is used to download artifacts such as vulnerability database and policies from OCI registries. +type Artifact struct { + image v1.Image + layer v1.Layer // Take the first layer as OCI artifact + quiet bool +} + +// NewArtifact returns a new artifact +func NewArtifact(repo, mediaType string, quiet bool, opts ...Option) (*Artifact, error) { + o := &options{} + + for _, opt := range opts { + opt(o) + } + + if o.img == nil { + ref, err := name.ParseReference(repo) + if err != nil { + return nil, xerrors.Errorf("repository name error (%s): %w", repo, err) + } + + o.img, err = remote.Image(ref) + if err != nil { + return nil, xerrors.Errorf("OCI repository error: %w", err) + } + } + + layers, err := o.img.Layers() + if err != nil { + return nil, xerrors.Errorf("OCI layer error: %w", err) + } + + // A single layer is only supported now. + if len(layers) != 1 { + return nil, xerrors.Errorf("OCI artifact must be a single layer") + } + + // Take the first layer + layer := layers[0] + + layerMediaType, err := layer.MediaType() + if err != nil { + return nil, xerrors.Errorf("media type error: %w", err) + } else if mediaType != string(layerMediaType) { + return nil, xerrors.Errorf("unacceptable media type: %s", string(layerMediaType)) + } + + return &Artifact{ + image: o.img, + layer: layer, + quiet: quiet, + }, nil +} + +func (a Artifact) Download(ctx context.Context, dir string) error { + size, err := a.layer.Size() + if err != nil { + return xerrors.Errorf("size error: %w", err) + } + + rc, err := a.layer.Compressed() + if err != nil { + return xerrors.Errorf("failed to fetch the layer: %w", err) + } + defer rc.Close() + + // Show progress bar + bar := pb.Full.Start64(size) + if a.quiet { + bar.SetWriter(io.Discard) + } + pr := bar.NewProxyReader(rc) + defer bar.Finish() + + // https://github.com/hashicorp/go-getter/issues/326 + f, err := os.CreateTemp("", "artifact-*.tar.gz") + if err != nil { + return xerrors.Errorf("failed to create a temp file: %w", err) + } + defer func() { + _ = f.Close() + _ = os.Remove(f.Name()) + }() + + // Download the layer content into a temporal file + if _, err = io.Copy(f, pr); err != nil { + return xerrors.Errorf("copy error: %w", err) + } + + // Decompress artifact-xxx.tar.gz and copy it into the cache dir + if err = downloader.Download(ctx, f.Name(), dir, dir); err != nil { + return xerrors.Errorf("download error: %w", err) + } + + return nil +} + +func (a Artifact) Digest() (string, error) { + digest, err := a.image.Digest() + if err != nil { + return "", xerrors.Errorf("digest error: %w", err) + } + return digest.String(), nil +} diff --git a/pkg/oci/artifact_test.go b/pkg/oci/artifact_test.go new file mode 100644 index 0000000000..bf2c947f19 --- /dev/null +++ b/pkg/oci/artifact_test.go @@ -0,0 +1,149 @@ +package oci_test + +import ( + "context" + "fmt" + "os" + "path/filepath" + "testing" + + "github.com/aquasecurity/trivy/pkg/oci" + "github.com/aquasecurity/trivy/pkg/utils" + v1 "github.com/google/go-containerregistry/pkg/v1" + fakei "github.com/google/go-containerregistry/pkg/v1/fake" + "github.com/google/go-containerregistry/pkg/v1/tarball" + "github.com/google/go-containerregistry/pkg/v1/types" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +type fakeLayer struct { + v1.Layer +} + +func (f fakeLayer) MediaType() (types.MediaType, error) { + return "application/vnd.cncf.openpolicyagent.layer.v1.tar+gzip", nil +} + +func TestNewArtifact(t *testing.T) { + layer, err := tarball.LayerFromFile("testdata/test.tar.gz") + require.NoError(t, err) + + flayer := fakeLayer{layer} + + type layersReturns struct { + layers []v1.Layer + err error + } + tests := []struct { + name string + mediaType string + layersReturns layersReturns + wantErr string + }{ + { + name: "happy path", + mediaType: "application/vnd.cncf.openpolicyagent.layer.v1.tar+gzip", + layersReturns: layersReturns{ + layers: []v1.Layer{flayer}, + }, + }, + { + name: "sad: two layers", + mediaType: "application/vnd.cncf.openpolicyagent.layer.v1.tar+gzip", + layersReturns: layersReturns{ + layers: []v1.Layer{layer, layer}, + }, + wantErr: "OCI artifact must be a single layer", + }, + { + name: "sad: Layers returns an error", + mediaType: "application/vnd.cncf.openpolicyagent.layer.v1.tar+gzip", + layersReturns: layersReturns{ + err: fmt.Errorf("error"), + }, + wantErr: "OCI layer error", + }, + { + name: "sad: media type doesn't match", + mediaType: "unknown", + layersReturns: layersReturns{ + layers: []v1.Layer{layer}, + }, + wantErr: "unacceptable media type", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tempDir := t.TempDir() + utils.SetCacheDir(tempDir) + + // Mock image + img := new(fakei.FakeImage) + img.LayersReturns(tt.layersReturns.layers, tt.layersReturns.err) + + _, err = oci.NewArtifact("repo", tt.mediaType, true, oci.WithImage(img)) + if tt.wantErr != "" { + require.Error(t, err) + assert.Contains(t, err.Error(), tt.wantErr) + return + } + require.NoError(t, err) + }) + } +} + +func TestArtifact_Download(t *testing.T) { + tests := []struct { + name string + input string + want string + wantErr string + }{ + { + name: "happy path", + input: "testdata/test.tar.gz", + want: "Hello, world", + }, + { + name: "invalid gzip", + input: "testdata/test.txt", + wantErr: "unexpected EOF", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tempDir := t.TempDir() + utils.SetCacheDir(tempDir) + + // Mock layer + layer, err := tarball.LayerFromFile(tt.input) + require.NoError(t, err) + flayer := fakeLayer{layer} + + // Mock image + img := new(fakei.FakeImage) + img.LayersReturns([]v1.Layer{flayer}, nil) + + mediaType := "application/vnd.cncf.openpolicyagent.layer.v1.tar+gzip" + artifact, err := oci.NewArtifact("repo", mediaType, true, oci.WithImage(img)) + require.NoError(t, err) + + err = artifact.Download(context.Background(), tempDir) + if tt.wantErr != "" { + require.Error(t, err) + assert.Contains(t, err.Error(), tt.wantErr) + return + } + require.NoError(t, err) + + // Assert + got, err := os.ReadFile(filepath.Join(tempDir, "test.txt")) + require.NoError(t, err) + + assert.Equal(t, tt.want, string(got)) + }) + } +} diff --git a/pkg/oci/testdata/test.tar.gz b/pkg/oci/testdata/test.tar.gz new file mode 100644 index 0000000000..8fc7134871 Binary files /dev/null and b/pkg/oci/testdata/test.tar.gz differ diff --git a/pkg/oci/testdata/test.txt b/pkg/oci/testdata/test.txt new file mode 100644 index 0000000000..dbe9dba55e --- /dev/null +++ b/pkg/oci/testdata/test.txt @@ -0,0 +1 @@ +Hello, world \ No newline at end of file diff --git a/pkg/policy/policy.go b/pkg/policy/policy.go index e55a5d7ec7..d27e7c6386 100644 --- a/pkg/policy/policy.go +++ b/pkg/policy/policy.go @@ -4,42 +4,38 @@ import ( "context" "encoding/json" "fmt" - "io" "os" "path/filepath" "time" - "github.com/google/go-containerregistry/pkg/name" - v1 "github.com/google/go-containerregistry/pkg/v1" - "github.com/google/go-containerregistry/pkg/v1/remote" + "github.com/aquasecurity/trivy/pkg/oci" + "github.com/open-policy-agent/opa/bundle" "golang.org/x/xerrors" "k8s.io/utils/clock" - "github.com/aquasecurity/trivy/pkg/downloader" "github.com/aquasecurity/trivy/pkg/log" - "github.com/aquasecurity/trivy/pkg/utils" ) const ( bundleVersion = 1 bundleRepository = "ghcr.io/aquasecurity/appshield" - layerMediaType = "application/vnd.cncf.openpolicyagent.layer.v1.tar+gzip" + policyMediaType = "application/vnd.cncf.openpolicyagent.layer.v1.tar+gzip" updateInterval = 24 * time.Hour ) type options struct { - img v1.Image - clock clock.Clock + artifact *oci.Artifact + clock clock.Clock } // Option is a functional option type Option func(*options) -// WithImage takes an OCI v1 Image -func WithImage(img v1.Image) Option { +// WithOCIArtifact takes an OCI artifact +func WithOCIArtifact(art *oci.Artifact) Option { return func(opts *options) { - opts.img = img + opts.artifact = art } } @@ -52,18 +48,19 @@ func WithClock(clock clock.Clock) Option { // Metadata holds default policy metadata type Metadata struct { - Digest string - LastDownloadedAt time.Time + Digest string + DownloadedAt time.Time } // Client implements policy operations type Client struct { - img v1.Image - clock clock.Clock + *options + policyDir string + quiet bool } // NewClient is the factory method for policy client -func NewClient(opts ...Option) (*Client, error) { +func NewClient(cacheDir string, quiet bool, opts ...Option) (*Client, error) { o := &options{ clock: clock.RealClock{}, } @@ -73,32 +70,33 @@ func NewClient(opts ...Option) (*Client, error) { } return &Client{ - img: o.img, - clock: o.clock, + options: o, + policyDir: filepath.Join(cacheDir, "policy"), + quiet: quiet, }, nil } // LoadBuiltinPolicies loads default policies func (c *Client) LoadBuiltinPolicies() ([]string, error) { - f, err := os.Open(manifestPath()) + f, err := os.Open(c.manifestPath()) if err != nil { - return nil, xerrors.Errorf("manifest file open error (%s): %w", manifestPath(), err) + return nil, xerrors.Errorf("manifest file open error (%s): %w", c.manifestPath(), err) } var manifest bundle.Manifest if err = json.NewDecoder(f).Decode(&manifest); err != nil { - return nil, xerrors.Errorf("json decode error (%s): %w", manifestPath(), err) + return nil, xerrors.Errorf("json decode error (%s): %w", c.manifestPath(), err) } // If the "roots" field is not included in the manifest it defaults to [""] // which means that ALL data and policy must come from the bundle. if manifest.Roots == nil || len(*manifest.Roots) == 0 { - return []string{contentDir()}, nil + return []string{c.contentDir()}, nil } var policyPaths []string for _, root := range *manifest.Roots { - policyPaths = append(policyPaths, filepath.Join(contentDir(), root)) + policyPaths = append(policyPaths, filepath.Join(c.contentDir(), root)) } return policyPaths, nil @@ -106,7 +104,7 @@ func (c *Client) LoadBuiltinPolicies() ([]string, error) { // NeedsUpdate returns if the default policy should be updated func (c *Client) NeedsUpdate() (bool, error) { - f, err := os.Open(metadataPath()) + f, err := os.Open(c.metadataPath()) if err != nil { log.Logger.Debugf("Failed to open the policy metadata: %s", err) return true, nil @@ -119,20 +117,20 @@ func (c *Client) NeedsUpdate() (bool, error) { } // No need to update if it's been within a day since the last update. - if c.clock.Now().Before(meta.LastDownloadedAt.Add(updateInterval)) { + if c.clock.Now().Before(meta.DownloadedAt.Add(updateInterval)) { return false, nil } - if err = c.populateImage(); err != nil { + if err = c.populateOCIArtifact(); err != nil { return false, xerrors.Errorf("OPA bundle error: %w", err) } - digest, err := c.img.Digest() + digest, err := c.artifact.Digest() if err != nil { return false, xerrors.Errorf("digest error: %w", err) } - if meta.Digest != digest.String() { + if meta.Digest != digest { return true, nil } @@ -144,112 +142,57 @@ func (c *Client) NeedsUpdate() (bool, error) { } return false, nil - } -func (c *Client) populateImage() error { - if c.img == nil { +func (c *Client) populateOCIArtifact() error { + if c.artifact == nil { repo := fmt.Sprintf("%s:%d", bundleRepository, bundleVersion) - ref, err := name.ParseReference(repo) + art, err := oci.NewArtifact(repo, policyMediaType, c.quiet) if err != nil { - return xerrors.Errorf("repository name error (%s): %w", repo, err) - } - - c.img, err = remote.Image(ref) - if err != nil { - return xerrors.Errorf("OCI repository error: %w", err) + return xerrors.Errorf("OCI artifact error: %w", err) } + c.artifact = art } return nil } // DownloadBuiltinPolicies download default policies from GitHub Pages func (c *Client) DownloadBuiltinPolicies(ctx context.Context) error { - if err := c.populateImage(); err != nil { + if err := c.populateOCIArtifact(); err != nil { return xerrors.Errorf("OPA bundle error: %w", err) } - layers, err := c.img.Layers() - if err != nil { - return xerrors.Errorf("OCI layer error: %w", err) - } - - if len(layers) != 1 { - return xerrors.Errorf("OPA bundle must be a single layer: %w", err) - } - - bundleLayer := layers[0] - mediaType, err := bundleLayer.MediaType() - if err != nil { - return xerrors.Errorf("media type error: %w", err) - } - - if mediaType != layerMediaType { - return xerrors.Errorf("unacceptable media type: %s", mediaType) - } - - if err = c.downloadBuiltinPolicies(ctx, bundleLayer); err != nil { + dst := c.contentDir() + if err := c.artifact.Download(ctx, dst); err != nil { return xerrors.Errorf("download error: %w", err) } - digest, err := c.img.Digest() + digest, err := c.artifact.Digest() if err != nil { return xerrors.Errorf("digest error: %w", err) } log.Logger.Debugf("Digest of the built-in policies: %s", digest) // Update metadata.json with the new digest and the current date - if err = c.updateMetadata(digest.String(), c.clock.Now()); err != nil { + if err = c.updateMetadata(digest, c.clock.Now()); err != nil { return xerrors.Errorf("unable to update the policy metadata: %w", err) } return nil } -func (c *Client) downloadBuiltinPolicies(ctx context.Context, bundleLayer v1.Layer) error { - // Take the first layer as OPA bundle - rc, err := bundleLayer.Compressed() - if err != nil { - return xerrors.Errorf("failed to fetch a layer: %w", err) - } - defer rc.Close() - - // https://github.com/hashicorp/go-getter/issues/326 - f, err := os.CreateTemp("", "bundle-*.tar.gz") - if err != nil { - return xerrors.Errorf("failed to create a temp dir: %w", err) - } - defer func() { - _ = f.Close() - _ = os.Remove(f.Name()) - }() - - // Download bundle.tar.gz into a temporal file - if _, err = io.Copy(f, rc); err != nil { - return xerrors.Errorf("copy error: %w", err) - } - - // Decompress bundle.tar.gz and copy into the cache dir - dst := contentDir() - if err = downloader.Download(ctx, f.Name(), dst, dst); err != nil { - return xerrors.Errorf("policy download error: %w", err) - } - - return nil -} - func (c *Client) updateMetadata(digest string, now time.Time) error { - meta := Metadata{ - Digest: digest, - LastDownloadedAt: now, - } - - f, err := os.Create(metadataPath()) + f, err := os.Create(c.metadataPath()) if err != nil { return xerrors.Errorf("failed to open a policy manifest: %w", err) } defer f.Close() + meta := Metadata{ + Digest: digest, + DownloadedAt: now, + } + if err = json.NewEncoder(f).Encode(meta); err != nil { return xerrors.Errorf("json encode error: %w", err) } @@ -257,18 +200,14 @@ func (c *Client) updateMetadata(digest string, now time.Time) error { return nil } -func policyDir() string { - return filepath.Join(utils.CacheDir(), "policy") +func (c *Client) contentDir() string { + return filepath.Join(c.policyDir, "content") } -func contentDir() string { - return filepath.Join(policyDir(), "content") +func (c *Client) metadataPath() string { + return filepath.Join(c.policyDir, "metadata.json") } -func metadataPath() string { - return filepath.Join(policyDir(), "metadata.json") -} - -func manifestPath() string { - return filepath.Join(contentDir(), bundle.ManifestExt) +func (c *Client) manifestPath() string { + return filepath.Join(c.contentDir(), bundle.ManifestExt) } diff --git a/pkg/policy/policy_test.go b/pkg/policy/policy_test.go index ede5a63e98..ccbd7dae2b 100644 --- a/pkg/policy/policy_test.go +++ b/pkg/policy/policy_test.go @@ -4,6 +4,7 @@ import ( "context" "encoding/json" "fmt" + "io" "os" "path/filepath" "testing" @@ -18,8 +19,8 @@ import ( "k8s.io/utils/clock" fake "k8s.io/utils/clock/testing" + "github.com/aquasecurity/trivy/pkg/oci" "github.com/aquasecurity/trivy/pkg/policy" - "github.com/aquasecurity/trivy/pkg/utils" ) type fakeLayer struct { @@ -37,6 +38,25 @@ func newFakeLayer(t *testing.T) v1.Layer { return fakeLayer{layer} } +type brokenLayer struct { + v1.Layer +} + +func (b brokenLayer) MediaType() (types.MediaType, error) { + return "application/vnd.cncf.openpolicyagent.layer.v1.tar+gzip", nil +} + +func (b brokenLayer) Compressed() (io.ReadCloser, error) { + return nil, fmt.Errorf("compressed error") +} + +func newBrokenLayer(t *testing.T) v1.Layer { + layer, err := tarball.LayerFromFile("testdata/bundle.tar.gz") + require.NoError(t, err) + + return brokenLayer{layer} +} + func TestClient_LoadBuiltinPolicies(t *testing.T) { tests := []struct { name string @@ -74,10 +94,16 @@ func TestClient_LoadBuiltinPolicies(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - utils.SetCacheDir(tt.cacheDir) - + // Mock image img := new(fakei.FakeImage) - c, err := policy.NewClient(policy.WithImage(img)) + img.LayersReturns([]v1.Layer{newFakeLayer(t)}, nil) + + // Mock OCI artifact + mediaType := "application/vnd.cncf.openpolicyagent.layer.v1.tar+gzip" + art, err := oci.NewArtifact("repo", mediaType, true, oci.WithImage(img)) + require.NoError(t, err) + + c, err := policy.NewClient(tt.cacheDir, true, policy.WithOCIArtifact(art)) require.NoError(t, err) got, err := c.LoadBuiltinPolicies() @@ -112,8 +138,8 @@ func TestClient_NeedsUpdate(t *testing.T) { h: v1.Hash{Algorithm: "sha256", Hex: "01e033e78bd8a59fa4f4577215e7da06c05e1152526094d8d79d2aa06e98cb9d"}, }, metadata: policy.Metadata{ - Digest: `sha256:922e50f14ab484f11ae65540c3d2d76009020213f1027d4331d31141575e5414`, - LastDownloadedAt: time.Date(2021, 1, 1, 0, 0, 0, 0, time.UTC), + Digest: `sha256:922e50f14ab484f11ae65540c3d2d76009020213f1027d4331d31141575e5414`, + DownloadedAt: time.Date(2021, 1, 1, 0, 0, 0, 0, time.UTC), }, want: false, }, @@ -124,8 +150,8 @@ func TestClient_NeedsUpdate(t *testing.T) { h: v1.Hash{Algorithm: "sha256", Hex: "01e033e78bd8a59fa4f4577215e7da06c05e1152526094d8d79d2aa06e98cb9d"}, }, metadata: policy.Metadata{ - Digest: `sha256:01e033e78bd8a59fa4f4577215e7da06c05e1152526094d8d79d2aa06e98cb9d`, - LastDownloadedAt: time.Date(2021, 1, 1, 0, 0, 0, 0, time.UTC), + Digest: `sha256:01e033e78bd8a59fa4f4577215e7da06c05e1152526094d8d79d2aa06e98cb9d`, + DownloadedAt: time.Date(2021, 1, 1, 0, 0, 0, 0, time.UTC), }, want: false, }, @@ -136,8 +162,8 @@ func TestClient_NeedsUpdate(t *testing.T) { h: v1.Hash{Algorithm: "sha256", Hex: "01e033e78bd8a59fa4f4577215e7da06c05e1152526094d8d79d2aa06e98cb9d"}, }, metadata: policy.Metadata{ - Digest: `sha256:922e50f14ab484f11ae65540c3d2d76009020213f1027d4331d31141575e5414`, - LastDownloadedAt: time.Date(2021, 1, 1, 0, 0, 0, 0, time.UTC), + Digest: `sha256:922e50f14ab484f11ae65540c3d2d76009020213f1027d4331d31141575e5414`, + DownloadedAt: time.Date(2021, 1, 1, 0, 0, 0, 0, time.UTC), }, want: true, }, @@ -148,8 +174,8 @@ func TestClient_NeedsUpdate(t *testing.T) { err: fmt.Errorf("error"), }, metadata: policy.Metadata{ - Digest: `sha256:922e50f14ab484f11ae65540c3d2d76009020213f1027d4331d31141575e5414`, - LastDownloadedAt: time.Date(2021, 1, 1, 0, 0, 0, 0, time.UTC), + Digest: `sha256:922e50f14ab484f11ae65540c3d2d76009020213f1027d4331d31141575e5414`, + DownloadedAt: time.Date(2021, 1, 1, 0, 0, 0, 0, time.UTC), }, want: false, wantErr: true, @@ -171,10 +197,10 @@ func TestClient_NeedsUpdate(t *testing.T) { t.Run(tt.name, func(t *testing.T) { // Set up a temporary directory tmpDir := t.TempDir() - utils.SetCacheDir(tmpDir) // Mock image img := new(fakei.FakeImage) + img.LayersReturns([]v1.Layer{newFakeLayer(t)}, nil) img.DigestReturns(tt.digestReturns.h, tt.digestReturns.err) // Create a policy directory @@ -191,10 +217,14 @@ func TestClient_NeedsUpdate(t *testing.T) { require.NoError(t, err) } - // Assert results - c, err := policy.NewClient(policy.WithImage(img), policy.WithClock(tt.clock)) + mediaType := "application/vnd.cncf.openpolicyagent.layer.v1.tar+gzip" + art, err := oci.NewArtifact("repo", mediaType, true, oci.WithImage(img)) require.NoError(t, err) + c, err := policy.NewClient(tmpDir, true, policy.WithOCIArtifact(art), policy.WithClock(tt.clock)) + require.NoError(t, err) + + // Assert results got, err := c.NeedsUpdate() assert.Equal(t, tt.wantErr, err != nil) assert.Equal(t, tt.want, got) @@ -203,8 +233,6 @@ func TestClient_NeedsUpdate(t *testing.T) { } func TestClient_DownloadBuiltinPolicies(t *testing.T) { - layer := newFakeLayer(t) - type digestReturns struct { h v1.Hash err error @@ -225,55 +253,39 @@ func TestClient_DownloadBuiltinPolicies(t *testing.T) { name: "happy path", clock: fake.NewFakeClock(time.Date(2021, 1, 1, 1, 0, 0, 0, time.UTC)), layersReturns: layersReturns{ - layers: []v1.Layer{layer}, + layers: []v1.Layer{newFakeLayer(t)}, }, digestReturns: digestReturns{ h: v1.Hash{Algorithm: "sha256", Hex: "01e033e78bd8a59fa4f4577215e7da06c05e1152526094d8d79d2aa06e98cb9d"}, }, want: &policy.Metadata{ - Digest: "sha256:01e033e78bd8a59fa4f4577215e7da06c05e1152526094d8d79d2aa06e98cb9d", - LastDownloadedAt: time.Date(2021, 1, 1, 1, 0, 0, 0, time.UTC), + Digest: "sha256:01e033e78bd8a59fa4f4577215e7da06c05e1152526094d8d79d2aa06e98cb9d", + DownloadedAt: time.Date(2021, 1, 1, 1, 0, 0, 0, time.UTC), }, }, { - name: "sad: two layers", + name: "sad: broken layer", clock: fake.NewFakeClock(time.Date(2021, 1, 1, 1, 0, 0, 0, time.UTC)), layersReturns: layersReturns{ - layers: []v1.Layer{layer, layer}, - }, - want: &policy.Metadata{ - Digest: "sha256:01e033e78bd8a59fa4f4577215e7da06c05e1152526094d8d79d2aa06e98cb9d", - LastDownloadedAt: time.Date(2021, 1, 1, 1, 0, 0, 0, time.UTC), - }, - wantErr: "OPA bundle must be a single layer", - }, - { - name: "sad: Layers returns an error", - clock: fake.NewFakeClock(time.Date(2021, 1, 1, 1, 0, 0, 0, time.UTC)), - layersReturns: layersReturns{ - err: fmt.Errorf("error"), + layers: []v1.Layer{newBrokenLayer(t)}, }, digestReturns: digestReturns{ h: v1.Hash{Algorithm: "sha256", Hex: "01e033e78bd8a59fa4f4577215e7da06c05e1152526094d8d79d2aa06e98cb9d"}, }, - want: &policy.Metadata{ - Digest: "sha256:01e033e78bd8a59fa4f4577215e7da06c05e1152526094d8d79d2aa06e98cb9d", - LastDownloadedAt: time.Date(2021, 1, 1, 1, 0, 0, 0, time.UTC), - }, - wantErr: "OCI layer error", + wantErr: "compressed error", }, { name: "sad: Digest returns an error", clock: fake.NewFakeClock(time.Date(2021, 1, 1, 1, 0, 0, 0, time.UTC)), layersReturns: layersReturns{ - layers: []v1.Layer{layer}, + layers: []v1.Layer{newFakeLayer(t)}, }, digestReturns: digestReturns{ err: fmt.Errorf("error"), }, want: &policy.Metadata{ - Digest: "sha256:01e033e78bd8a59fa4f4577215e7da06c05e1152526094d8d79d2aa06e98cb9d", - LastDownloadedAt: time.Date(2021, 1, 1, 1, 0, 0, 0, time.UTC), + Digest: "sha256:01e033e78bd8a59fa4f4577215e7da06c05e1152526094d8d79d2aa06e98cb9d", + DownloadedAt: time.Date(2021, 1, 1, 1, 0, 0, 0, time.UTC), }, wantErr: "digest error", }, @@ -282,14 +294,18 @@ func TestClient_DownloadBuiltinPolicies(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { tempDir := t.TempDir() - utils.SetCacheDir(tempDir) // Mock image img := new(fakei.FakeImage) img.DigestReturns(tt.digestReturns.h, tt.digestReturns.err) img.LayersReturns(tt.layersReturns.layers, tt.layersReturns.err) - c, err := policy.NewClient(policy.WithClock(tt.clock), policy.WithImage(img)) + // Mock OCI artifact + mediaType := "application/vnd.cncf.openpolicyagent.layer.v1.tar+gzip" + art, err := oci.NewArtifact("repo", mediaType, true, oci.WithImage(img)) + require.NoError(t, err) + + c, err := policy.NewClient(tempDir, true, policy.WithClock(tt.clock), policy.WithOCIArtifact(art)) require.NoError(t, err) err = c.DownloadBuiltinPolicies(context.Background()) diff --git a/pkg/report/table.go b/pkg/report/table.go index 05e3f8d142..0cf9cf11a2 100644 --- a/pkg/report/table.go +++ b/pkg/report/table.go @@ -19,9 +19,6 @@ type TableWriter struct { Severities []dbTypes.Severity Output io.Writer - // For vulnerabilities - Light bool - // For misconfigurations IncludeNonFailures bool Trace bool @@ -103,10 +100,7 @@ func (tw TableWriter) summary(severityCount map[string]int) (int, []string) { } func (tw TableWriter) writeVulnerabilities(table *tablewriter.Table, vulns []types.DetectedVulnerability) map[string]int { - header := []string{"Library", "Vulnerability ID", "Severity", "Installed Version", "Fixed Version"} - if !tw.Light { - header = append(header, "Title") - } + header := []string{"Library", "Vulnerability ID", "Severity", "Installed Version", "Fixed Version", "Title"} table.SetHeader(header) severityCount := tw.setVulnerabilityRows(table, vulns) @@ -156,14 +150,11 @@ func (tw TableWriter) setVulnerabilityRows(table *tablewriter.Table, vulns []typ var row []string if tw.Output == os.Stdout { row = []string{v.PkgName, v.VulnerabilityID, dbTypes.ColorizeSeverity(v.Severity), - v.InstalledVersion, v.FixedVersion} + v.InstalledVersion, v.FixedVersion, strings.TrimSpace(title)} } else { - row = []string{v.PkgName, v.VulnerabilityID, v.Severity, v.InstalledVersion, v.FixedVersion} + row = []string{v.PkgName, v.VulnerabilityID, v.Severity, v.InstalledVersion, v.FixedVersion, strings.TrimSpace(title)} } - if !tw.Light { - row = append(row, strings.TrimSpace(title)) - } table.Append(row) } return severityCount diff --git a/pkg/report/table_test.go b/pkg/report/table_test.go index d8d9a243aa..26bd6917d1 100644 --- a/pkg/report/table_test.go +++ b/pkg/report/table_test.go @@ -16,7 +16,6 @@ func TestReportWriter_Table(t *testing.T) { name string results report.Results expectedOutput string - light bool includeNonFailures bool }{ { @@ -46,33 +45,6 @@ func TestReportWriter_Table(t *testing.T) { | foo | CVE-2020-0001 | HIGH | 1.2.3 | 3.4.5 | foobar | | | | | | | -->avd.aquasec.com/nvd/cve-2020-0001 | +---------+------------------+----------+-------------------+---------------+--------------------------------------+ -`, - }, - { - name: "happy path light", - light: true, - results: report.Results{ - { - Target: "test", - Vulnerabilities: []types.DetectedVulnerability{ - { - VulnerabilityID: "CVE-2020-0001", - PkgName: "foo", - InstalledVersion: "1.2.3", - FixedVersion: "3.4.5", - Vulnerability: dbTypes.Vulnerability{ - Title: "foobar", - Severity: "HIGH", - }, - }, - }, - }, - }, - expectedOutput: `+---------+------------------+----------+-------------------+---------------+ -| LIBRARY | VULNERABILITY ID | SEVERITY | INSTALLED VERSION | FIXED VERSION | -+---------+------------------+----------+-------------------+---------------+ -| foo | CVE-2020-0001 | HIGH | 1.2.3 | 3.4.5 | -+---------+------------------+----------+-------------------+---------------+ `, }, { @@ -218,7 +190,6 @@ func TestReportWriter_Table(t *testing.T) { err := report.Write(report.Report{Results: tc.results}, report.Option{ Format: "table", Output: &tableWritten, - Light: tc.light, IncludeNonFailures: tc.includeNonFailures, }) assert.NoError(t, err) diff --git a/pkg/report/writer.go b/pkg/report/writer.go index 0e5769e061..171bf055f4 100644 --- a/pkg/report/writer.go +++ b/pkg/report/writer.go @@ -93,7 +93,6 @@ type Option struct { Output io.Writer Severities []dbTypes.Severity OutputTemplate string - Light bool // For misconfigurations IncludeNonFailures bool @@ -108,7 +107,6 @@ func Write(report Report, option Option) error { writer = &TableWriter{ Output: option.Output, Severities: option.Severities, - Light: option.Light, IncludeNonFailures: option.IncludeNonFailures, Trace: option.Trace, } diff --git a/pkg/result/result_test.go b/pkg/result/result_test.go index bd0d7300df..14ef8318e8 100644 --- a/pkg/result/result_test.go +++ b/pkg/result/result_test.go @@ -30,7 +30,7 @@ func TestClient_FillVulnerabilityInfo(t *testing.T) { }{ { name: "happy path, with only OS vulnerability but no vendor severity, no NVD", - fixtures: []string{"testdata/fixtures/full.yaml"}, + fixtures: []string{"testdata/fixtures/vulnerability.yaml"}, args: args{ vulns: []types.DetectedVulnerability{ {VulnerabilityID: "CVE-2019-0001"}, @@ -54,7 +54,7 @@ func TestClient_FillVulnerabilityInfo(t *testing.T) { }, { name: "happy path, with only OS vulnerability but no vendor severity, yes NVD", - fixtures: []string{"testdata/fixtures/full.yaml"}, + fixtures: []string{"testdata/fixtures/vulnerability.yaml"}, args: args{ vulns: []types.DetectedVulnerability{ {VulnerabilityID: "CVE-2019-0002"}, @@ -79,7 +79,7 @@ func TestClient_FillVulnerabilityInfo(t *testing.T) { }, { name: "happy path, with only OS vulnerability but no severity, no vendor severity, no NVD", - fixtures: []string{"testdata/fixtures/full.yaml"}, + fixtures: []string{"testdata/fixtures/vulnerability.yaml"}, args: args{ vulns: []types.DetectedVulnerability{ {VulnerabilityID: "CVE-2019-0003"}, @@ -101,7 +101,7 @@ func TestClient_FillVulnerabilityInfo(t *testing.T) { }, { name: "happy path, with only OS vulnerability, yes vendor severity, with both NVD and CVSS info", - fixtures: []string{"testdata/fixtures/full.yaml"}, + fixtures: []string{"testdata/fixtures/vulnerability.yaml"}, args: args{ vulns: []types.DetectedVulnerability{ {VulnerabilityID: "CVE-2019-0004"}, @@ -137,50 +137,9 @@ func TestClient_FillVulnerabilityInfo(t *testing.T) { }, }, }, - { - name: "happy path light db, with only OS vulnerability, yes vendor severity", - fixtures: []string{"testdata/fixtures/light.yaml"}, - args: args{ - vulns: []types.DetectedVulnerability{ - {VulnerabilityID: "CVE-2020-0001"}, - }, - reportType: vulnerability.Ubuntu, - }, - expectedVulnerabilities: []types.DetectedVulnerability{ - { - VulnerabilityID: "CVE-2020-0001", - Vulnerability: dbTypes.Vulnerability{ - Title: "dos", - Severity: dbTypes.SeverityLow.String(), - }, - SeveritySource: vulnerability.Ubuntu, - PrimaryURL: "https://avd.aquasec.com/nvd/cve-2020-0001", - }, - }, - }, - { - name: "happy path light db, with only OS vulnerability, no vendor severity", - fixtures: []string{"testdata/fixtures/light.yaml"}, - args: args{ - vulns: []types.DetectedVulnerability{ - {VulnerabilityID: "CVE-2020-0002"}, - }, - reportType: vulnerability.Alpine, - }, - expectedVulnerabilities: []types.DetectedVulnerability{ - { - VulnerabilityID: "CVE-2020-0002", - Vulnerability: dbTypes.Vulnerability{ - Title: "dos", - Severity: dbTypes.SeverityUnknown.String(), - }, - PrimaryURL: "https://avd.aquasec.com/nvd/cve-2020-0002", - }, - }, - }, { name: "happy path, with only library vulnerability", - fixtures: []string{"testdata/fixtures/full.yaml"}, + fixtures: []string{"testdata/fixtures/vulnerability.yaml"}, args: args{ vulns: []types.DetectedVulnerability{ {VulnerabilityID: "CVE-2019-0005"}, @@ -203,7 +162,7 @@ func TestClient_FillVulnerabilityInfo(t *testing.T) { }, { name: "happy path, with package-specific severity", - fixtures: []string{"testdata/fixtures/full.yaml"}, + fixtures: []string{"testdata/fixtures/vulnerability.yaml"}, args: args{ vulns: []types.DetectedVulnerability{ { diff --git a/pkg/result/testdata/fixtures/light.yaml b/pkg/result/testdata/fixtures/light.yaml deleted file mode 100644 index c0c2aad240..0000000000 --- a/pkg/result/testdata/fixtures/light.yaml +++ /dev/null @@ -1,11 +0,0 @@ -- bucket: vulnerability - pairs: - - key: CVE-2020-0001 - value: - Title: dos - Severity: MEDIUM - VendorSeverity: - ubuntu: 1 - - key: CVE-2020-0002 - value: - Title: dos diff --git a/pkg/result/testdata/fixtures/full.yaml b/pkg/result/testdata/fixtures/vulnerability.yaml similarity index 100% rename from pkg/result/testdata/fixtures/full.yaml rename to pkg/result/testdata/fixtures/vulnerability.yaml diff --git a/pkg/rpc/server/inject.go b/pkg/rpc/server/inject.go index 5477e65c14..b77b80125d 100644 --- a/pkg/rpc/server/inject.go +++ b/pkg/rpc/server/inject.go @@ -12,8 +12,3 @@ func initializeScanServer(localArtifactCache cache.LocalArtifactCache) *ScanServ wire.Build(ScanSuperSet) return &ScanServer{} } - -func initializeDBWorker(cacheDir string, quiet bool) dbWorker { - wire.Build(DBWorkerSuperSet) - return dbWorker{} -} diff --git a/pkg/rpc/server/listen.go b/pkg/rpc/server/listen.go index 66de17dc1b..5af2751a9c 100644 --- a/pkg/rpc/server/listen.go +++ b/pkg/rpc/server/listen.go @@ -8,24 +8,21 @@ import ( "time" "github.com/NYTimes/gziphandler" - "github.com/google/wire" "github.com/twitchtv/twirp" "golang.org/x/xerrors" "github.com/aquasecurity/fanal/cache" "github.com/aquasecurity/trivy-db/pkg/db" + "github.com/aquasecurity/trivy-db/pkg/metadata" dbFile "github.com/aquasecurity/trivy/pkg/db" + dbc "github.com/aquasecurity/trivy/pkg/db" "github.com/aquasecurity/trivy/pkg/log" "github.com/aquasecurity/trivy/pkg/utils" rpcCache "github.com/aquasecurity/trivy/rpc/cache" rpcScanner "github.com/aquasecurity/trivy/rpc/scanner" ) -// DBWorkerSuperSet binds the dependencies for Trivy DB worker -var DBWorkerSuperSet = wire.NewSet( - dbFile.SuperSet, - newDBWorker, -) +const updateInterval = 1 * time.Hour // Server represents Trivy server type Server struct { @@ -53,10 +50,10 @@ func (s Server) ListenAndServe(serverCache cache.Cache) error { dbUpdateWg := &sync.WaitGroup{} go func() { - worker := initializeDBWorker(s.cacheDir, true) + worker := newDBWorker(dbc.NewClient(s.cacheDir, true)) ctx := context.Background() for { - time.Sleep(1 * time.Hour) + time.Sleep(updateInterval) if err := worker.update(ctx, s.appVersion, s.cacheDir, dbUpdateWg, requestWg); err != nil { log.Logger.Errorf("%+v\n", err) } @@ -124,7 +121,7 @@ func newDBWorker(dbClient dbFile.Operation) dbWorker { func (w dbWorker) update(ctx context.Context, appVersion, cacheDir string, dbUpdateWg, requestWg *sync.WaitGroup) error { log.Logger.Debug("Check for DB update...") - needsUpdate, err := w.dbClient.NeedsUpdate(appVersion, false, false) + needsUpdate, err := w.dbClient.NeedsUpdate(appVersion, false) if err != nil { return xerrors.Errorf("failed to check if db needs an update") } else if !needsUpdate { @@ -145,7 +142,7 @@ func (w dbWorker) hotUpdate(ctx context.Context, cacheDir string, dbUpdateWg, re } defer os.RemoveAll(tmpDir) - if err = w.dbClient.Download(ctx, tmpDir, false); err != nil { + if err = w.dbClient.Download(ctx, tmpDir); err != nil { return xerrors.Errorf("failed to download vulnerability DB: %w", err) } @@ -160,12 +157,14 @@ func (w dbWorker) hotUpdate(ctx context.Context, cacheDir string, dbUpdateWg, re return xerrors.Errorf("failed to close DB: %w", err) } + // Copy trivy.db if _, err = utils.CopyFile(db.Path(tmpDir), db.Path(cacheDir)); err != nil { return xerrors.Errorf("failed to copy the database file: %w", err) } - if err = w.dbClient.UpdateMetadata(cacheDir); err != nil { - return xerrors.Errorf("unable to update database metadata: %w", err) + // Copy metadata.json + if _, err = utils.CopyFile(metadata.Path(tmpDir), metadata.Path(cacheDir)); err != nil { + return xerrors.Errorf("failed to copy the metadata file: %w", err) } log.Logger.Info("Reopening DB...") diff --git a/pkg/rpc/server/listen_test.go b/pkg/rpc/server/listen_test.go index d535f1f38d..0aae9b23a2 100644 --- a/pkg/rpc/server/listen_test.go +++ b/pkg/rpc/server/listen_test.go @@ -6,7 +6,6 @@ import ( "net/http/httptest" "os" "path" - "path/filepath" "sync" "testing" "time" @@ -18,7 +17,9 @@ import ( "github.com/aquasecurity/fanal/cache" "github.com/aquasecurity/trivy-db/pkg/db" + "github.com/aquasecurity/trivy-db/pkg/metadata" dbFile "github.com/aquasecurity/trivy/pkg/db" + "github.com/aquasecurity/trivy/pkg/utils" rpcCache "github.com/aquasecurity/trivy/rpc/cache" ) @@ -52,7 +53,7 @@ func Test_dbWorker_update(t *testing.T) { needsUpdate needsUpdate download download args args - want db.Metadata + want metadata.Metadata wantErr string }{ { @@ -65,9 +66,8 @@ func Test_dbWorker_update(t *testing.T) { call: true, }, args: args{appVersion: "1"}, - want: db.Metadata{ + want: metadata.Metadata{ Version: 1, - Type: db.TypeFull, NextUpdate: timeNextUpdate, UpdatedAt: timeUpdateAt, }, @@ -105,51 +105,50 @@ func Test_dbWorker_update(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - cacheDir, err := os.MkdirTemp("", "server-test") - require.NoError(t, err, tt.name) + cacheDir := t.TempDir() require.NoError(t, db.Init(cacheDir), tt.name) mockDBClient := new(dbFile.MockOperation) mockDBClient.On("NeedsUpdate", - tt.needsUpdate.input.appVersion, false, tt.needsUpdate.input.skip).Return( + tt.needsUpdate.input.appVersion, tt.needsUpdate.input.skip).Return( tt.needsUpdate.output.needsUpdate, tt.needsUpdate.output.err) - mockDBClient.On("UpdateMetadata", mock.Anything).Return(nil) if tt.download.call { - mockDBClient.On("Download", mock.Anything, mock.Anything, false).Run( + mockDBClient.On("Download", mock.Anything, mock.Anything).Run( func(args mock.Arguments) { // fake download: copy testdata/new.db to tmpDir/db/trivy.db - content, err := os.ReadFile("testdata/new.db") - require.NoError(t, err, tt.name) - tmpDir := args.String(1) - dbPath := db.Path(tmpDir) - require.NoError(t, os.MkdirAll(filepath.Dir(dbPath), 0777), tt.name) - err = os.WriteFile(dbPath, content, 0444) - require.NoError(t, err, tt.name) + err := os.MkdirAll(db.Dir(tmpDir), 0744) + require.NoError(t, err) + + _, err = utils.CopyFile("testdata/new.db", db.Path(tmpDir)) + require.NoError(t, err) + + // fake download: copy testdata/metadata.json to tmpDir/db/metadata.json + _, err = utils.CopyFile("testdata/metadata.json", metadata.Path(tmpDir)) + require.NoError(t, err) }).Return(tt.download.err) } w := newDBWorker(mockDBClient) var dbUpdateWg, requestWg sync.WaitGroup - err = w.update(context.Background(), tt.args.appVersion, cacheDir, + err := w.update(context.Background(), tt.args.appVersion, cacheDir, &dbUpdateWg, &requestWg) if tt.wantErr != "" { require.NotNil(t, err, tt.name) assert.Contains(t, err.Error(), tt.wantErr, tt.name) return - } else { - assert.NoError(t, err, tt.name) } + require.NoError(t, err, tt.name) if !tt.download.call { return } - dbc := db.Config{} - got, err := dbc.GetMetadata() + mc := metadata.NewClient(cacheDir) + got, err := mc.Get() assert.NoError(t, err, tt.name) assert.Equal(t, tt.want, got, tt.name) diff --git a/pkg/rpc/server/testdata/metadata.json b/pkg/rpc/server/testdata/metadata.json new file mode 100644 index 0000000000..dfc2957b62 --- /dev/null +++ b/pkg/rpc/server/testdata/metadata.json @@ -0,0 +1 @@ +{"Version":1,"NextUpdate":"3000-01-01T0:00:00.0Z","UpdatedAt":"3000-01-01T0:00:00.0Z"} \ No newline at end of file diff --git a/pkg/rpc/server/wire_gen.go b/pkg/rpc/server/wire_gen.go index 31f32e495a..fd583b579e 100644 --- a/pkg/rpc/server/wire_gen.go +++ b/pkg/rpc/server/wire_gen.go @@ -10,14 +10,9 @@ import ( "github.com/aquasecurity/fanal/applier" "github.com/aquasecurity/fanal/cache" "github.com/aquasecurity/trivy-db/pkg/db" - db2 "github.com/aquasecurity/trivy/pkg/db" "github.com/aquasecurity/trivy/pkg/detector/ospkg" - "github.com/aquasecurity/trivy/pkg/github" - "github.com/aquasecurity/trivy/pkg/indicator" "github.com/aquasecurity/trivy/pkg/result" "github.com/aquasecurity/trivy/pkg/scanner/local" - "github.com/spf13/afero" - "k8s.io/utils/clock" ) // Injectors from inject.go: @@ -31,15 +26,3 @@ func initializeScanServer(localArtifactCache cache.LocalArtifactCache) *ScanServ scanServer := NewScanServer(scanner, client) return scanServer } - -func initializeDBWorker(cacheDir string, quiet bool) dbWorker { - config := db.Config{} - client := github.NewClient() - progressBar := indicator.NewProgressBar(quiet) - realClock := clock.RealClock{} - fs := afero.NewOsFs() - metadata := db2.NewMetadata(fs, cacheDir) - dbClient := db2.NewClient(config, client, progressBar, realClock, metadata) - serverDbWorker := newDBWorker(dbClient) - return serverDbWorker -} diff --git a/pkg/utils/utils.go b/pkg/utils/utils.go index 0fff8f9ff1..4369b1b3ff 100644 --- a/pkg/utils/utils.go +++ b/pkg/utils/utils.go @@ -5,6 +5,8 @@ import ( "io" "os" "path/filepath" + + "golang.org/x/xerrors" ) var cacheDir string @@ -42,7 +44,7 @@ func StringInSlice(a string, list []string) bool { func CopyFile(src, dst string) (int64, error) { sourceFileStat, err := os.Stat(src) if err != nil { - return 0, err + return 0, xerrors.Errorf("file (%s) stat error: %w", src, err) } if !sourceFileStat.Mode().IsRegular() {